Deleted Added
full compact
thr_cond.c (113658) thr_cond.c (113786)
1/*
2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
1/*
2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $FreeBSD: head/lib/libkse/thread/thr_cond.c 113658 2003-04-18 05:04:16Z deischen $
32 * $FreeBSD: head/lib/libkse/thread/thr_cond.c 113786 2003-04-21 04:02:56Z deischen $
33 */
34#include <stdlib.h>
35#include <errno.h>
36#include <string.h>
37#include <pthread.h>
38#include "thr_private.h"
39
40#define THR_IN_CONDQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
41#define THR_IN_CONDQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
42#define THR_CONDQ_SET(thr) (thr)->sflags |= THR_FLAGS_IN_SYNCQ
43#define THR_CONDQ_CLEAR(thr) (thr)->sflags &= ~THR_FLAGS_IN_SYNCQ
44
45/*
46 * Prototypes
47 */
48static inline struct pthread *cond_queue_deq(pthread_cond_t);
49static inline void cond_queue_remove(pthread_cond_t, pthread_t);
50static inline void cond_queue_enq(pthread_cond_t, pthread_t);
51
52__weak_reference(_pthread_cond_init, pthread_cond_init);
53__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
54__weak_reference(_pthread_cond_wait, pthread_cond_wait);
55__weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait);
56__weak_reference(_pthread_cond_signal, pthread_cond_signal);
57__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
58
59
60int
61_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
62{
63 enum pthread_cond_type type;
64 pthread_cond_t pcond;
65 int flags;
66 int rval = 0;
67
68 if (cond == NULL)
69 rval = EINVAL;
70 else {
71 /*
72 * Check if a pointer to a condition variable attribute
73 * structure was passed by the caller:
74 */
75 if (cond_attr != NULL && *cond_attr != NULL) {
76 /* Default to a fast condition variable: */
77 type = (*cond_attr)->c_type;
78 flags = (*cond_attr)->c_flags;
79 } else {
80 /* Default to a fast condition variable: */
81 type = COND_TYPE_FAST;
82 flags = 0;
83 }
84
85 /* Process according to condition variable type: */
86 switch (type) {
87 /* Fast condition variable: */
88 case COND_TYPE_FAST:
89 /* Nothing to do here. */
90 break;
91
92 /* Trap invalid condition variable types: */
93 default:
94 /* Return an invalid argument error: */
95 rval = EINVAL;
96 break;
97 }
98
99 /* Check for no errors: */
100 if (rval == 0) {
101 if ((pcond = (pthread_cond_t)
102 malloc(sizeof(struct pthread_cond))) == NULL) {
103 rval = ENOMEM;
104 } else if (_lock_init(&pcond->c_lock, LCK_ADAPTIVE,
33 */
34#include <stdlib.h>
35#include <errno.h>
36#include <string.h>
37#include <pthread.h>
38#include "thr_private.h"
39
40#define THR_IN_CONDQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
41#define THR_IN_CONDQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
42#define THR_CONDQ_SET(thr) (thr)->sflags |= THR_FLAGS_IN_SYNCQ
43#define THR_CONDQ_CLEAR(thr) (thr)->sflags &= ~THR_FLAGS_IN_SYNCQ
44
45/*
46 * Prototypes
47 */
48static inline struct pthread *cond_queue_deq(pthread_cond_t);
49static inline void cond_queue_remove(pthread_cond_t, pthread_t);
50static inline void cond_queue_enq(pthread_cond_t, pthread_t);
51
52__weak_reference(_pthread_cond_init, pthread_cond_init);
53__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
54__weak_reference(_pthread_cond_wait, pthread_cond_wait);
55__weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait);
56__weak_reference(_pthread_cond_signal, pthread_cond_signal);
57__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
58
59
60int
61_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
62{
63 enum pthread_cond_type type;
64 pthread_cond_t pcond;
65 int flags;
66 int rval = 0;
67
68 if (cond == NULL)
69 rval = EINVAL;
70 else {
71 /*
72 * Check if a pointer to a condition variable attribute
73 * structure was passed by the caller:
74 */
75 if (cond_attr != NULL && *cond_attr != NULL) {
76 /* Default to a fast condition variable: */
77 type = (*cond_attr)->c_type;
78 flags = (*cond_attr)->c_flags;
79 } else {
80 /* Default to a fast condition variable: */
81 type = COND_TYPE_FAST;
82 flags = 0;
83 }
84
85 /* Process according to condition variable type: */
86 switch (type) {
87 /* Fast condition variable: */
88 case COND_TYPE_FAST:
89 /* Nothing to do here. */
90 break;
91
92 /* Trap invalid condition variable types: */
93 default:
94 /* Return an invalid argument error: */
95 rval = EINVAL;
96 break;
97 }
98
99 /* Check for no errors: */
100 if (rval == 0) {
101 if ((pcond = (pthread_cond_t)
102 malloc(sizeof(struct pthread_cond))) == NULL) {
103 rval = ENOMEM;
104 } else if (_lock_init(&pcond->c_lock, LCK_ADAPTIVE,
105 _kse_lock_wait, _kse_lock_wakeup) != 0) {
105 _thr_lock_wait, _thr_lock_wakeup) != 0) {
106 free(pcond);
107 rval = ENOMEM;
108 } else {
109 /*
110 * Initialise the condition variable
111 * structure:
112 */
113 TAILQ_INIT(&pcond->c_queue);
114 pcond->c_flags |= COND_FLAGS_INITED;
115 pcond->c_type = type;
116 pcond->c_mutex = NULL;
117 pcond->c_seqno = 0;
118 *cond = pcond;
119 }
120 }
121 }
122 /* Return the completion status: */
123 return (rval);
124}
125
126int
127_pthread_cond_destroy(pthread_cond_t *cond)
128{
129 struct pthread_cond *cv;
130 struct pthread *curthread = _get_curthread();
131 int rval = 0;
132
133 if (cond == NULL || *cond == NULL)
134 rval = EINVAL;
135 else {
136 /* Lock the condition variable structure: */
137 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
138
139 /*
140 * NULL the caller's pointer now that the condition
141 * variable has been destroyed:
142 */
143 cv = *cond;
144 *cond = NULL;
145
146 /* Unlock the condition variable structure: */
147 THR_LOCK_RELEASE(curthread, &cv->c_lock);
148
149 /*
150 * Free the memory allocated for the condition
151 * variable structure:
152 */
153 free(cv);
154
155 }
156 /* Return the completion status: */
157 return (rval);
158}
159
160int
161_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
162{
163 struct pthread *curthread = _get_curthread();
164 int rval = 0;
165 int done = 0;
166 int interrupted = 0;
167 int unlock_mutex = 1;
168 int seqno;
169
170 _thr_enter_cancellation_point(curthread);
171
172 if (cond == NULL) {
173 _thr_leave_cancellation_point(curthread);
174 return (EINVAL);
175 }
176
177 /*
178 * If the condition variable is statically initialized,
179 * perform the dynamic initialization:
180 */
181 if (*cond == NULL &&
182 (rval = pthread_cond_init(cond, NULL)) != 0) {
183 _thr_leave_cancellation_point(curthread);
184 return (rval);
185 }
186
187 /*
188 * Enter a loop waiting for a condition signal or broadcast
189 * to wake up this thread. A loop is needed in case the waiting
190 * thread is interrupted by a signal to execute a signal handler.
191 * It is not (currently) possible to remain in the waiting queue
192 * while running a handler. Instead, the thread is interrupted
193 * and backed out of the waiting queue prior to executing the
194 * signal handler.
195 */
196 do {
197 /* Lock the condition variable structure: */
198 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
199
200 /*
201 * If the condvar was statically allocated, properly
202 * initialize the tail queue.
203 */
204 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
205 TAILQ_INIT(&(*cond)->c_queue);
206 (*cond)->c_flags |= COND_FLAGS_INITED;
207 }
208
209 /* Process according to condition variable type: */
210 switch ((*cond)->c_type) {
211 /* Fast condition variable: */
212 case COND_TYPE_FAST:
213 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
214 ((*cond)->c_mutex != *mutex))) {
215 /* Unlock the condition variable structure: */
216 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
217
218 /* Return invalid argument error: */
219 rval = EINVAL;
220 } else {
221 /* Reset the timeout and interrupted flags: */
222 curthread->timeout = 0;
223 curthread->interrupted = 0;
224
225 /*
226 * Queue the running thread for the condition
227 * variable:
228 */
229 cond_queue_enq(*cond, curthread);
230
231 /* Remember the mutex and sequence number: */
232 (*cond)->c_mutex = *mutex;
233 seqno = (*cond)->c_seqno;
234
235 /* Wait forever: */
236 curthread->wakeup_time.tv_sec = -1;
237
238 /* Unlock the mutex: */
239 if ((unlock_mutex != 0) &&
240 ((rval = _mutex_cv_unlock(mutex)) != 0)) {
241 /*
242 * Cannot unlock the mutex, so remove
243 * the running thread from the condition
244 * variable queue:
245 */
246 cond_queue_remove(*cond, curthread);
247
248 /* Check for no more waiters: */
249 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
250 (*cond)->c_mutex = NULL;
251
252 /* Unlock the condition variable structure: */
253 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
254 }
255 else {
256 /*
257 * Don't unlock the mutex the next
258 * time through the loop (if the
259 * thread has to be requeued after
260 * handling a signal).
261 */
262 unlock_mutex = 0;
263
264 /*
265 * This thread is active and is in a
266 * critical region (holding the cv
267 * lock); we should be able to safely
268 * set the state.
269 */
270 THR_SET_STATE(curthread, PS_COND_WAIT);
271
272 /* Remember the CV: */
273 curthread->data.cond = *cond;
274
275 /* Unlock the CV structure: */
276 THR_LOCK_RELEASE(curthread,
277 &(*cond)->c_lock);
278
279 /* Schedule the next thread: */
280 _thr_sched_switch(curthread);
281
282 curthread->data.cond = NULL;
283
284 /*
285 * XXX - This really isn't a good check
286 * since there can be more than one
287 * thread waiting on the CV. Signals
288 * sent to threads waiting on mutexes
289 * or CVs should really be deferred
290 * until the threads are no longer
291 * waiting, but POSIX says that signals
292 * should be sent "as soon as possible".
293 */
294 done = (seqno != (*cond)->c_seqno);
295
296 if (THR_IN_SYNCQ(curthread)) {
297 /*
298 * Lock the condition variable
299 * while removing the thread.
300 */
301 THR_LOCK_ACQUIRE(curthread,
302 &(*cond)->c_lock);
303
304 cond_queue_remove(*cond,
305 curthread);
306
307 /* Check for no more waiters: */
308 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
309 (*cond)->c_mutex = NULL;
310
311 THR_LOCK_RELEASE(curthread,
312 &(*cond)->c_lock);
313 }
314
315 /*
316 * Save the interrupted flag; locking
317 * the mutex may destroy it.
318 */
319 interrupted = curthread->interrupted;
320
321 /*
322 * Note that even though this thread may
323 * have been canceled, POSIX requires
324 * that the mutex be reaquired prior to
325 * cancellation.
326 */
327 if (done != 0)
328 rval = _mutex_cv_lock(mutex);
329 }
330 }
331 break;
332
333 /* Trap invalid condition variable types: */
334 default:
335 /* Unlock the condition variable structure: */
336 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
337
338 /* Return an invalid argument error: */
339 rval = EINVAL;
340 break;
341 }
342
343 if ((interrupted != 0) && (curthread->continuation != NULL))
344 curthread->continuation((void *) curthread);
345 } while ((done == 0) && (rval == 0));
346
347 _thr_leave_cancellation_point(curthread);
348
349 /* Return the completion status: */
350 return (rval);
351}
352
353int
354__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
355{
356 struct pthread *curthread = _get_curthread();
357 int ret;
358
359 _thr_enter_cancellation_point(curthread);
360 ret = _pthread_cond_wait(cond, mutex);
361 _thr_leave_cancellation_point(curthread);
362 return (ret);
363}
364
365int
366_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
367 const struct timespec * abstime)
368{
369 struct pthread *curthread = _get_curthread();
370 int rval = 0;
371 int done = 0;
372 int interrupted = 0;
373 int unlock_mutex = 1;
374 int seqno;
375
376 _thr_enter_cancellation_point(curthread);
377
378 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
379 abstime->tv_nsec >= 1000000000) {
380 _thr_leave_cancellation_point(curthread);
381 return (EINVAL);
382 }
383 /*
384 * If the condition variable is statically initialized, perform dynamic
385 * initialization.
386 */
387 if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) {
388 _thr_leave_cancellation_point(curthread);
389 return (rval);
390 }
391
392 /*
393 * Enter a loop waiting for a condition signal or broadcast
394 * to wake up this thread. A loop is needed in case the waiting
395 * thread is interrupted by a signal to execute a signal handler.
396 * It is not (currently) possible to remain in the waiting queue
397 * while running a handler. Instead, the thread is interrupted
398 * and backed out of the waiting queue prior to executing the
399 * signal handler.
400 */
401 do {
402 /* Lock the condition variable structure: */
403 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
404
405 /*
406 * If the condvar was statically allocated, properly
407 * initialize the tail queue.
408 */
409 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
410 TAILQ_INIT(&(*cond)->c_queue);
411 (*cond)->c_flags |= COND_FLAGS_INITED;
412 }
413
414 /* Process according to condition variable type: */
415 switch ((*cond)->c_type) {
416 /* Fast condition variable: */
417 case COND_TYPE_FAST:
418 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
419 ((*cond)->c_mutex != *mutex))) {
420 /* Return invalid argument error: */
421 rval = EINVAL;
422
423 /* Unlock the condition variable structure: */
424 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
425 } else {
426 /* Set the wakeup time: */
427 curthread->wakeup_time.tv_sec = abstime->tv_sec;
428 curthread->wakeup_time.tv_nsec =
429 abstime->tv_nsec;
430
431 /* Reset the timeout and interrupted flags: */
432 curthread->timeout = 0;
433 curthread->interrupted = 0;
434
435 /*
436 * Queue the running thread for the condition
437 * variable:
438 */
439 cond_queue_enq(*cond, curthread);
440
441 /* Remember the mutex and sequence number: */
442 (*cond)->c_mutex = *mutex;
443 seqno = (*cond)->c_seqno;
444
445 /* Unlock the mutex: */
446 if ((unlock_mutex != 0) &&
447 ((rval = _mutex_cv_unlock(mutex)) != 0)) {
448 /*
449 * Cannot unlock the mutex; remove the
450 * running thread from the condition
451 * variable queue:
452 */
453 cond_queue_remove(*cond, curthread);
454
455 /* Check for no more waiters: */
456 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
457 (*cond)->c_mutex = NULL;
458
459 /* Unlock the condition variable structure: */
460 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
461 } else {
462 /*
463 * Don't unlock the mutex the next
464 * time through the loop (if the
465 * thread has to be requeued after
466 * handling a signal).
467 */
468 unlock_mutex = 0;
469
470 /*
471 * This thread is active and is in a
472 * critical region (holding the cv
473 * lock); we should be able to safely
474 * set the state.
475 */
476 THR_SET_STATE(curthread, PS_COND_WAIT);
477
478 /* Remember the CV: */
479 curthread->data.cond = *cond;
480
481 /* Unlock the CV structure: */
482 THR_LOCK_RELEASE(curthread,
483 &(*cond)->c_lock);
484
485 /* Schedule the next thread: */
486 _thr_sched_switch(curthread);
487
488 curthread->data.cond = NULL;
489
490 /*
491 * XXX - This really isn't a good check
492 * since there can be more than one
493 * thread waiting on the CV. Signals
494 * sent to threads waiting on mutexes
495 * or CVs should really be deferred
496 * until the threads are no longer
497 * waiting, but POSIX says that signals
498 * should be sent "as soon as possible".
499 */
500 done = (seqno != (*cond)->c_seqno);
501
502 if (THR_IN_CONDQ(curthread)) {
503 /*
504 * Lock the condition variable
505 * while removing the thread.
506 */
507 THR_LOCK_ACQUIRE(curthread,
508 &(*cond)->c_lock);
509
510 cond_queue_remove(*cond,
511 curthread);
512
513 /* Check for no more waiters: */
514 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
515 (*cond)->c_mutex = NULL;
516
517 THR_LOCK_RELEASE(curthread,
518 &(*cond)->c_lock);
519 }
520
521 /*
522 * Save the interrupted flag; locking
523 * the mutex may destroy it.
524 */
525 interrupted = curthread->interrupted;
526 if (curthread->timeout != 0) {
527 /* The wait timedout. */
528 rval = ETIMEDOUT;
529 (void)_mutex_cv_lock(mutex);
530 } else if ((interrupted == 0) ||
531 (done != 0))
532 rval = _mutex_cv_lock(mutex);
533 }
534 }
535 break;
536
537 /* Trap invalid condition variable types: */
538 default:
539 /* Unlock the condition variable structure: */
540 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
541
542 /* Return an invalid argument error: */
543 rval = EINVAL;
544 break;
545 }
546
547 if ((interrupted != 0) && (curthread->continuation != NULL))
548 curthread->continuation((void *)curthread);
549 } while ((done == 0) && (rval == 0));
550
551 _thr_leave_cancellation_point(curthread);
552
553 /* Return the completion status: */
554 return (rval);
555}
556
557int
558__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
559 const struct timespec *abstime)
560{
561 struct pthread *curthread = _get_curthread();
562 int ret;
563
564 _thr_enter_cancellation_point(curthread);
565 ret = _pthread_cond_timedwait(cond, mutex, abstime);
566 _thr_leave_cancellation_point(curthread);
567 return (ret);
568}
569
570
571int
572_pthread_cond_signal(pthread_cond_t * cond)
573{
574 struct pthread *curthread = _get_curthread();
575 struct pthread *pthread;
576 int rval = 0;
577
578 if (cond == NULL)
579 rval = EINVAL;
580 /*
581 * If the condition variable is statically initialized, perform dynamic
582 * initialization.
583 */
584 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
585 /* Lock the condition variable structure: */
586 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
587
588 /* Process according to condition variable type: */
589 switch ((*cond)->c_type) {
590 /* Fast condition variable: */
591 case COND_TYPE_FAST:
592 /* Increment the sequence number: */
593 (*cond)->c_seqno++;
594
595 /*
596 * Wakeups have to be done with the CV lock held;
597 * otherwise there is a race condition where the
598 * thread can timeout, run on another KSE, and enter
599 * another blocking state (including blocking on a CV).
600 */
601 if ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
602 != NULL) {
603 THR_SCHED_LOCK(curthread, pthread);
604 cond_queue_remove(*cond, pthread);
605 _thr_setrunnable_unlocked(pthread);
606 THR_SCHED_UNLOCK(curthread, pthread);
607 }
608 /* Check for no more waiters: */
609 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
610 (*cond)->c_mutex = NULL;
611 break;
612
613 /* Trap invalid condition variable types: */
614 default:
615 /* Return an invalid argument error: */
616 rval = EINVAL;
617 break;
618 }
619
620 /* Unlock the condition variable structure: */
621 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
622 }
623
624 /* Return the completion status: */
625 return (rval);
626}
627
628int
629_pthread_cond_broadcast(pthread_cond_t * cond)
630{
631 struct pthread *curthread = _get_curthread();
632 struct pthread *pthread;
633 int rval = 0;
634
635 if (cond == NULL)
636 rval = EINVAL;
637 /*
638 * If the condition variable is statically initialized, perform dynamic
639 * initialization.
640 */
641 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
642 /* Lock the condition variable structure: */
643 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
644
645 /* Process according to condition variable type: */
646 switch ((*cond)->c_type) {
647 /* Fast condition variable: */
648 case COND_TYPE_FAST:
649 /* Increment the sequence number: */
650 (*cond)->c_seqno++;
651
652 /*
653 * Enter a loop to bring all threads off the
654 * condition queue:
655 */
656 while ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
657 != NULL) {
658 THR_SCHED_LOCK(curthread, pthread);
659 cond_queue_remove(*cond, pthread);
660 _thr_setrunnable_unlocked(pthread);
661 THR_SCHED_UNLOCK(curthread, pthread);
662 }
663
664 /* There are no more waiting threads: */
665 (*cond)->c_mutex = NULL;
666 break;
667
668 /* Trap invalid condition variable types: */
669 default:
670 /* Return an invalid argument error: */
671 rval = EINVAL;
672 break;
673 }
674
675 /* Unlock the condition variable structure: */
676 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
677 }
678
679 /* Return the completion status: */
680 return (rval);
681}
682
683void
684_cond_wait_backout(struct pthread *curthread)
685{
686 pthread_cond_t cond;
687
688 cond = curthread->data.cond;
689 if (cond != NULL) {
690 /* Lock the condition variable structure: */
691 THR_LOCK_ACQUIRE(curthread, &cond->c_lock);
692
693 /* Process according to condition variable type: */
694 switch (cond->c_type) {
695 /* Fast condition variable: */
696 case COND_TYPE_FAST:
697 cond_queue_remove(cond, curthread);
698
699 /* Check for no more waiters: */
700 if (TAILQ_FIRST(&cond->c_queue) == NULL)
701 cond->c_mutex = NULL;
702 break;
703
704 default:
705 break;
706 }
707
708 /* Unlock the condition variable structure: */
709 THR_LOCK_RELEASE(curthread, &cond->c_lock);
710 }
711}
712
713/*
714 * Dequeue a waiting thread from the head of a condition queue in
715 * descending priority order.
716 */
717static inline struct pthread *
718cond_queue_deq(pthread_cond_t cond)
719{
720 struct pthread *pthread;
721
722 while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
723 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
724 THR_CONDQ_SET(pthread);
725 if ((pthread->timeout == 0) && (pthread->interrupted == 0))
726 /*
727 * Only exit the loop when we find a thread
728 * that hasn't timed out or been canceled;
729 * those threads are already running and don't
730 * need their run state changed.
731 */
732 break;
733 }
734
735 return (pthread);
736}
737
738/*
739 * Remove a waiting thread from a condition queue in descending priority
740 * order.
741 */
742static inline void
743cond_queue_remove(pthread_cond_t cond, struct pthread *pthread)
744{
745 /*
746 * Because pthread_cond_timedwait() can timeout as well
747 * as be signaled by another thread, it is necessary to
748 * guard against removing the thread from the queue if
749 * it isn't in the queue.
750 */
751 if (THR_IN_CONDQ(pthread)) {
752 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
753 THR_CONDQ_CLEAR(pthread);
754 }
755}
756
757/*
758 * Enqueue a waiting thread to a condition queue in descending priority
759 * order.
760 */
761static inline void
762cond_queue_enq(pthread_cond_t cond, struct pthread *pthread)
763{
764 struct pthread *tid = TAILQ_LAST(&cond->c_queue, cond_head);
765
766 THR_ASSERT(!THR_IN_SYNCQ(pthread),
767 "cond_queue_enq: thread already queued!");
768
769 /*
770 * For the common case of all threads having equal priority,
771 * we perform a quick check against the priority of the thread
772 * at the tail of the queue.
773 */
774 if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
775 TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
776 else {
777 tid = TAILQ_FIRST(&cond->c_queue);
778 while (pthread->active_priority <= tid->active_priority)
779 tid = TAILQ_NEXT(tid, sqe);
780 TAILQ_INSERT_BEFORE(tid, pthread, sqe);
781 }
782 THR_CONDQ_SET(pthread);
783 pthread->data.cond = cond;
784}
106 free(pcond);
107 rval = ENOMEM;
108 } else {
109 /*
110 * Initialise the condition variable
111 * structure:
112 */
113 TAILQ_INIT(&pcond->c_queue);
114 pcond->c_flags |= COND_FLAGS_INITED;
115 pcond->c_type = type;
116 pcond->c_mutex = NULL;
117 pcond->c_seqno = 0;
118 *cond = pcond;
119 }
120 }
121 }
122 /* Return the completion status: */
123 return (rval);
124}
125
126int
127_pthread_cond_destroy(pthread_cond_t *cond)
128{
129 struct pthread_cond *cv;
130 struct pthread *curthread = _get_curthread();
131 int rval = 0;
132
133 if (cond == NULL || *cond == NULL)
134 rval = EINVAL;
135 else {
136 /* Lock the condition variable structure: */
137 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
138
139 /*
140 * NULL the caller's pointer now that the condition
141 * variable has been destroyed:
142 */
143 cv = *cond;
144 *cond = NULL;
145
146 /* Unlock the condition variable structure: */
147 THR_LOCK_RELEASE(curthread, &cv->c_lock);
148
149 /*
150 * Free the memory allocated for the condition
151 * variable structure:
152 */
153 free(cv);
154
155 }
156 /* Return the completion status: */
157 return (rval);
158}
159
160int
161_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
162{
163 struct pthread *curthread = _get_curthread();
164 int rval = 0;
165 int done = 0;
166 int interrupted = 0;
167 int unlock_mutex = 1;
168 int seqno;
169
170 _thr_enter_cancellation_point(curthread);
171
172 if (cond == NULL) {
173 _thr_leave_cancellation_point(curthread);
174 return (EINVAL);
175 }
176
177 /*
178 * If the condition variable is statically initialized,
179 * perform the dynamic initialization:
180 */
181 if (*cond == NULL &&
182 (rval = pthread_cond_init(cond, NULL)) != 0) {
183 _thr_leave_cancellation_point(curthread);
184 return (rval);
185 }
186
187 /*
188 * Enter a loop waiting for a condition signal or broadcast
189 * to wake up this thread. A loop is needed in case the waiting
190 * thread is interrupted by a signal to execute a signal handler.
191 * It is not (currently) possible to remain in the waiting queue
192 * while running a handler. Instead, the thread is interrupted
193 * and backed out of the waiting queue prior to executing the
194 * signal handler.
195 */
196 do {
197 /* Lock the condition variable structure: */
198 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
199
200 /*
201 * If the condvar was statically allocated, properly
202 * initialize the tail queue.
203 */
204 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
205 TAILQ_INIT(&(*cond)->c_queue);
206 (*cond)->c_flags |= COND_FLAGS_INITED;
207 }
208
209 /* Process according to condition variable type: */
210 switch ((*cond)->c_type) {
211 /* Fast condition variable: */
212 case COND_TYPE_FAST:
213 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
214 ((*cond)->c_mutex != *mutex))) {
215 /* Unlock the condition variable structure: */
216 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
217
218 /* Return invalid argument error: */
219 rval = EINVAL;
220 } else {
221 /* Reset the timeout and interrupted flags: */
222 curthread->timeout = 0;
223 curthread->interrupted = 0;
224
225 /*
226 * Queue the running thread for the condition
227 * variable:
228 */
229 cond_queue_enq(*cond, curthread);
230
231 /* Remember the mutex and sequence number: */
232 (*cond)->c_mutex = *mutex;
233 seqno = (*cond)->c_seqno;
234
235 /* Wait forever: */
236 curthread->wakeup_time.tv_sec = -1;
237
238 /* Unlock the mutex: */
239 if ((unlock_mutex != 0) &&
240 ((rval = _mutex_cv_unlock(mutex)) != 0)) {
241 /*
242 * Cannot unlock the mutex, so remove
243 * the running thread from the condition
244 * variable queue:
245 */
246 cond_queue_remove(*cond, curthread);
247
248 /* Check for no more waiters: */
249 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
250 (*cond)->c_mutex = NULL;
251
252 /* Unlock the condition variable structure: */
253 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
254 }
255 else {
256 /*
257 * Don't unlock the mutex the next
258 * time through the loop (if the
259 * thread has to be requeued after
260 * handling a signal).
261 */
262 unlock_mutex = 0;
263
264 /*
265 * This thread is active and is in a
266 * critical region (holding the cv
267 * lock); we should be able to safely
268 * set the state.
269 */
270 THR_SET_STATE(curthread, PS_COND_WAIT);
271
272 /* Remember the CV: */
273 curthread->data.cond = *cond;
274
275 /* Unlock the CV structure: */
276 THR_LOCK_RELEASE(curthread,
277 &(*cond)->c_lock);
278
279 /* Schedule the next thread: */
280 _thr_sched_switch(curthread);
281
282 curthread->data.cond = NULL;
283
284 /*
285 * XXX - This really isn't a good check
286 * since there can be more than one
287 * thread waiting on the CV. Signals
288 * sent to threads waiting on mutexes
289 * or CVs should really be deferred
290 * until the threads are no longer
291 * waiting, but POSIX says that signals
292 * should be sent "as soon as possible".
293 */
294 done = (seqno != (*cond)->c_seqno);
295
296 if (THR_IN_SYNCQ(curthread)) {
297 /*
298 * Lock the condition variable
299 * while removing the thread.
300 */
301 THR_LOCK_ACQUIRE(curthread,
302 &(*cond)->c_lock);
303
304 cond_queue_remove(*cond,
305 curthread);
306
307 /* Check for no more waiters: */
308 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
309 (*cond)->c_mutex = NULL;
310
311 THR_LOCK_RELEASE(curthread,
312 &(*cond)->c_lock);
313 }
314
315 /*
316 * Save the interrupted flag; locking
317 * the mutex may destroy it.
318 */
319 interrupted = curthread->interrupted;
320
321 /*
322 * Note that even though this thread may
323 * have been canceled, POSIX requires
324 * that the mutex be reaquired prior to
325 * cancellation.
326 */
327 if (done != 0)
328 rval = _mutex_cv_lock(mutex);
329 }
330 }
331 break;
332
333 /* Trap invalid condition variable types: */
334 default:
335 /* Unlock the condition variable structure: */
336 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
337
338 /* Return an invalid argument error: */
339 rval = EINVAL;
340 break;
341 }
342
343 if ((interrupted != 0) && (curthread->continuation != NULL))
344 curthread->continuation((void *) curthread);
345 } while ((done == 0) && (rval == 0));
346
347 _thr_leave_cancellation_point(curthread);
348
349 /* Return the completion status: */
350 return (rval);
351}
352
353int
354__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
355{
356 struct pthread *curthread = _get_curthread();
357 int ret;
358
359 _thr_enter_cancellation_point(curthread);
360 ret = _pthread_cond_wait(cond, mutex);
361 _thr_leave_cancellation_point(curthread);
362 return (ret);
363}
364
365int
366_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
367 const struct timespec * abstime)
368{
369 struct pthread *curthread = _get_curthread();
370 int rval = 0;
371 int done = 0;
372 int interrupted = 0;
373 int unlock_mutex = 1;
374 int seqno;
375
376 _thr_enter_cancellation_point(curthread);
377
378 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
379 abstime->tv_nsec >= 1000000000) {
380 _thr_leave_cancellation_point(curthread);
381 return (EINVAL);
382 }
383 /*
384 * If the condition variable is statically initialized, perform dynamic
385 * initialization.
386 */
387 if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) {
388 _thr_leave_cancellation_point(curthread);
389 return (rval);
390 }
391
392 /*
393 * Enter a loop waiting for a condition signal or broadcast
394 * to wake up this thread. A loop is needed in case the waiting
395 * thread is interrupted by a signal to execute a signal handler.
396 * It is not (currently) possible to remain in the waiting queue
397 * while running a handler. Instead, the thread is interrupted
398 * and backed out of the waiting queue prior to executing the
399 * signal handler.
400 */
401 do {
402 /* Lock the condition variable structure: */
403 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
404
405 /*
406 * If the condvar was statically allocated, properly
407 * initialize the tail queue.
408 */
409 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
410 TAILQ_INIT(&(*cond)->c_queue);
411 (*cond)->c_flags |= COND_FLAGS_INITED;
412 }
413
414 /* Process according to condition variable type: */
415 switch ((*cond)->c_type) {
416 /* Fast condition variable: */
417 case COND_TYPE_FAST:
418 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
419 ((*cond)->c_mutex != *mutex))) {
420 /* Return invalid argument error: */
421 rval = EINVAL;
422
423 /* Unlock the condition variable structure: */
424 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
425 } else {
426 /* Set the wakeup time: */
427 curthread->wakeup_time.tv_sec = abstime->tv_sec;
428 curthread->wakeup_time.tv_nsec =
429 abstime->tv_nsec;
430
431 /* Reset the timeout and interrupted flags: */
432 curthread->timeout = 0;
433 curthread->interrupted = 0;
434
435 /*
436 * Queue the running thread for the condition
437 * variable:
438 */
439 cond_queue_enq(*cond, curthread);
440
441 /* Remember the mutex and sequence number: */
442 (*cond)->c_mutex = *mutex;
443 seqno = (*cond)->c_seqno;
444
445 /* Unlock the mutex: */
446 if ((unlock_mutex != 0) &&
447 ((rval = _mutex_cv_unlock(mutex)) != 0)) {
448 /*
449 * Cannot unlock the mutex; remove the
450 * running thread from the condition
451 * variable queue:
452 */
453 cond_queue_remove(*cond, curthread);
454
455 /* Check for no more waiters: */
456 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
457 (*cond)->c_mutex = NULL;
458
459 /* Unlock the condition variable structure: */
460 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
461 } else {
462 /*
463 * Don't unlock the mutex the next
464 * time through the loop (if the
465 * thread has to be requeued after
466 * handling a signal).
467 */
468 unlock_mutex = 0;
469
470 /*
471 * This thread is active and is in a
472 * critical region (holding the cv
473 * lock); we should be able to safely
474 * set the state.
475 */
476 THR_SET_STATE(curthread, PS_COND_WAIT);
477
478 /* Remember the CV: */
479 curthread->data.cond = *cond;
480
481 /* Unlock the CV structure: */
482 THR_LOCK_RELEASE(curthread,
483 &(*cond)->c_lock);
484
485 /* Schedule the next thread: */
486 _thr_sched_switch(curthread);
487
488 curthread->data.cond = NULL;
489
490 /*
491 * XXX - This really isn't a good check
492 * since there can be more than one
493 * thread waiting on the CV. Signals
494 * sent to threads waiting on mutexes
495 * or CVs should really be deferred
496 * until the threads are no longer
497 * waiting, but POSIX says that signals
498 * should be sent "as soon as possible".
499 */
500 done = (seqno != (*cond)->c_seqno);
501
502 if (THR_IN_CONDQ(curthread)) {
503 /*
504 * Lock the condition variable
505 * while removing the thread.
506 */
507 THR_LOCK_ACQUIRE(curthread,
508 &(*cond)->c_lock);
509
510 cond_queue_remove(*cond,
511 curthread);
512
513 /* Check for no more waiters: */
514 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
515 (*cond)->c_mutex = NULL;
516
517 THR_LOCK_RELEASE(curthread,
518 &(*cond)->c_lock);
519 }
520
521 /*
522 * Save the interrupted flag; locking
523 * the mutex may destroy it.
524 */
525 interrupted = curthread->interrupted;
526 if (curthread->timeout != 0) {
527 /* The wait timedout. */
528 rval = ETIMEDOUT;
529 (void)_mutex_cv_lock(mutex);
530 } else if ((interrupted == 0) ||
531 (done != 0))
532 rval = _mutex_cv_lock(mutex);
533 }
534 }
535 break;
536
537 /* Trap invalid condition variable types: */
538 default:
539 /* Unlock the condition variable structure: */
540 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
541
542 /* Return an invalid argument error: */
543 rval = EINVAL;
544 break;
545 }
546
547 if ((interrupted != 0) && (curthread->continuation != NULL))
548 curthread->continuation((void *)curthread);
549 } while ((done == 0) && (rval == 0));
550
551 _thr_leave_cancellation_point(curthread);
552
553 /* Return the completion status: */
554 return (rval);
555}
556
557int
558__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
559 const struct timespec *abstime)
560{
561 struct pthread *curthread = _get_curthread();
562 int ret;
563
564 _thr_enter_cancellation_point(curthread);
565 ret = _pthread_cond_timedwait(cond, mutex, abstime);
566 _thr_leave_cancellation_point(curthread);
567 return (ret);
568}
569
570
571int
572_pthread_cond_signal(pthread_cond_t * cond)
573{
574 struct pthread *curthread = _get_curthread();
575 struct pthread *pthread;
576 int rval = 0;
577
578 if (cond == NULL)
579 rval = EINVAL;
580 /*
581 * If the condition variable is statically initialized, perform dynamic
582 * initialization.
583 */
584 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
585 /* Lock the condition variable structure: */
586 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
587
588 /* Process according to condition variable type: */
589 switch ((*cond)->c_type) {
590 /* Fast condition variable: */
591 case COND_TYPE_FAST:
592 /* Increment the sequence number: */
593 (*cond)->c_seqno++;
594
595 /*
596 * Wakeups have to be done with the CV lock held;
597 * otherwise there is a race condition where the
598 * thread can timeout, run on another KSE, and enter
599 * another blocking state (including blocking on a CV).
600 */
601 if ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
602 != NULL) {
603 THR_SCHED_LOCK(curthread, pthread);
604 cond_queue_remove(*cond, pthread);
605 _thr_setrunnable_unlocked(pthread);
606 THR_SCHED_UNLOCK(curthread, pthread);
607 }
608 /* Check for no more waiters: */
609 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
610 (*cond)->c_mutex = NULL;
611 break;
612
613 /* Trap invalid condition variable types: */
614 default:
615 /* Return an invalid argument error: */
616 rval = EINVAL;
617 break;
618 }
619
620 /* Unlock the condition variable structure: */
621 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
622 }
623
624 /* Return the completion status: */
625 return (rval);
626}
627
628int
629_pthread_cond_broadcast(pthread_cond_t * cond)
630{
631 struct pthread *curthread = _get_curthread();
632 struct pthread *pthread;
633 int rval = 0;
634
635 if (cond == NULL)
636 rval = EINVAL;
637 /*
638 * If the condition variable is statically initialized, perform dynamic
639 * initialization.
640 */
641 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
642 /* Lock the condition variable structure: */
643 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
644
645 /* Process according to condition variable type: */
646 switch ((*cond)->c_type) {
647 /* Fast condition variable: */
648 case COND_TYPE_FAST:
649 /* Increment the sequence number: */
650 (*cond)->c_seqno++;
651
652 /*
653 * Enter a loop to bring all threads off the
654 * condition queue:
655 */
656 while ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
657 != NULL) {
658 THR_SCHED_LOCK(curthread, pthread);
659 cond_queue_remove(*cond, pthread);
660 _thr_setrunnable_unlocked(pthread);
661 THR_SCHED_UNLOCK(curthread, pthread);
662 }
663
664 /* There are no more waiting threads: */
665 (*cond)->c_mutex = NULL;
666 break;
667
668 /* Trap invalid condition variable types: */
669 default:
670 /* Return an invalid argument error: */
671 rval = EINVAL;
672 break;
673 }
674
675 /* Unlock the condition variable structure: */
676 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
677 }
678
679 /* Return the completion status: */
680 return (rval);
681}
682
683void
684_cond_wait_backout(struct pthread *curthread)
685{
686 pthread_cond_t cond;
687
688 cond = curthread->data.cond;
689 if (cond != NULL) {
690 /* Lock the condition variable structure: */
691 THR_LOCK_ACQUIRE(curthread, &cond->c_lock);
692
693 /* Process according to condition variable type: */
694 switch (cond->c_type) {
695 /* Fast condition variable: */
696 case COND_TYPE_FAST:
697 cond_queue_remove(cond, curthread);
698
699 /* Check for no more waiters: */
700 if (TAILQ_FIRST(&cond->c_queue) == NULL)
701 cond->c_mutex = NULL;
702 break;
703
704 default:
705 break;
706 }
707
708 /* Unlock the condition variable structure: */
709 THR_LOCK_RELEASE(curthread, &cond->c_lock);
710 }
711}
712
713/*
714 * Dequeue a waiting thread from the head of a condition queue in
715 * descending priority order.
716 */
717static inline struct pthread *
718cond_queue_deq(pthread_cond_t cond)
719{
720 struct pthread *pthread;
721
722 while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
723 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
724 THR_CONDQ_SET(pthread);
725 if ((pthread->timeout == 0) && (pthread->interrupted == 0))
726 /*
727 * Only exit the loop when we find a thread
728 * that hasn't timed out or been canceled;
729 * those threads are already running and don't
730 * need their run state changed.
731 */
732 break;
733 }
734
735 return (pthread);
736}
737
738/*
739 * Remove a waiting thread from a condition queue in descending priority
740 * order.
741 */
742static inline void
743cond_queue_remove(pthread_cond_t cond, struct pthread *pthread)
744{
745 /*
746 * Because pthread_cond_timedwait() can timeout as well
747 * as be signaled by another thread, it is necessary to
748 * guard against removing the thread from the queue if
749 * it isn't in the queue.
750 */
751 if (THR_IN_CONDQ(pthread)) {
752 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
753 THR_CONDQ_CLEAR(pthread);
754 }
755}
756
757/*
758 * Enqueue a waiting thread to a condition queue in descending priority
759 * order.
760 */
761static inline void
762cond_queue_enq(pthread_cond_t cond, struct pthread *pthread)
763{
764 struct pthread *tid = TAILQ_LAST(&cond->c_queue, cond_head);
765
766 THR_ASSERT(!THR_IN_SYNCQ(pthread),
767 "cond_queue_enq: thread already queued!");
768
769 /*
770 * For the common case of all threads having equal priority,
771 * we perform a quick check against the priority of the thread
772 * at the tail of the queue.
773 */
774 if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
775 TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
776 else {
777 tid = TAILQ_FIRST(&cond->c_queue);
778 while (pthread->active_priority <= tid->active_priority)
779 tid = TAILQ_NEXT(tid, sqe);
780 TAILQ_INSERT_BEFORE(tid, pthread, sqe);
781 }
782 THR_CONDQ_SET(pthread);
783 pthread->data.cond = cond;
784}