pthread_cond_wait.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /*
  2. * pthread_cond_wait.c
  3. *
  4. * Description:
  5. * This translation unit implements condition variables and their primitives.
  6. *
  7. *
  8. * --------------------------------------------------------------------------
  9. *
  10. * Pthreads-win32 - POSIX Threads Library for Win32
  11. * Copyright(C) 1998 John E. Bossom
  12. * Copyright(C) 1999,2005 Pthreads-win32 contributors
  13. *
  14. * Contact Email: [email protected]
  15. *
  16. * The current list of contributors is contained
  17. * in the file CONTRIBUTORS included with the source
  18. * code distribution. The list can also be seen at the
  19. * following World Wide Web location:
  20. * http://sources.redhat.com/pthreads-win32/contributors.html
  21. *
  22. * This library is free software; you can redistribute it and/or
  23. * modify it under the terms of the GNU Lesser General Public
  24. * License as published by the Free Software Foundation; either
  25. * version 2 of the License, or (at your option) any later version.
  26. *
  27. * This library is distributed in the hope that it will be useful,
  28. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  29. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  30. * Lesser General Public License for more details.
  31. *
  32. * You should have received a copy of the GNU Lesser General Public
  33. * License along with this library in the file COPYING.LIB;
  34. * if not, write to the Free Software Foundation, Inc.,
  35. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  36. *
  37. * -------------------------------------------------------------
  38. * Algorithm:
  39. * The algorithm used in this implementation is that developed by
  40. * Alexander Terekhov in colaboration with Louis Thomas. The bulk
  41. * of the discussion is recorded in the file README.CV, which contains
  42. * several generations of both colaborators original algorithms. The final
  43. * algorithm used here is the one referred to as
  44. *
  45. * Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
  46. *
  47. * presented below in pseudo-code as it appeared:
  48. *
  49. *
  50. * given:
  51. * semBlockLock - bin.semaphore
  52. * semBlockQueue - semaphore
  53. * mtxExternal - mutex or CS
  54. * mtxUnblockLock - mutex or CS
  55. * nWaitersGone - int
  56. * nWaitersBlocked - int
  57. * nWaitersToUnblock - int
  58. *
  59. * wait( timeout ) {
  60. *
  61. * [auto: register int result ] // error checking omitted
  62. * [auto: register int nSignalsWasLeft ]
  63. * [auto: register int nWaitersWasGone ]
  64. *
  65. * sem_wait( semBlockLock );
  66. * nWaitersBlocked++;
  67. * sem_post( semBlockLock );
  68. *
  69. * unlock( mtxExternal );
  70. * bTimedOut = sem_wait( semBlockQueue,timeout );
  71. *
  72. * lock( mtxUnblockLock );
  73. * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
  74. * if ( bTimeout ) { // timeout (or canceled)
  75. * if ( 0 != nWaitersBlocked ) {
  76. * nWaitersBlocked--;
  77. * }
  78. * else {
  79. * nWaitersGone++; // count spurious wakeups.
  80. * }
  81. * }
  82. * if ( 0 == --nWaitersToUnblock ) {
  83. * if ( 0 != nWaitersBlocked ) {
  84. * sem_post( semBlockLock ); // open the gate.
  85. * nSignalsWasLeft = 0; // do not open the gate
  86. * // below again.
  87. * }
  88. * else if ( 0 != (nWaitersWasGone = nWaitersGone) ) {
  89. * nWaitersGone = 0;
  90. * }
  91. * }
  92. * }
  93. * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
  94. * // spurious semaphore :-)
  95. * sem_wait( semBlockLock );
  96. * nWaitersBlocked -= nWaitersGone; // something is going on here
  97. * // - test of timeouts? :-)
  98. * sem_post( semBlockLock );
  99. * nWaitersGone = 0;
  100. * }
  101. * unlock( mtxUnblockLock );
  102. *
  103. * if ( 1 == nSignalsWasLeft ) {
  104. * if ( 0 != nWaitersWasGone ) {
  105. * // sem_adjust( semBlockQueue,-nWaitersWasGone );
  106. * while ( nWaitersWasGone-- ) {
  107. * sem_wait( semBlockQueue ); // better now than spurious later
  108. * }
  109. * } sem_post( semBlockLock ); // open the gate
  110. * }
  111. *
  112. * lock( mtxExternal );
  113. *
  114. * return ( bTimedOut ) ? ETIMEOUT : 0;
  115. * }
  116. *
  117. * signal(bAll) {
  118. *
  119. * [auto: register int result ]
  120. * [auto: register int nSignalsToIssue]
  121. *
  122. * lock( mtxUnblockLock );
  123. *
  124. * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
  125. * if ( 0 == nWaitersBlocked ) { // NO-OP
  126. * return unlock( mtxUnblockLock );
  127. * }
  128. * if (bAll) {
  129. * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
  130. * nWaitersBlocked = 0;
  131. * }
  132. * else {
  133. * nSignalsToIssue = 1;
  134. * nWaitersToUnblock++;
  135. * nWaitersBlocked--;
  136. * }
  137. * }
  138. * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
  139. * sem_wait( semBlockLock ); // close the gate
  140. * if ( 0 != nWaitersGone ) {
  141. * nWaitersBlocked -= nWaitersGone;
  142. * nWaitersGone = 0;
  143. * }
  144. * if (bAll) {
  145. * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
  146. * nWaitersBlocked = 0;
  147. * }
  148. * else {
  149. * nSignalsToIssue = nWaitersToUnblock = 1;
  150. * nWaitersBlocked--;
  151. * }
  152. * }
  153. * else { // NO-OP
  154. * return unlock( mtxUnblockLock );
  155. * }
  156. *
  157. * unlock( mtxUnblockLock );
  158. * sem_post( semBlockQueue,nSignalsToIssue );
  159. * return result;
  160. * }
  161. * -------------------------------------------------------------
  162. *
  163. * Algorithm 9 / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
  164. *
  165. * presented below in pseudo-code; basically 8a...
  166. * ...BUT W/O "spurious wakes" prevention:
  167. *
  168. *
  169. * given:
  170. * semBlockLock - bin.semaphore
  171. * semBlockQueue - semaphore
  172. * mtxExternal - mutex or CS
  173. * mtxUnblockLock - mutex or CS
  174. * nWaitersGone - int
  175. * nWaitersBlocked - int
  176. * nWaitersToUnblock - int
  177. *
  178. * wait( timeout ) {
  179. *
  180. * [auto: register int result ] // error checking omitted
  181. * [auto: register int nSignalsWasLeft ]
  182. *
  183. * sem_wait( semBlockLock );
  184. * ++nWaitersBlocked;
  185. * sem_post( semBlockLock );
  186. *
  187. * unlock( mtxExternal );
  188. * bTimedOut = sem_wait( semBlockQueue,timeout );
  189. *
  190. * lock( mtxUnblockLock );
  191. * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
  192. * --nWaitersToUnblock;
  193. * }
  194. * else if ( INT_MAX/2 == ++nWaitersGone ) { // timeout/canceled or
  195. * // spurious semaphore :-)
  196. * sem_wait( semBlockLock );
  197. * nWaitersBlocked -= nWaitersGone; // something is going on here
  198. * // - test of timeouts? :-)
  199. * sem_post( semBlockLock );
  200. * nWaitersGone = 0;
  201. * }
  202. * unlock( mtxUnblockLock );
  203. *
  204. * if ( 1 == nSignalsWasLeft ) {
  205. * sem_post( semBlockLock ); // open the gate
  206. * }
  207. *
  208. * lock( mtxExternal );
  209. *
  210. * return ( bTimedOut ) ? ETIMEOUT : 0;
  211. * }
  212. *
  213. * signal(bAll) {
  214. *
  215. * [auto: register int result ]
  216. * [auto: register int nSignalsToIssue]
  217. *
  218. * lock( mtxUnblockLock );
  219. *
  220. * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
  221. * if ( 0 == nWaitersBlocked ) { // NO-OP
  222. * return unlock( mtxUnblockLock );
  223. * }
  224. * if (bAll) {
  225. * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
  226. * nWaitersBlocked = 0;
  227. * }
  228. * else {
  229. * nSignalsToIssue = 1;
  230. * ++nWaitersToUnblock;
  231. * --nWaitersBlocked;
  232. * }
  233. * }
  234. * else if ( nWaitersBlocked > nWaitersGone ) { // HARMLESS RACE CONDITION!
  235. * sem_wait( semBlockLock ); // close the gate
  236. * if ( 0 != nWaitersGone ) {
  237. * nWaitersBlocked -= nWaitersGone;
  238. * nWaitersGone = 0;
  239. * }
  240. * if (bAll) {
  241. * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
  242. * nWaitersBlocked = 0;
  243. * }
  244. * else {
  245. * nSignalsToIssue = nWaitersToUnblock = 1;
  246. * --nWaitersBlocked;
  247. * }
  248. * }
  249. * else { // NO-OP
  250. * return unlock( mtxUnblockLock );
  251. * }
  252. *
  253. * unlock( mtxUnblockLock );
  254. * sem_post( semBlockQueue,nSignalsToIssue );
  255. * return result;
  256. * }
  257. * -------------------------------------------------------------
  258. *
  259. */
  260. #include "pthread.h"
  261. #include "implement.h"
  262. /*
  263. * Arguments for cond_wait_cleanup, since we can only pass a
  264. * single void * to it.
  265. */
  266. typedef struct
  267. {
  268. pthread_mutex_t *mutexPtr;
  269. pthread_cond_t cv;
  270. int *resultPtr;
  271. } ptw32_cond_wait_cleanup_args_t;
  272. static void PTW32_CDECL
  273. ptw32_cond_wait_cleanup (void *args)
  274. {
  275. ptw32_cond_wait_cleanup_args_t *cleanup_args =
  276. (ptw32_cond_wait_cleanup_args_t *) args;
  277. pthread_cond_t cv = cleanup_args->cv;
  278. int *resultPtr = cleanup_args->resultPtr;
  279. int nSignalsWasLeft;
  280. int result;
  281. /*
  282. * Whether we got here as a result of signal/broadcast or because of
  283. * timeout on wait or thread cancellation we indicate that we are no
  284. * longer waiting. The waiter is responsible for adjusting waiters
  285. * (to)unblock(ed) counts (protected by unblock lock).
  286. */
  287. if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0)
  288. {
  289. *resultPtr = result;
  290. return;
  291. }
  292. if (0 != (nSignalsWasLeft = cv->nWaitersToUnblock))
  293. {
  294. --(cv->nWaitersToUnblock);
  295. }
  296. else if (INT_MAX / 2 == ++(cv->nWaitersGone))
  297. {
  298. /* Use the non-cancellable version of sem_wait() */
  299. if (ptw32_semwait (&(cv->semBlockLock)) != 0)
  300. {
  301. *resultPtr = errno;
  302. /*
  303. * This is a fatal error for this CV,
  304. * so we deliberately don't unlock
  305. * cv->mtxUnblockLock before returning.
  306. */
  307. return;
  308. }
  309. cv->nWaitersBlocked -= cv->nWaitersGone;
  310. if (sem_post (&(cv->semBlockLock)) != 0)
  311. {
  312. *resultPtr = errno;
  313. /*
  314. * This is a fatal error for this CV,
  315. * so we deliberately don't unlock
  316. * cv->mtxUnblockLock before returning.
  317. */
  318. return;
  319. }
  320. cv->nWaitersGone = 0;
  321. }
  322. if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) != 0)
  323. {
  324. *resultPtr = result;
  325. return;
  326. }
  327. if (1 == nSignalsWasLeft)
  328. {
  329. if (sem_post (&(cv->semBlockLock)) != 0)
  330. {
  331. *resultPtr = errno;
  332. return;
  333. }
  334. }
  335. /*
  336. * XSH: Upon successful return, the mutex has been locked and is owned
  337. * by the calling thread.
  338. */
  339. if ((result = pthread_mutex_lock (cleanup_args->mutexPtr)) != 0)
  340. {
  341. *resultPtr = result;
  342. }
  343. } /* ptw32_cond_wait_cleanup */
  344. static INLINE int
  345. ptw32_cond_timedwait (pthread_cond_t * cond,
  346. pthread_mutex_t * mutex, const struct timespec *abstime)
  347. {
  348. int result = 0;
  349. pthread_cond_t cv;
  350. ptw32_cond_wait_cleanup_args_t cleanup_args;
  351. if (cond == NULL || *cond == NULL)
  352. {
  353. return EINVAL;
  354. }
  355. /*
  356. * We do a quick check to see if we need to do more work
  357. * to initialise a static condition variable. We check
  358. * again inside the guarded section of ptw32_cond_check_need_init()
  359. * to avoid race conditions.
  360. */
  361. if (*cond == PTHREAD_COND_INITIALIZER)
  362. {
  363. result = ptw32_cond_check_need_init (cond);
  364. }
  365. if (result != 0 && result != EBUSY)
  366. {
  367. return result;
  368. }
  369. cv = *cond;
  370. /* Thread can be cancelled in sem_wait() but this is OK */
  371. if (sem_wait (&(cv->semBlockLock)) != 0)
  372. {
  373. return errno;
  374. }
  375. ++(cv->nWaitersBlocked);
  376. if (sem_post (&(cv->semBlockLock)) != 0)
  377. {
  378. return errno;
  379. }
  380. /*
  381. * Setup this waiter cleanup handler
  382. */
  383. cleanup_args.mutexPtr = mutex;
  384. cleanup_args.cv = cv;
  385. cleanup_args.resultPtr = &result;
  386. #if defined(_MSC_VER) && _MSC_VER < 1400
  387. #pragma inline_depth(0)
  388. #endif
  389. pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args);
  390. /*
  391. * Now we can release 'mutex' and...
  392. */
  393. if ((result = pthread_mutex_unlock (mutex)) == 0)
  394. {
  395. /*
  396. * ...wait to be awakened by
  397. * pthread_cond_signal, or
  398. * pthread_cond_broadcast, or
  399. * timeout, or
  400. * thread cancellation
  401. *
  402. * Note:
  403. *
  404. * sem_timedwait is a cancellation point,
  405. * hence providing the mechanism for making
  406. * pthread_cond_wait a cancellation point.
  407. * We use the cleanup mechanism to ensure we
  408. * re-lock the mutex and adjust (to)unblock(ed) waiters
  409. * counts if we are cancelled, timed out or signalled.
  410. */
  411. if (sem_timedwait (&(cv->semBlockQueue), abstime) != 0)
  412. {
  413. result = errno;
  414. }
  415. }
  416. /*
  417. * Always cleanup
  418. */
  419. pthread_cleanup_pop (1);
  420. #if defined(_MSC_VER) && _MSC_VER < 1400
  421. #pragma inline_depth()
  422. #endif
  423. /*
  424. * "result" can be modified by the cleanup handler.
  425. */
  426. return result;
  427. } /* ptw32_cond_timedwait */
  428. int
  429. pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex)
  430. /*
  431. * ------------------------------------------------------
  432. * DOCPUBLIC
  433. * This function waits on a condition variable until
  434. * awakened by a signal or broadcast.
  435. *
  436. * Caller MUST be holding the mutex lock; the
  437. * lock is released and the caller is blocked waiting
  438. * on 'cond'. When 'cond' is signaled, the mutex
  439. * is re-acquired before returning to the caller.
  440. *
  441. * PARAMETERS
  442. * cond
  443. * pointer to an instance of pthread_cond_t
  444. *
  445. * mutex
  446. * pointer to an instance of pthread_mutex_t
  447. *
  448. *
  449. * DESCRIPTION
  450. * This function waits on a condition variable until
  451. * awakened by a signal or broadcast.
  452. *
  453. * NOTES:
  454. *
  455. * 1) The function must be called with 'mutex' LOCKED
  456. * by the calling thread, or undefined behaviour
  457. * will result.
  458. *
  459. * 2) This routine atomically releases 'mutex' and causes
  460. * the calling thread to block on the condition variable.
  461. * The blocked thread may be awakened by
  462. * pthread_cond_signal or
  463. * pthread_cond_broadcast.
  464. *
  465. * Upon successful completion, the 'mutex' has been locked and
  466. * is owned by the calling thread.
  467. *
  468. *
  469. * RESULTS
  470. * 0 caught condition; mutex released,
  471. * EINVAL 'cond' or 'mutex' is invalid,
  472. * EINVAL different mutexes for concurrent waits,
  473. * EINVAL mutex is not held by the calling thread,
  474. *
  475. * ------------------------------------------------------
  476. */
  477. {
  478. /*
  479. * The NULL abstime arg means INFINITE waiting.
  480. */
  481. return (ptw32_cond_timedwait (cond, mutex, NULL));
  482. } /* pthread_cond_wait */
  483. int
  484. pthread_cond_timedwait (pthread_cond_t * cond,
  485. pthread_mutex_t * mutex,
  486. const struct timespec *abstime)
  487. /*
  488. * ------------------------------------------------------
  489. * DOCPUBLIC
  490. * This function waits on a condition variable either until
  491. * awakened by a signal or broadcast; or until the time
  492. * specified by abstime passes.
  493. *
  494. * PARAMETERS
  495. * cond
  496. * pointer to an instance of pthread_cond_t
  497. *
  498. * mutex
  499. * pointer to an instance of pthread_mutex_t
  500. *
  501. * abstime
  502. * pointer to an instance of (const struct timespec)
  503. *
  504. *
  505. * DESCRIPTION
  506. * This function waits on a condition variable either until
  507. * awakened by a signal or broadcast; or until the time
  508. * specified by abstime passes.
  509. *
  510. * NOTES:
  511. * 1) The function must be called with 'mutex' LOCKED
  512. * by the calling thread, or undefined behaviour
  513. * will result.
  514. *
  515. * 2) This routine atomically releases 'mutex' and causes
  516. * the calling thread to block on the condition variable.
  517. * The blocked thread may be awakened by
  518. * pthread_cond_signal or
  519. * pthread_cond_broadcast.
  520. *
  521. *
  522. * RESULTS
  523. * 0 caught condition; mutex released,
  524. * EINVAL 'cond', 'mutex', or abstime is invalid,
  525. * EINVAL different mutexes for concurrent waits,
  526. * EINVAL mutex is not held by the calling thread,
  527. * ETIMEDOUT abstime ellapsed before cond was signaled.
  528. *
  529. * ------------------------------------------------------
  530. */
  531. {
  532. if (abstime == NULL)
  533. {
  534. return EINVAL;
  535. }
  536. return (ptw32_cond_timedwait (cond, mutex, abstime));
  537. } /* pthread_cond_timedwait */