You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
8.0 KiB

  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. static int exiting; /* we're already exiting (for maybe_exit) */
  18. static pid_t my_pid; /* PID of main thread */
  19. static struct pidlist {
  20. pid_t parent;
  21. pid_t child;
  22. } pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */
  23. static int maxpidindex; /* # of PIDs in pidlist */
  24. /*
  25. * Initialization.
  26. */
  27. static void PyThread__init_thread(void)
  28. {
  29. #ifdef USE_DL
  30. long addr, size;
  31. #endif /* USE_DL */
  32. #ifdef USE_DL
  33. if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
  34. perror("usconfig - CONF_INITSIZE (check)");
  35. if (usconfig(CONF_INITSIZE, size) < 0)
  36. perror("usconfig - CONF_INITSIZE (reset)");
  37. addr = (long) dl_getrange(size + HDR_SIZE);
  38. dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size));
  39. errno = 0;
  40. if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
  41. perror("usconfig - CONF_ATTACHADDR (set)");
  42. #endif /* USE_DL */
  43. if (usconfig(CONF_INITUSERS, 16) < 0)
  44. perror("usconfig - CONF_INITUSERS");
  45. my_pid = getpid(); /* so that we know which is the main thread */
  46. if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
  47. perror("usconfig - CONF_ARENATYPE");
  48. usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
  49. #ifdef Py_DEBUG
  50. if (thread_debug & 4)
  51. usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
  52. else if (thread_debug & 2)
  53. usconfig(CONF_LOCKTYPE, US_DEBUG);
  54. #endif /* Py_DEBUG */
  55. if ((shared_arena = usinit(tmpnam(0))) == 0)
  56. perror("usinit");
  57. #ifdef USE_DL
  58. if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
  59. perror("usconfig - CONF_ATTACHADDR (reset)");
  60. #endif /* USE_DL */
  61. if ((count_lock = usnewlock(shared_arena)) == NULL)
  62. perror("usnewlock (count_lock)");
  63. (void) usinitlock(count_lock);
  64. if ((wait_lock = usnewlock(shared_arena)) == NULL)
  65. perror("usnewlock (wait_lock)");
  66. dprintf(("arena start: %p, arena size: %ld\n", shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
  67. }
  68. /*
  69. * Thread support.
  70. */
  71. static void clean_threads(void)
  72. {
  73. int i, j;
  74. pid_t mypid, pid;
  75. /* clean up any exited threads */
  76. mypid = getpid();
  77. i = 0;
  78. while (i < maxpidindex) {
  79. if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
  80. pid = waitpid(pid, 0, WNOHANG);
  81. if (pid > 0) {
  82. /* a thread has exited */
  83. pidlist[i] = pidlist[--maxpidindex];
  84. /* remove references to children of dead proc */
  85. for (j = 0; j < maxpidindex; j++)
  86. if (pidlist[j].parent == pid)
  87. pidlist[j].child = -1;
  88. continue; /* don't increment i */
  89. }
  90. }
  91. i++;
  92. }
  93. /* clean up the list */
  94. i = 0;
  95. while (i < maxpidindex) {
  96. if (pidlist[i].child == -1) {
  97. pidlist[i] = pidlist[--maxpidindex];
  98. continue; /* don't increment i */
  99. }
  100. i++;
  101. }
  102. }
  103. long PyThread_start_new_thread(void (*func)(void *), void *arg)
  104. {
  105. #ifdef USE_DL
  106. long addr, size;
  107. static int local_initialized = 0;
  108. #endif /* USE_DL */
  109. int success = 0; /* init not needed when SOLARIS_THREADS and */
  110. /* C_THREADS implemented properly */
  111. dprintf(("PyThread_start_new_thread called\n"));
  112. if (!initialized)
  113. PyThread_init_thread();
  114. switch (ussetlock(count_lock)) {
  115. case 0: return 0;
  116. case -1: perror("ussetlock (count_lock)");
  117. }
  118. if (maxpidindex >= MAXPROC)
  119. success = -1;
  120. else {
  121. #ifdef USE_DL
  122. if (!local_initialized) {
  123. if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
  124. perror("usconfig - CONF_INITSIZE (check)");
  125. if (usconfig(CONF_INITSIZE, size) < 0)
  126. perror("usconfig - CONF_INITSIZE (reset)");
  127. addr = (long) dl_getrange(size + HDR_SIZE);
  128. dprintf(("trying to use addr %p-%p for sproc\n",
  129. addr, addr+size));
  130. errno = 0;
  131. if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
  132. errno != 0)
  133. perror("usconfig - CONF_ATTACHADDR (set)");
  134. }
  135. #endif /* USE_DL */
  136. clean_threads();
  137. if ((success = sproc(func, PR_SALL, arg)) < 0)
  138. perror("sproc");
  139. #ifdef USE_DL
  140. if (!local_initialized) {
  141. if (usconfig(CONF_ATTACHADDR, addr) < 0)
  142. /* reset address */
  143. perror("usconfig - CONF_ATTACHADDR (reset)");
  144. local_initialized = 1;
  145. }
  146. #endif /* USE_DL */
  147. if (success >= 0) {
  148. nthreads++;
  149. pidlist[maxpidindex].parent = getpid();
  150. pidlist[maxpidindex++].child = success;
  151. dprintf(("pidlist[%d] = %d\n",
  152. maxpidindex-1, success));
  153. }
  154. }
  155. if (usunsetlock(count_lock) < 0)
  156. perror("usunsetlock (count_lock)");
  157. return success;
  158. }
  159. long PyThread_get_thread_ident(void)
  160. {
  161. return getpid();
  162. }
  163. void PyThread_exit_thread(void)
  164. {
  165. dprintf(("PyThread_exit_thread called\n"));
  166. if (!initialized)
  167. exit(0);
  168. if (ussetlock(count_lock) < 0)
  169. perror("ussetlock (count_lock)");
  170. nthreads--;
  171. if (getpid() == my_pid) {
  172. /* main thread; wait for other threads to exit */
  173. exiting = 1;
  174. waiting_for_threads = 1;
  175. if (ussetlock(wait_lock) < 0)
  176. perror("ussetlock (wait_lock)");
  177. for (;;) {
  178. if (nthreads < 0) {
  179. dprintf(("really exit (%d)\n", exit_status));
  180. exit(exit_status);
  181. }
  182. if (usunsetlock(count_lock) < 0)
  183. perror("usunsetlock (count_lock)");
  184. dprintf(("waiting for other threads (%d)\n", nthreads));
  185. if (ussetlock(wait_lock) < 0)
  186. perror("ussetlock (wait_lock)");
  187. if (ussetlock(count_lock) < 0)
  188. perror("ussetlock (count_lock)");
  189. }
  190. }
  191. /* not the main thread */
  192. if (waiting_for_threads) {
  193. dprintf(("main thread is waiting\n"));
  194. if (usunsetlock(wait_lock) < 0)
  195. perror("usunsetlock (wait_lock)");
  196. }
  197. if (usunsetlock(count_lock) < 0)
  198. perror("usunsetlock (count_lock)");
  199. _exit(0);
  200. }
  201. /*
  202. * Lock support.
  203. */
  204. PyThread_type_lock PyThread_allocate_lock(void)
  205. {
  206. ulock_t lock;
  207. dprintf(("PyThread_allocate_lock called\n"));
  208. if (!initialized)
  209. PyThread_init_thread();
  210. if ((lock = usnewlock(shared_arena)) == NULL)
  211. perror("usnewlock");
  212. (void) usinitlock(lock);
  213. dprintf(("PyThread_allocate_lock() -> %p\n", lock));
  214. return (PyThread_type_lock) lock;
  215. }
  216. void PyThread_free_lock(PyThread_type_lock lock)
  217. {
  218. dprintf(("PyThread_free_lock(%p) called\n", lock));
  219. usfreelock((ulock_t) lock, shared_arena);
  220. }
  221. int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
  222. {
  223. int success;
  224. dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
  225. errno = 0; /* clear it just in case */
  226. if (waitflag)
  227. success = ussetlock((ulock_t) lock);
  228. else
  229. success = uscsetlock((ulock_t) lock, 1); /* Try it once */
  230. if (success < 0)
  231. perror(waitflag ? "ussetlock" : "uscsetlock");
  232. dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
  233. return success;
  234. }
  235. void PyThread_release_lock(PyThread_type_lock lock)
  236. {
  237. dprintf(("PyThread_release_lock(%p) called\n", lock));
  238. if (usunsetlock((ulock_t) lock) < 0)
  239. perror("usunsetlock");
  240. }