PageRenderTime 78ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/translator/c/src/thread_pthread.h

https://bitbucket.org/chence/pypy
C++ Header | 582 lines | 420 code | 91 blank | 71 comment | 61 complexity | 7bd61a6d86bca218a9a5392df633cf96 MD5 | raw file
  1. /* Posix threads interface (from CPython) */
  2. /* XXX needs to detect HAVE_BROKEN_POSIX_SEMAPHORES properly; currently
  3. it is set only if _POSIX_SEMAPHORES == -1. Seems to be only for
  4. SunOS/5.8 and AIX/5.
  5. */
  6. #include <unistd.h> /* for the _POSIX_xxx and _POSIX_THREAD_xxx defines */
  7. #include <stdlib.h>
  8. #include <pthread.h>
  9. #include <signal.h>
  10. #include <stdio.h>
  11. #include <errno.h>
  12. #include <assert.h>
  13. /* The following is hopefully equivalent to what CPython does
  14. (which is trying to compile a snippet of code using it) */
  15. #ifdef PTHREAD_SCOPE_SYSTEM
  16. # ifndef PTHREAD_SYSTEM_SCHED_SUPPORTED
  17. # define PTHREAD_SYSTEM_SCHED_SUPPORTED
  18. # endif
  19. #endif
  20. /* The POSIX spec says that implementations supporting the sem_*
  21. family of functions must indicate this by defining
  22. _POSIX_SEMAPHORES. */
  23. #ifdef _POSIX_SEMAPHORES
  24. /* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so
  25. we need to add 0 to make it work there as well. */
  26. #if (_POSIX_SEMAPHORES+0) == -1
  27. #define HAVE_BROKEN_POSIX_SEMAPHORES
  28. #else
  29. #include <semaphore.h>
  30. #endif
  31. #endif
  32. #if !defined(pthread_attr_default)
  33. # define pthread_attr_default ((pthread_attr_t *)NULL)
  34. #endif
  35. #if !defined(pthread_mutexattr_default)
  36. # define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL)
  37. #endif
  38. #if !defined(pthread_condattr_default)
  39. # define pthread_condattr_default ((pthread_condattr_t *)NULL)
  40. #endif
  41. /* Whether or not to use semaphores directly rather than emulating them with
  42. * mutexes and condition variables:
  43. */
  44. #if defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES)
  45. # define USE_SEMAPHORES
  46. #else
  47. # undef USE_SEMAPHORES
  48. #endif
  49. #define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; }
  50. /********************* structs ***********/
  51. #ifdef USE_SEMAPHORES
  52. #include <semaphore.h>
  53. struct RPyOpaque_ThreadLock {
  54. sem_t sem;
  55. int initialized;
  56. };
  57. #define RPyOpaque_INITEXPR_ThreadLock { { /* sem */ }, 0 }
  58. #else /* no semaphores */
  59. /* A pthread mutex isn't sufficient to model the Python lock type
  60. (see explanations in CPython's Python/thread_pthread.h */
  61. struct RPyOpaque_ThreadLock {
  62. char locked; /* 0=unlocked, 1=locked */
  63. char initialized;
  64. /* a <cond, mutex> pair to handle an acquire of a locked lock */
  65. pthread_cond_t lock_released;
  66. pthread_mutex_t mut;
  67. struct RPyOpaque_ThreadLock *prev, *next;
  68. };
  69. #define RPyOpaque_INITEXPR_ThreadLock { \
  70. 0, 0, \
  71. PTHREAD_COND_INITIALIZER, \
  72. PTHREAD_MUTEX_INITIALIZER \
  73. }
  74. #endif /* no semaphores */
  75. /* prototypes */
  76. long RPyThreadGetIdent(void);
  77. long RPyThreadStart(void (*func)(void));
  78. int RPyThreadLockInit(struct RPyOpaque_ThreadLock *lock);
  79. void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock);
  80. int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag);
  81. void RPyThreadReleaseLock(struct RPyOpaque_ThreadLock *lock);
  82. long RPyThreadGetStackSize(void);
  83. long RPyThreadSetStackSize(long);
  84. void RPyThreadAfterFork(void);
  85. /* implementations */
  86. #ifndef PYPY_NOT_MAIN_FILE
  87. /* The POSIX spec requires that use of pthread_attr_setstacksize
  88. be conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */
  89. #ifdef _POSIX_THREAD_ATTR_STACKSIZE
  90. # ifndef THREAD_STACK_SIZE
  91. # define THREAD_STACK_SIZE 0 /* use default stack size */
  92. # endif
  93. /* for safety, ensure a viable minimum stacksize */
  94. # define THREAD_STACK_MIN 0x8000 /* 32kB */
  95. #else /* !_POSIX_THREAD_ATTR_STACKSIZE */
  96. # ifdef THREAD_STACK_SIZE
  97. # error "THREAD_STACK_SIZE defined but _POSIX_THREAD_ATTR_STACKSIZE undefined"
  98. # endif
  99. #endif
  100. /* XXX This implementation is considered (to quote Tim Peters) "inherently
  101. hosed" because:
  102. - It does not guarantee the promise that a non-zero integer is returned.
  103. - The cast to long is inherently unsafe.
  104. - It is not clear that the 'volatile' (for AIX?) and ugly casting in the
  105. latter return statement (for Alpha OSF/1) are any longer necessary.
  106. */
  107. long RPyThreadGetIdent(void)
  108. {
  109. volatile pthread_t threadid;
  110. /* Jump through some hoops for Alpha OSF/1 */
  111. threadid = pthread_self();
  112. #ifdef __CYGWIN__
  113. /* typedef __uint32_t pthread_t; */
  114. return (long) threadid;
  115. #else
  116. if (sizeof(pthread_t) <= sizeof(long))
  117. return (long) threadid;
  118. else
  119. return (long) *(long *) &threadid;
  120. #endif
  121. }
  122. static long _pypythread_stacksize = 0;
  123. static void *bootstrap_pthread(void *func)
  124. {
  125. ((void(*)(void))func)();
  126. return NULL;
  127. }
  128. long RPyThreadStart(void (*func)(void))
  129. {
  130. pthread_t th;
  131. int status;
  132. #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
  133. pthread_attr_t attrs;
  134. #endif
  135. #if defined(THREAD_STACK_SIZE)
  136. size_t tss;
  137. #endif
  138. #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
  139. pthread_attr_init(&attrs);
  140. #endif
  141. #ifdef THREAD_STACK_SIZE
  142. tss = (_pypythread_stacksize != 0) ? _pypythread_stacksize
  143. : THREAD_STACK_SIZE;
  144. if (tss != 0)
  145. pthread_attr_setstacksize(&attrs, tss);
  146. #endif
  147. #if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) && !defined(__FreeBSD__)
  148. pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);
  149. #endif
  150. status = pthread_create(&th,
  151. #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
  152. &attrs,
  153. #else
  154. (pthread_attr_t*)NULL,
  155. #endif
  156. bootstrap_pthread,
  157. (void *)func
  158. );
  159. #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
  160. pthread_attr_destroy(&attrs);
  161. #endif
  162. if (status != 0)
  163. return -1;
  164. pthread_detach(th);
  165. #ifdef __CYGWIN__
  166. /* typedef __uint32_t pthread_t; */
  167. return (long) th;
  168. #else
  169. if (sizeof(pthread_t) <= sizeof(long))
  170. return (long) th;
  171. else
  172. return (long) *(long *) &th;
  173. #endif
  174. }
  175. long RPyThreadGetStackSize(void)
  176. {
  177. return _pypythread_stacksize;
  178. }
  179. long RPyThreadSetStackSize(long newsize)
  180. {
  181. #if defined(THREAD_STACK_SIZE)
  182. pthread_attr_t attrs;
  183. size_t tss_min;
  184. int rc;
  185. #endif
  186. if (newsize == 0) { /* set to default */
  187. _pypythread_stacksize = 0;
  188. return 0;
  189. }
  190. #if defined(THREAD_STACK_SIZE)
  191. # if defined(PTHREAD_STACK_MIN)
  192. tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN
  193. : THREAD_STACK_MIN;
  194. # else
  195. tss_min = THREAD_STACK_MIN;
  196. # endif
  197. if (newsize >= tss_min) {
  198. /* validate stack size by setting thread attribute */
  199. if (pthread_attr_init(&attrs) == 0) {
  200. rc = pthread_attr_setstacksize(&attrs, newsize);
  201. pthread_attr_destroy(&attrs);
  202. if (rc == 0) {
  203. _pypythread_stacksize = newsize;
  204. return 0;
  205. }
  206. }
  207. }
  208. return -1;
  209. #else
  210. return -2;
  211. #endif
  212. }
  213. /************************************************************/
  214. #ifdef USE_SEMAPHORES
  215. /************************************************************/
  216. #include <semaphore.h>
  217. void RPyThreadAfterFork(void)
  218. {
  219. }
  220. int RPyThreadLockInit(struct RPyOpaque_ThreadLock *lock)
  221. {
  222. int status, error = 0;
  223. lock->initialized = 0;
  224. status = sem_init(&lock->sem, 0, 1);
  225. CHECK_STATUS("sem_init");
  226. if (error)
  227. return 0;
  228. lock->initialized = 1;
  229. return 1;
  230. }
  231. void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock)
  232. {
  233. int status, error = 0;
  234. if (lock->initialized) {
  235. status = sem_destroy(&lock->sem);
  236. CHECK_STATUS("sem_destroy");
  237. /* 'error' is ignored;
  238. CHECK_STATUS already printed an error message */
  239. }
  240. }
  241. /*
  242. * As of February 2002, Cygwin thread implementations mistakenly report error
  243. * codes in the return value of the sem_ calls (like the pthread_ functions).
  244. * Correct implementations return -1 and put the code in errno. This supports
  245. * either.
  246. */
  247. static int
  248. rpythread_fix_status(int status)
  249. {
  250. return (status == -1) ? errno : status;
  251. }
  252. int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag)
  253. {
  254. int success;
  255. sem_t *thelock = &lock->sem;
  256. int status, error = 0;
  257. do {
  258. if (waitflag)
  259. status = rpythread_fix_status(sem_wait(thelock));
  260. else
  261. status = rpythread_fix_status(sem_trywait(thelock));
  262. } while (status == EINTR); /* Retry if interrupted by a signal */
  263. if (waitflag) {
  264. CHECK_STATUS("sem_wait");
  265. } else if (status != EAGAIN) {
  266. CHECK_STATUS("sem_trywait");
  267. }
  268. success = (status == 0) ? 1 : 0;
  269. return success;
  270. }
  271. void RPyThreadReleaseLock(struct RPyOpaque_ThreadLock *lock)
  272. {
  273. sem_t *thelock = &lock->sem;
  274. int status, error = 0;
  275. status = sem_post(thelock);
  276. CHECK_STATUS("sem_post");
  277. }
  278. /************************************************************/
  279. #else /* no semaphores */
  280. /************************************************************/
  281. struct RPyOpaque_ThreadLock *alllocks; /* doubly-linked list */
  282. void RPyThreadAfterFork(void)
  283. {
  284. /* Mess. We have no clue about how it works on CPython on OSX,
  285. but the issue is that the state of mutexes is not really
  286. preserved across a fork(). So we need to walk over all lock
  287. objects here, and rebuild their mutex and condition variable.
  288. See e.g. http://hackage.haskell.org/trac/ghc/ticket/1391 for
  289. a similar bug about GHC.
  290. */
  291. struct RPyOpaque_ThreadLock *p = alllocks;
  292. alllocks = NULL;
  293. while (p) {
  294. struct RPyOpaque_ThreadLock *next = p->next;
  295. int was_locked = p->locked;
  296. RPyThreadLockInit(p);
  297. p->locked = was_locked;
  298. p = next;
  299. }
  300. }
  301. int RPyThreadLockInit(struct RPyOpaque_ThreadLock *lock)
  302. {
  303. int status, error = 0;
  304. lock->initialized = 0;
  305. lock->locked = 0;
  306. status = pthread_mutex_init(&lock->mut,
  307. pthread_mutexattr_default);
  308. CHECK_STATUS("pthread_mutex_init");
  309. status = pthread_cond_init(&lock->lock_released,
  310. pthread_condattr_default);
  311. CHECK_STATUS("pthread_cond_init");
  312. if (error)
  313. return 0;
  314. lock->initialized = 1;
  315. /* add 'lock' in the doubly-linked list */
  316. if (alllocks)
  317. alllocks->prev = lock;
  318. lock->next = alllocks;
  319. lock->prev = NULL;
  320. alllocks = lock;
  321. return 1;
  322. }
  323. void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock)
  324. {
  325. int status, error = 0;
  326. if (lock->initialized) {
  327. /* remove 'lock' from the doubly-linked list */
  328. if (lock->prev)
  329. lock->prev->next = lock->next;
  330. else {
  331. assert(alllocks == lock);
  332. alllocks = lock->next;
  333. }
  334. if (lock->next)
  335. lock->next->prev = lock->prev;
  336. status = pthread_mutex_destroy(&lock->mut);
  337. CHECK_STATUS("pthread_mutex_destroy");
  338. status = pthread_cond_destroy(&lock->lock_released);
  339. CHECK_STATUS("pthread_cond_destroy");
  340. /* 'error' is ignored;
  341. CHECK_STATUS already printed an error message */
  342. }
  343. }
  344. int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag)
  345. {
  346. int success;
  347. int status, error = 0;
  348. status = pthread_mutex_lock( &lock->mut );
  349. CHECK_STATUS("pthread_mutex_lock[1]");
  350. success = lock->locked == 0;
  351. if ( !success && waitflag ) {
  352. /* continue trying until we get the lock */
  353. /* mut must be locked by me -- part of the condition
  354. * protocol */
  355. while ( lock->locked ) {
  356. status = pthread_cond_wait(&lock->lock_released,
  357. &lock->mut);
  358. CHECK_STATUS("pthread_cond_wait");
  359. }
  360. success = 1;
  361. }
  362. if (success) lock->locked = 1;
  363. status = pthread_mutex_unlock( &lock->mut );
  364. CHECK_STATUS("pthread_mutex_unlock[1]");
  365. if (error) success = 0;
  366. return success;
  367. }
  368. void RPyThreadReleaseLock(struct RPyOpaque_ThreadLock *lock)
  369. {
  370. int status, error = 0;
  371. status = pthread_mutex_lock( &lock->mut );
  372. CHECK_STATUS("pthread_mutex_lock[3]");
  373. lock->locked = 0;
  374. status = pthread_mutex_unlock( &lock->mut );
  375. CHECK_STATUS("pthread_mutex_unlock[3]");
  376. /* wake up someone (anyone, if any) waiting on the lock */
  377. status = pthread_cond_signal( &lock->lock_released );
  378. CHECK_STATUS("pthread_cond_signal");
  379. }
  380. /************************************************************/
  381. #endif /* no semaphores */
  382. /************************************************************/
  383. /* Thread-local storage */
  384. #define RPyThreadTLS pthread_key_t
  385. char *RPyThreadTLS_Create(RPyThreadTLS *result)
  386. {
  387. if (pthread_key_create(result, NULL) != 0)
  388. return "out of thread-local storage keys";
  389. else
  390. return NULL;
  391. }
  392. #define RPyThreadTLS_Get(key) pthread_getspecific(key)
  393. #define RPyThreadTLS_Set(key, value) pthread_setspecific(key, value)
  394. /************************************************************/
  395. /* GIL code */
  396. /************************************************************/
  397. #ifdef __llvm__
  398. # define HAS_ATOMIC_ADD
  399. #endif
  400. #ifdef __GNUC__
  401. # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
  402. # define HAS_ATOMIC_ADD
  403. # endif
  404. #endif
  405. #ifdef HAS_ATOMIC_ADD
  406. # define atomic_add __sync_fetch_and_add
  407. #else
  408. # if defined(__amd64__)
  409. # define atomic_add(ptr, value) asm volatile ("lock addq %0, %1" \
  410. : : "ri"(value), "m"(*(ptr)) : "memory")
  411. # elif defined(__i386__)
  412. # define atomic_add(ptr, value) asm volatile ("lock addl %0, %1" \
  413. : : "ri"(value), "m"(*(ptr)) : "memory")
  414. # else
  415. # error "Please use gcc >= 4.1 or write a custom 'asm' for your CPU."
  416. # endif
  417. #endif
  418. #define ASSERT_STATUS(call) \
  419. if (call != 0) { \
  420. fprintf(stderr, "Fatal error: " #call "\n"); \
  421. abort(); \
  422. }
  423. static void _debug_print(const char *msg)
  424. {
  425. #if 0
  426. int col = (int)pthread_self();
  427. col = 31 + ((col / 8) % 8);
  428. fprintf(stderr, "\033[%dm%s\033[0m", col, msg);
  429. #endif
  430. }
  431. static volatile long pending_acquires = -1;
  432. static pthread_mutex_t mutex_gil = PTHREAD_MUTEX_INITIALIZER;
  433. static pthread_cond_t cond_gil = PTHREAD_COND_INITIALIZER;
  434. static void assert_has_the_gil(void)
  435. {
  436. #ifdef RPY_ASSERT
  437. assert(pthread_mutex_trylock(&mutex_gil) != 0);
  438. assert(pending_acquires >= 0);
  439. #endif
  440. }
  441. long RPyGilAllocate(void)
  442. {
  443. _debug_print("RPyGilAllocate\n");
  444. pending_acquires = 0;
  445. pthread_mutex_trylock(&mutex_gil);
  446. assert_has_the_gil();
  447. return 1;
  448. }
  449. long RPyGilYieldThread(void)
  450. {
  451. /* can be called even before RPyGilAllocate(), but in this case,
  452. pending_acquires will be -1 */
  453. #ifdef RPY_ASSERT
  454. if (pending_acquires >= 0)
  455. assert_has_the_gil();
  456. #endif
  457. if (pending_acquires <= 0)
  458. return 0;
  459. atomic_add(&pending_acquires, 1L);
  460. _debug_print("{");
  461. ASSERT_STATUS(pthread_cond_signal(&cond_gil));
  462. ASSERT_STATUS(pthread_cond_wait(&cond_gil, &mutex_gil));
  463. _debug_print("}");
  464. atomic_add(&pending_acquires, -1L);
  465. assert_has_the_gil();
  466. return 1;
  467. }
  468. void RPyGilRelease(void)
  469. {
  470. _debug_print("RPyGilRelease\n");
  471. #ifdef RPY_ASSERT
  472. assert(pending_acquires >= 0);
  473. #endif
  474. assert_has_the_gil();
  475. ASSERT_STATUS(pthread_mutex_unlock(&mutex_gil));
  476. ASSERT_STATUS(pthread_cond_signal(&cond_gil));
  477. }
  478. void RPyGilAcquire(void)
  479. {
  480. _debug_print("about to RPyGilAcquire...\n");
  481. #ifdef RPY_ASSERT
  482. assert(pending_acquires >= 0);
  483. #endif
  484. atomic_add(&pending_acquires, 1L);
  485. ASSERT_STATUS(pthread_mutex_lock(&mutex_gil));
  486. atomic_add(&pending_acquires, -1L);
  487. assert_has_the_gil();
  488. _debug_print("RPyGilAcquire\n");
  489. }
  490. #endif /* PYPY_NOT_MAIN_FILE */