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