/Python/thread_sgi.h

http://unladen-swallow.googlecode.com/ · C++ Header · 375 lines · 319 code · 28 blank · 28 comment · 79 complexity · 697a44794ff5d2180d89f4f36f3efa74 MD5 · raw file

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <signal.h>
  4. #include <sys/types.h>
  5. #include <sys/wait.h>
  6. #include <sys/prctl.h>
  7. #include <ulocks.h>
  8. #include <errno.h>
  9. #define HDR_SIZE 2680 /* sizeof(ushdr_t) */
  10. #define MAXPROC 100 /* max # of threads that can be started */
  11. static usptr_t *shared_arena;
  12. static ulock_t count_lock; /* protection for some variables */
  13. static ulock_t wait_lock; /* lock used to wait for other threads */
  14. static int waiting_for_threads; /* protected by count_lock */
  15. static int nthreads; /* protected by count_lock */
  16. static int exit_status;
  17. #ifndef NO_EXIT_PROG
  18. static int do_exit; /* indicates that the program is to exit */
  19. #endif
  20. static int exiting; /* we're already exiting (for maybe_exit) */
  21. static pid_t my_pid; /* PID of main thread */
  22. static struct pidlist {
  23. pid_t parent;
  24. pid_t child;
  25. } pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */
  26. static int maxpidindex; /* # of PIDs in pidlist */
  27. #ifndef NO_EXIT_PROG
  28. /*
  29. * This routine is called as a signal handler when another thread
  30. * exits. When that happens, we must see whether we have to exit as
  31. * well (because of an PyThread_exit_prog()) or whether we should continue on.
  32. */
  33. static void exit_sig(void)
  34. {
  35. d2printf(("exit_sig called\n"));
  36. if (exiting && getpid() == my_pid) {
  37. d2printf(("already exiting\n"));
  38. return;
  39. }
  40. if (do_exit) {
  41. d2printf(("exiting in exit_sig\n"));
  42. #ifdef Py_DEBUG
  43. if ((thread_debug & 8) == 0)
  44. thread_debug &= ~1; /* don't produce debug messages */
  45. #endif
  46. PyThread_exit_thread();
  47. }
  48. }
  49. /*
  50. * This routine is called when a process calls exit(). If that wasn't
  51. * done from the library, we do as if an PyThread_exit_prog() was intended.
  52. */
  53. static void maybe_exit(void)
  54. {
  55. dprintf(("maybe_exit called\n"));
  56. if (exiting) {
  57. dprintf(("already exiting\n"));
  58. return;
  59. }
  60. PyThread_exit_prog(0);
  61. }
  62. #endif /* NO_EXIT_PROG */
  63. /*
  64. * Initialization.
  65. */
  66. static void PyThread__init_thread(void)
  67. {
  68. #ifndef NO_EXIT_PROG
  69. struct sigaction s;
  70. #endif /* NO_EXIT_PROG */
  71. #ifdef USE_DL
  72. long addr, size;
  73. #endif /* USE_DL */
  74. #ifdef USE_DL
  75. if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
  76. perror("usconfig - CONF_INITSIZE (check)");
  77. if (usconfig(CONF_INITSIZE, size) < 0)
  78. perror("usconfig - CONF_INITSIZE (reset)");
  79. addr = (long) dl_getrange(size + HDR_SIZE);
  80. dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size));
  81. errno = 0;
  82. if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
  83. perror("usconfig - CONF_ATTACHADDR (set)");
  84. #endif /* USE_DL */
  85. if (usconfig(CONF_INITUSERS, 16) < 0)
  86. perror("usconfig - CONF_INITUSERS");
  87. my_pid = getpid(); /* so that we know which is the main thread */
  88. #ifndef NO_EXIT_PROG
  89. atexit(maybe_exit);
  90. s.sa_handler = exit_sig;
  91. sigemptyset(&s.sa_mask);
  92. /*sigaddset(&s.sa_mask, SIGUSR1);*/
  93. s.sa_flags = 0;
  94. sigaction(SIGUSR1, &s, 0);
  95. if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
  96. perror("prctl - PR_SETEXITSIG");
  97. #endif /* NO_EXIT_PROG */
  98. if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
  99. perror("usconfig - CONF_ARENATYPE");
  100. usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
  101. #ifdef Py_DEBUG
  102. if (thread_debug & 4)
  103. usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
  104. else if (thread_debug & 2)
  105. usconfig(CONF_LOCKTYPE, US_DEBUG);
  106. #endif /* Py_DEBUG */
  107. if ((shared_arena = usinit(tmpnam(0))) == 0)
  108. perror("usinit");
  109. #ifdef USE_DL
  110. if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
  111. perror("usconfig - CONF_ATTACHADDR (reset)");
  112. #endif /* USE_DL */
  113. if ((count_lock = usnewlock(shared_arena)) == NULL)
  114. perror("usnewlock (count_lock)");
  115. (void) usinitlock(count_lock);
  116. if ((wait_lock = usnewlock(shared_arena)) == NULL)
  117. perror("usnewlock (wait_lock)");
  118. dprintf(("arena start: %p, arena size: %ld\n", shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
  119. }
  120. /*
  121. * Thread support.
  122. */
  123. static void clean_threads(void)
  124. {
  125. int i, j;
  126. pid_t mypid, pid;
  127. /* clean up any exited threads */
  128. mypid = getpid();
  129. i = 0;
  130. while (i < maxpidindex) {
  131. if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
  132. pid = waitpid(pid, 0, WNOHANG);
  133. if (pid > 0) {
  134. /* a thread has exited */
  135. pidlist[i] = pidlist[--maxpidindex];
  136. /* remove references to children of dead proc */
  137. for (j = 0; j < maxpidindex; j++)
  138. if (pidlist[j].parent == pid)
  139. pidlist[j].child = -1;
  140. continue; /* don't increment i */
  141. }
  142. }
  143. i++;
  144. }
  145. /* clean up the list */
  146. i = 0;
  147. while (i < maxpidindex) {
  148. if (pidlist[i].child == -1) {
  149. pidlist[i] = pidlist[--maxpidindex];
  150. continue; /* don't increment i */
  151. }
  152. i++;
  153. }
  154. }
  155. long PyThread_start_new_thread(void (*func)(void *), void *arg)
  156. {
  157. #ifdef USE_DL
  158. long addr, size;
  159. static int local_initialized = 0;
  160. #endif /* USE_DL */
  161. int success = 0; /* init not needed when SOLARIS_THREADS and */
  162. /* C_THREADS implemented properly */
  163. dprintf(("PyThread_start_new_thread called\n"));
  164. if (!initialized)
  165. PyThread_init_thread();
  166. switch (ussetlock(count_lock)) {
  167. case 0: return 0;
  168. case -1: perror("ussetlock (count_lock)");
  169. }
  170. if (maxpidindex >= MAXPROC)
  171. success = -1;
  172. else {
  173. #ifdef USE_DL
  174. if (!local_initialized) {
  175. if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
  176. perror("usconfig - CONF_INITSIZE (check)");
  177. if (usconfig(CONF_INITSIZE, size) < 0)
  178. perror("usconfig - CONF_INITSIZE (reset)");
  179. addr = (long) dl_getrange(size + HDR_SIZE);
  180. dprintf(("trying to use addr %p-%p for sproc\n",
  181. addr, addr+size));
  182. errno = 0;
  183. if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
  184. errno != 0)
  185. perror("usconfig - CONF_ATTACHADDR (set)");
  186. }
  187. #endif /* USE_DL */
  188. clean_threads();
  189. if ((success = sproc(func, PR_SALL, arg)) < 0)
  190. perror("sproc");
  191. #ifdef USE_DL
  192. if (!local_initialized) {
  193. if (usconfig(CONF_ATTACHADDR, addr) < 0)
  194. /* reset address */
  195. perror("usconfig - CONF_ATTACHADDR (reset)");
  196. local_initialized = 1;
  197. }
  198. #endif /* USE_DL */
  199. if (success >= 0) {
  200. nthreads++;
  201. pidlist[maxpidindex].parent = getpid();
  202. pidlist[maxpidindex++].child = success;
  203. dprintf(("pidlist[%d] = %d\n",
  204. maxpidindex-1, success));
  205. }
  206. }
  207. if (usunsetlock(count_lock) < 0)
  208. perror("usunsetlock (count_lock)");
  209. return success;
  210. }
  211. long PyThread_get_thread_ident(void)
  212. {
  213. return getpid();
  214. }
  215. static void do_PyThread_exit_thread(int no_cleanup)
  216. {
  217. dprintf(("PyThread_exit_thread called\n"));
  218. if (!initialized)
  219. if (no_cleanup)
  220. _exit(0);
  221. else
  222. exit(0);
  223. if (ussetlock(count_lock) < 0)
  224. perror("ussetlock (count_lock)");
  225. nthreads--;
  226. if (getpid() == my_pid) {
  227. /* main thread; wait for other threads to exit */
  228. exiting = 1;
  229. #ifndef NO_EXIT_PROG
  230. if (do_exit) {
  231. int i;
  232. /* notify other threads */
  233. clean_threads();
  234. if (nthreads >= 0) {
  235. dprintf(("kill other threads\n"));
  236. for (i = 0; i < maxpidindex; i++)
  237. if (pidlist[i].child > 0)
  238. (void) kill(pidlist[i].child,
  239. SIGKILL);
  240. _exit(exit_status);
  241. }
  242. }
  243. #endif /* NO_EXIT_PROG */
  244. waiting_for_threads = 1;
  245. if (ussetlock(wait_lock) < 0)
  246. perror("ussetlock (wait_lock)");
  247. for (;;) {
  248. if (nthreads < 0) {
  249. dprintf(("really exit (%d)\n", exit_status));
  250. if (no_cleanup)
  251. _exit(exit_status);
  252. else
  253. exit(exit_status);
  254. }
  255. if (usunsetlock(count_lock) < 0)
  256. perror("usunsetlock (count_lock)");
  257. dprintf(("waiting for other threads (%d)\n", nthreads));
  258. if (ussetlock(wait_lock) < 0)
  259. perror("ussetlock (wait_lock)");
  260. if (ussetlock(count_lock) < 0)
  261. perror("ussetlock (count_lock)");
  262. }
  263. }
  264. /* not the main thread */
  265. if (waiting_for_threads) {
  266. dprintf(("main thread is waiting\n"));
  267. if (usunsetlock(wait_lock) < 0)
  268. perror("usunsetlock (wait_lock)");
  269. }
  270. #ifndef NO_EXIT_PROG
  271. else if (do_exit)
  272. (void) kill(my_pid, SIGUSR1);
  273. #endif /* NO_EXIT_PROG */
  274. if (usunsetlock(count_lock) < 0)
  275. perror("usunsetlock (count_lock)");
  276. _exit(0);
  277. }
  278. void PyThread_exit_thread(void)
  279. {
  280. do_PyThread_exit_thread(0);
  281. }
  282. void PyThread__exit_thread(void)
  283. {
  284. do_PyThread_exit_thread(1);
  285. }
  286. #ifndef NO_EXIT_PROG
  287. static void do_PyThread_exit_prog(int status, int no_cleanup)
  288. {
  289. dprintf(("PyThread_exit_prog(%d) called\n", status));
  290. if (!initialized)
  291. if (no_cleanup)
  292. _exit(status);
  293. else
  294. exit(status);
  295. do_exit = 1;
  296. exit_status = status;
  297. do_PyThread_exit_thread(no_cleanup);
  298. }
  299. void PyThread_exit_prog(int status)
  300. {
  301. do_PyThread_exit_prog(status, 0);
  302. }
  303. void PyThread__exit_prog(int status)
  304. {
  305. do_PyThread_exit_prog(status, 1);
  306. }
  307. #endif /* NO_EXIT_PROG */
  308. /*
  309. * Lock support.
  310. */
  311. PyThread_type_lock PyThread_allocate_lock(void)
  312. {
  313. ulock_t lock;
  314. dprintf(("PyThread_allocate_lock called\n"));
  315. if (!initialized)
  316. PyThread_init_thread();
  317. if ((lock = usnewlock(shared_arena)) == NULL)
  318. perror("usnewlock");
  319. (void) usinitlock(lock);
  320. dprintf(("PyThread_allocate_lock() -> %p\n", lock));
  321. return (PyThread_type_lock) lock;
  322. }
  323. void PyThread_free_lock(PyThread_type_lock lock)
  324. {
  325. dprintf(("PyThread_free_lock(%p) called\n", lock));
  326. usfreelock((ulock_t) lock, shared_arena);
  327. }
  328. int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
  329. {
  330. int success;
  331. dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
  332. errno = 0; /* clear it just in case */
  333. if (waitflag)
  334. success = ussetlock((ulock_t) lock);
  335. else
  336. success = uscsetlock((ulock_t) lock, 1); /* Try it once */
  337. if (success < 0)
  338. perror(waitflag ? "ussetlock" : "uscsetlock");
  339. dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
  340. return success;
  341. }
  342. void PyThread_release_lock(PyThread_type_lock lock)
  343. {
  344. dprintf(("PyThread_release_lock(%p) called\n", lock));
  345. if (usunsetlock((ulock_t) lock) < 0)
  346. perror("usunsetlock");
  347. }