xref: /relibc/pthreads-emb/pthread_cond_wait.c (revision 062c5bc4dfeed2c1bed58ed4810dd27adb32c68d)
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