Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / native_client_sdk / src / libraries / third_party / pthreads-win32 / pthread_cond_wait.c
blob359219ae9b6f46063b2487288263319277bd2e37
1 /*
2 * pthread_cond_wait.c
4 * Description:
5 * This translation unit implements condition variables and their primitives.
8 * --------------------------------------------------------------------------
10 * Pthreads-win32 - POSIX Threads Library for Win32
11 * Copyright(C) 1998 John E. Bossom
12 * Copyright(C) 1999,2005 Pthreads-win32 contributors
14 * Contact Email: rpj@callisto.canberra.edu.au
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
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.
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.
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
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
45 * Algorithm 8a / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
47 * presented below in pseudo-code as it appeared:
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
59 * wait( timeout ) {
61 * [auto: register int result ] // error checking omitted
62 * [auto: register int nSignalsWasLeft ]
63 * [auto: register int nWaitersWasGone ]
65 * sem_wait( semBlockLock );
66 * nWaitersBlocked++;
67 * sem_post( semBlockLock );
69 * unlock( mtxExternal );
70 * bTimedOut = sem_wait( semBlockQueue,timeout );
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;
101 * unlock( mtxUnblockLock );
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
109 * } sem_post( semBlockLock ); // open the gate
112 * lock( mtxExternal );
114 * return ( bTimedOut ) ? ETIMEOUT : 0;
117 * signal(bAll) {
119 * [auto: register int result ]
120 * [auto: register int nSignalsToIssue]
122 * lock( mtxUnblockLock );
124 * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
125 * if ( 0 == nWaitersBlocked ) { // NO-OP
126 * return unlock( mtxUnblockLock );
128 * if (bAll) {
129 * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
130 * nWaitersBlocked = 0;
132 * else {
133 * nSignalsToIssue = 1;
134 * nWaitersToUnblock++;
135 * nWaitersBlocked--;
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;
144 * if (bAll) {
145 * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
146 * nWaitersBlocked = 0;
148 * else {
149 * nSignalsToIssue = nWaitersToUnblock = 1;
150 * nWaitersBlocked--;
153 * else { // NO-OP
154 * return unlock( mtxUnblockLock );
157 * unlock( mtxUnblockLock );
158 * sem_post( semBlockQueue,nSignalsToIssue );
159 * return result;
161 * -------------------------------------------------------------
163 * Algorithm 9 / IMPL_SEM,UNBLOCK_STRATEGY == UNBLOCK_ALL
165 * presented below in pseudo-code; basically 8a...
166 * ...BUT W/O "spurious wakes" prevention:
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
178 * wait( timeout ) {
180 * [auto: register int result ] // error checking omitted
181 * [auto: register int nSignalsWasLeft ]
183 * sem_wait( semBlockLock );
184 * ++nWaitersBlocked;
185 * sem_post( semBlockLock );
187 * unlock( mtxExternal );
188 * bTimedOut = sem_wait( semBlockQueue,timeout );
190 * lock( mtxUnblockLock );
191 * if ( 0 != (nSignalsWasLeft = nWaitersToUnblock) ) {
192 * --nWaitersToUnblock;
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;
202 * unlock( mtxUnblockLock );
204 * if ( 1 == nSignalsWasLeft ) {
205 * sem_post( semBlockLock ); // open the gate
208 * lock( mtxExternal );
210 * return ( bTimedOut ) ? ETIMEOUT : 0;
213 * signal(bAll) {
215 * [auto: register int result ]
216 * [auto: register int nSignalsToIssue]
218 * lock( mtxUnblockLock );
220 * if ( 0 != nWaitersToUnblock ) { // the gate is closed!!!
221 * if ( 0 == nWaitersBlocked ) { // NO-OP
222 * return unlock( mtxUnblockLock );
224 * if (bAll) {
225 * nWaitersToUnblock += nSignalsToIssue=nWaitersBlocked;
226 * nWaitersBlocked = 0;
228 * else {
229 * nSignalsToIssue = 1;
230 * ++nWaitersToUnblock;
231 * --nWaitersBlocked;
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;
240 * if (bAll) {
241 * nSignalsToIssue = nWaitersToUnblock = nWaitersBlocked;
242 * nWaitersBlocked = 0;
244 * else {
245 * nSignalsToIssue = nWaitersToUnblock = 1;
246 * --nWaitersBlocked;
249 * else { // NO-OP
250 * return unlock( mtxUnblockLock );
253 * unlock( mtxUnblockLock );
254 * sem_post( semBlockQueue,nSignalsToIssue );
255 * return result;
257 * -------------------------------------------------------------
261 #include "pthread.h"
262 #include "implement.h"
265 * Arguments for cond_wait_cleanup, since we can only pass a
266 * single void * to it.
268 typedef struct
270 pthread_mutex_t *mutexPtr;
271 pthread_cond_t cv;
272 int *resultPtr;
273 } ptw32_cond_wait_cleanup_args_t;
275 static void PTW32_CDECL
276 ptw32_cond_wait_cleanup (void *args)
278 ptw32_cond_wait_cleanup_args_t *cleanup_args =
279 (ptw32_cond_wait_cleanup_args_t *) args;
280 pthread_cond_t cv = cleanup_args->cv;
281 int *resultPtr = cleanup_args->resultPtr;
282 int nSignalsWasLeft;
283 int result;
286 * Whether we got here as a result of signal/broadcast or because of
287 * timeout on wait or thread cancellation we indicate that we are no
288 * longer waiting. The waiter is responsible for adjusting waiters
289 * (to)unblock(ed) counts (protected by unblock lock).
291 if ((result = pthread_mutex_lock (&(cv->mtxUnblockLock))) != 0)
293 *resultPtr = result;
294 return;
297 if (0 != (nSignalsWasLeft = cv->nWaitersToUnblock))
299 --(cv->nWaitersToUnblock);
301 else if (INT_MAX / 2 == ++(cv->nWaitersGone))
303 /* Use the non-cancellable version of sem_wait() */
304 if (ptw32_semwait (&(cv->semBlockLock)) != 0)
306 *resultPtr = errno;
308 * This is a fatal error for this CV,
309 * so we deliberately don't unlock
310 * cv->mtxUnblockLock before returning.
312 return;
314 cv->nWaitersBlocked -= cv->nWaitersGone;
315 if (sem_post (&(cv->semBlockLock)) != 0)
317 *resultPtr = errno;
319 * This is a fatal error for this CV,
320 * so we deliberately don't unlock
321 * cv->mtxUnblockLock before returning.
323 return;
325 cv->nWaitersGone = 0;
328 if ((result = pthread_mutex_unlock (&(cv->mtxUnblockLock))) != 0)
330 *resultPtr = result;
331 return;
334 if (1 == nSignalsWasLeft)
336 if (sem_post (&(cv->semBlockLock)) != 0)
338 *resultPtr = errno;
339 return;
344 * XSH: Upon successful return, the mutex has been locked and is owned
345 * by the calling thread.
347 if ((result = pthread_mutex_lock (cleanup_args->mutexPtr)) != 0)
349 *resultPtr = result;
351 } /* ptw32_cond_wait_cleanup */
353 static INLINE int
354 ptw32_cond_timedwait (pthread_cond_t * cond,
355 pthread_mutex_t * mutex, const struct timespec *abstime)
357 int result = 0;
358 pthread_cond_t cv;
359 ptw32_cond_wait_cleanup_args_t cleanup_args;
361 if (cond == NULL || *cond == NULL)
363 return EINVAL;
367 * We do a quick check to see if we need to do more work
368 * to initialise a static condition variable. We check
369 * again inside the guarded section of ptw32_cond_check_need_init()
370 * to avoid race conditions.
372 if (*cond == PTHREAD_COND_INITIALIZER)
374 result = ptw32_cond_check_need_init (cond);
377 if (result != 0 && result != EBUSY)
379 return result;
382 cv = *cond;
384 /* Thread can be cancelled in sem_wait() but this is OK */
385 if (sem_wait (&(cv->semBlockLock)) != 0)
387 return errno;
390 ++(cv->nWaitersBlocked);
392 if (sem_post (&(cv->semBlockLock)) != 0)
394 return errno;
398 * Setup this waiter cleanup handler
400 cleanup_args.mutexPtr = mutex;
401 cleanup_args.cv = cv;
402 cleanup_args.resultPtr = &result;
404 #if defined(_MSC_VER) && _MSC_VER < 1400
405 #pragma inline_depth(0)
406 #endif
407 pthread_cleanup_push (ptw32_cond_wait_cleanup, (void *) &cleanup_args);
410 * Now we can release 'mutex' and...
412 if ((result = pthread_mutex_unlock (mutex)) == 0)
416 * ...wait to be awakened by
417 * pthread_cond_signal, or
418 * pthread_cond_broadcast, or
419 * timeout, or
420 * thread cancellation
422 * Note:
424 * sem_timedwait is a cancellation point,
425 * hence providing the mechanism for making
426 * pthread_cond_wait a cancellation point.
427 * We use the cleanup mechanism to ensure we
428 * re-lock the mutex and adjust (to)unblock(ed) waiters
429 * counts if we are cancelled, timed out or signalled.
431 if (sem_timedwait (&(cv->semBlockQueue), abstime) != 0)
433 result = errno;
438 * Always cleanup
440 pthread_cleanup_pop (1);
441 #if defined(_MSC_VER) && _MSC_VER < 1400
442 #pragma inline_depth()
443 #endif
446 * "result" can be modified by the cleanup handler.
448 return result;
450 } /* ptw32_cond_timedwait */
454 pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex)
456 * ------------------------------------------------------
457 * DOCPUBLIC
458 * This function waits on a condition variable until
459 * awakened by a signal or broadcast.
461 * Caller MUST be holding the mutex lock; the
462 * lock is released and the caller is blocked waiting
463 * on 'cond'. When 'cond' is signaled, the mutex
464 * is re-acquired before returning to the caller.
466 * PARAMETERS
467 * cond
468 * pointer to an instance of pthread_cond_t
470 * mutex
471 * pointer to an instance of pthread_mutex_t
474 * DESCRIPTION
475 * This function waits on a condition variable until
476 * awakened by a signal or broadcast.
478 * NOTES:
480 * 1) The function must be called with 'mutex' LOCKED
481 * by the calling thread, or undefined behaviour
482 * will result.
484 * 2) This routine atomically releases 'mutex' and causes
485 * the calling thread to block on the condition variable.
486 * The blocked thread may be awakened by
487 * pthread_cond_signal or
488 * pthread_cond_broadcast.
490 * Upon successful completion, the 'mutex' has been locked and
491 * is owned by the calling thread.
494 * RESULTS
495 * 0 caught condition; mutex released,
496 * EINVAL 'cond' or 'mutex' is invalid,
497 * EINVAL different mutexes for concurrent waits,
498 * EINVAL mutex is not held by the calling thread,
500 * ------------------------------------------------------
504 * The NULL abstime arg means INFINITE waiting.
506 return (ptw32_cond_timedwait (cond, mutex, NULL));
508 } /* pthread_cond_wait */
512 pthread_cond_timedwait (pthread_cond_t * cond,
513 pthread_mutex_t * mutex,
514 const struct timespec *abstime)
516 * ------------------------------------------------------
517 * DOCPUBLIC
518 * This function waits on a condition variable either until
519 * awakened by a signal or broadcast; or until the time
520 * specified by abstime passes.
522 * PARAMETERS
523 * cond
524 * pointer to an instance of pthread_cond_t
526 * mutex
527 * pointer to an instance of pthread_mutex_t
529 * abstime
530 * pointer to an instance of (const struct timespec)
533 * DESCRIPTION
534 * This function waits on a condition variable either until
535 * awakened by a signal or broadcast; or until the time
536 * specified by abstime passes.
538 * NOTES:
539 * 1) The function must be called with 'mutex' LOCKED
540 * by the calling thread, or undefined behaviour
541 * will result.
543 * 2) This routine atomically releases 'mutex' and causes
544 * the calling thread to block on the condition variable.
545 * The blocked thread may be awakened by
546 * pthread_cond_signal or
547 * pthread_cond_broadcast.
550 * RESULTS
551 * 0 caught condition; mutex released,
552 * EINVAL 'cond', 'mutex', or abstime is invalid,
553 * EINVAL different mutexes for concurrent waits,
554 * EINVAL mutex is not held by the calling thread,
555 * ETIMEDOUT abstime ellapsed before cond was signaled.
557 * ------------------------------------------------------
560 if (abstime == NULL)
562 return EINVAL;
565 return (ptw32_cond_timedwait (cond, mutex, abstime));
567 } /* pthread_cond_timedwait */