PageRenderTime 52ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/translator/c/src/thread_pthread.c

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