2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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. Neither the name of the author nor the names of any co-contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "namespace.h"
36 #include "un-namespace.h"
37 #include "pthread_private.h"
42 static inline pthread_t cond_queue_deq(pthread_cond_t);
43 static inline void cond_queue_remove(pthread_cond_t, pthread_t);
44 static inline void cond_queue_enq(pthread_cond_t, pthread_t);
45 int __pthread_cond_timedwait(pthread_cond_t *,
46 pthread_mutex_t *, const struct timespec *);
47 int __pthread_cond_wait(pthread_cond_t *,
52 * Double underscore versions are cancellation points. Single underscore
53 * versions are not and are provided for libc internal usage (which
54 * shouldn't introduce cancellation points).
56 __weak_reference(__pthread_cond_wait, pthread_cond_wait);
57 __weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
59 __weak_reference(_pthread_cond_init, pthread_cond_init);
60 __weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
61 __weak_reference(_pthread_cond_signal, pthread_cond_signal);
62 __weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
66 * Reinitialize a private condition variable; this is only used for
67 * internal condition variables. Currently, there is no difference.
70 _cond_reinit(pthread_cond_t *cond)
76 else if (*cond == NULL)
77 ret = _pthread_cond_init(cond, NULL);
80 * Initialize the condition variable structure:
82 TAILQ_INIT(&(*cond)->c_queue);
83 (*cond)->c_flags = COND_FLAGS_INITED;
84 (*cond)->c_type = COND_TYPE_FAST;
85 (*cond)->c_mutex = NULL;
87 memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
93 _pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
95 enum pthread_cond_type type;
103 * Check if a pointer to a condition variable attribute
104 * structure was passed by the caller:
106 if (cond_attr != NULL && *cond_attr != NULL) {
107 /* Default to a fast condition variable: */
108 type = (*cond_attr)->c_type;
110 /* Default to a fast condition variable: */
111 type = COND_TYPE_FAST;
114 /* Process according to condition variable type: */
116 /* Fast condition variable: */
118 /* Nothing to do here. */
121 /* Trap invalid condition variable types: */
123 /* Return an invalid argument error: */
128 /* Check for no errors: */
130 if ((pcond = (pthread_cond_t)
131 malloc(sizeof(struct pthread_cond))) == NULL) {
135 * Initialise the condition variable
138 TAILQ_INIT(&pcond->c_queue);
139 pcond->c_flags |= COND_FLAGS_INITED;
140 pcond->c_type = type;
141 pcond->c_mutex = NULL;
143 memset(&pcond->lock,0,sizeof(pcond->lock));
148 /* Return the completion status: */
153 _pthread_cond_destroy(pthread_cond_t *cond)
157 if (cond == NULL || *cond == NULL)
160 /* Lock the condition variable structure: */
161 _SPINLOCK(&(*cond)->lock);
164 * Free the memory allocated for the condition
165 * variable structure:
170 * NULL the caller's pointer now that the condition
171 * variable has been destroyed:
175 /* Return the completion status: */
180 _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
182 struct pthread *curthread = _get_curthread();
192 * If the condition variable is statically initialized,
193 * perform the dynamic initialization:
196 (rval = _pthread_cond_init(cond, NULL)) != 0)
200 * Enter a loop waiting for a condition signal or broadcast
201 * to wake up this thread. A loop is needed in case the waiting
202 * thread is interrupted by a signal to execute a signal handler.
203 * It is not (currently) possible to remain in the waiting queue
204 * while running a handler. Instead, the thread is interrupted
205 * and backed out of the waiting queue prior to executing the
209 /* Lock the condition variable structure: */
210 _SPINLOCK(&(*cond)->lock);
213 * If the condvar was statically allocated, properly
214 * initialize the tail queue.
216 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
217 TAILQ_INIT(&(*cond)->c_queue);
218 (*cond)->c_flags |= COND_FLAGS_INITED;
221 /* Process according to condition variable type: */
222 switch ((*cond)->c_type) {
223 /* Fast condition variable: */
225 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
226 ((*cond)->c_mutex != *mutex))) {
227 /* Unlock the condition variable structure: */
228 _SPINUNLOCK(&(*cond)->lock);
230 /* Return invalid argument error: */
233 /* Reset the timeout and interrupted flags: */
234 curthread->timeout = 0;
235 curthread->interrupted = 0;
238 * Queue the running thread for the condition
241 cond_queue_enq(*cond, curthread);
243 /* Remember the mutex and sequence number: */
244 (*cond)->c_mutex = *mutex;
245 seqno = (*cond)->c_seqno;
248 curthread->wakeup_time.tv_sec = -1;
250 /* Unlock the mutex: */
251 if ((rval = _mutex_cv_unlock(mutex)) != 0) {
253 * Cannot unlock the mutex, so remove
254 * the running thread from the condition
257 cond_queue_remove(*cond, curthread);
259 /* Check for no more waiters: */
260 if (TAILQ_FIRST(&(*cond)->c_queue) ==
262 (*cond)->c_mutex = NULL;
264 /* Unlock the condition variable structure: */
265 _SPINUNLOCK(&(*cond)->lock);
268 * Schedule the next thread and unlock
269 * the condition variable structure:
271 _thread_kern_sched_state_unlock(PS_COND_WAIT,
272 &(*cond)->lock, __FILE__, __LINE__);
274 done = (seqno != (*cond)->c_seqno);
276 interrupted = curthread->interrupted;
279 * Check if the wait was interrupted
280 * (canceled) or needs to be resumed
281 * after handling a signal.
283 if (interrupted != 0) {
285 * Lock the mutex and ignore any
286 * errors. Note that even
287 * though this thread may have
288 * been canceled, POSIX requires
289 * that the mutex be reaquired
290 * prior to cancellation.
292 (void)_mutex_cv_lock(mutex);
295 * Lock the condition variable
296 * while removing the thread.
298 _SPINLOCK(&(*cond)->lock);
300 cond_queue_remove(*cond,
303 /* Check for no more waiters: */
304 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
305 (*cond)->c_mutex = NULL;
307 _SPINUNLOCK(&(*cond)->lock);
309 /* Lock the mutex: */
310 rval = _mutex_cv_lock(mutex);
316 /* Trap invalid condition variable types: */
318 /* Unlock the condition variable structure: */
319 _SPINUNLOCK(&(*cond)->lock);
321 /* Return an invalid argument error: */
326 if ((interrupted != 0) && (curthread->continuation != NULL))
327 curthread->continuation((void *) curthread);
328 } while ((done == 0) && (rval == 0));
330 /* Return the completion status: */
335 __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
339 _thread_enter_cancellation_point();
340 ret = _pthread_cond_wait(cond, mutex);
341 _thread_leave_cancellation_point();
346 _pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
347 const struct timespec *abstime)
349 struct pthread *curthread = _get_curthread();
355 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
356 abstime->tv_nsec >= 1000000000)
359 * If the condition variable is statically initialized, perform dynamic
362 if (*cond == NULL && (rval = _pthread_cond_init(cond, NULL)) != 0)
366 * Enter a loop waiting for a condition signal or broadcast
367 * to wake up this thread. A loop is needed in case the waiting
368 * thread is interrupted by a signal to execute a signal handler.
369 * It is not (currently) possible to remain in the waiting queue
370 * while running a handler. Instead, the thread is interrupted
371 * and backed out of the waiting queue prior to executing the
375 /* Lock the condition variable structure: */
376 _SPINLOCK(&(*cond)->lock);
379 * If the condvar was statically allocated, properly
380 * initialize the tail queue.
382 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
383 TAILQ_INIT(&(*cond)->c_queue);
384 (*cond)->c_flags |= COND_FLAGS_INITED;
387 /* Process according to condition variable type: */
388 switch ((*cond)->c_type) {
389 /* Fast condition variable: */
391 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
392 ((*cond)->c_mutex != *mutex))) {
393 /* Return invalid argument error: */
396 /* Unlock the condition variable structure: */
397 _SPINUNLOCK(&(*cond)->lock);
399 /* Set the wakeup time: */
400 curthread->wakeup_time.tv_sec =
402 curthread->wakeup_time.tv_nsec =
405 /* Reset the timeout and interrupted flags: */
406 curthread->timeout = 0;
407 curthread->interrupted = 0;
410 * Queue the running thread for the condition
413 cond_queue_enq(*cond, curthread);
415 /* Remember the mutex and sequence number: */
416 (*cond)->c_mutex = *mutex;
417 seqno = (*cond)->c_seqno;
419 /* Unlock the mutex: */
420 if ((rval = _mutex_cv_unlock(mutex)) != 0) {
422 * Cannot unlock the mutex, so remove
423 * the running thread from the condition
426 cond_queue_remove(*cond, curthread);
428 /* Check for no more waiters: */
429 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
430 (*cond)->c_mutex = NULL;
432 /* Unlock the condition variable structure: */
433 _SPINUNLOCK(&(*cond)->lock);
436 * Schedule the next thread and unlock
437 * the condition variable structure:
439 _thread_kern_sched_state_unlock(PS_COND_WAIT,
440 &(*cond)->lock, __FILE__, __LINE__);
442 done = (seqno != (*cond)->c_seqno);
444 interrupted = curthread->interrupted;
447 * Check if the wait was interrupted
448 * (canceled) or needs to be resumed
449 * after handling a signal.
451 if (interrupted != 0) {
453 * Lock the mutex and ignore any
454 * errors. Note that even
455 * though this thread may have
456 * been canceled, POSIX requires
457 * that the mutex be reaquired
458 * prior to cancellation.
460 (void)_mutex_cv_lock(mutex);
463 * Lock the condition variable
464 * while removing the thread.
466 _SPINLOCK(&(*cond)->lock);
468 cond_queue_remove(*cond,
471 /* Check for no more waiters: */
472 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
473 (*cond)->c_mutex = NULL;
475 _SPINUNLOCK(&(*cond)->lock);
477 /* Lock the mutex: */
478 rval = _mutex_cv_lock(mutex);
481 * Return ETIMEDOUT if the wait
482 * timed out and there wasn't an
483 * error locking the mutex:
485 if ((curthread->timeout != 0)
494 /* Trap invalid condition variable types: */
496 /* Unlock the condition variable structure: */
497 _SPINUNLOCK(&(*cond)->lock);
499 /* Return an invalid argument error: */
504 if ((interrupted != 0) && (curthread->continuation != NULL))
505 curthread->continuation((void *) curthread);
506 } while ((done == 0) && (rval == 0));
508 /* Return the completion status: */
513 __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
514 const struct timespec *abstime)
518 _thread_enter_cancellation_point();
519 ret = _pthread_cond_timedwait(cond, mutex, abstime);
520 _thread_enter_cancellation_point();
525 _pthread_cond_signal(pthread_cond_t *cond)
533 * If the condition variable is statically initialized, perform dynamic
536 else if (*cond != NULL ||
537 (rval = _pthread_cond_init(cond, NULL)) == 0) {
539 * Defer signals to protect the scheduling queues
540 * from access by the signal handler:
542 _thread_kern_sig_defer();
544 /* Lock the condition variable structure: */
545 _SPINLOCK(&(*cond)->lock);
547 /* Process according to condition variable type: */
548 switch ((*cond)->c_type) {
549 /* Fast condition variable: */
551 /* Increment the sequence number: */
554 if ((pthread = cond_queue_deq(*cond)) != NULL) {
556 * Wake up the signaled thread:
558 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
561 /* Check for no more waiters: */
562 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
563 (*cond)->c_mutex = NULL;
566 /* Trap invalid condition variable types: */
568 /* Return an invalid argument error: */
573 /* Unlock the condition variable structure: */
574 _SPINUNLOCK(&(*cond)->lock);
577 * Undefer and handle pending signals, yielding if
580 _thread_kern_sig_undefer();
583 /* Return the completion status: */
588 _pthread_cond_broadcast(pthread_cond_t *cond)
596 * If the condition variable is statically initialized, perform dynamic
599 else if (*cond != NULL ||
600 (rval = _pthread_cond_init(cond, NULL)) == 0) {
602 * Defer signals to protect the scheduling queues
603 * from access by the signal handler:
605 _thread_kern_sig_defer();
607 /* Lock the condition variable structure: */
608 _SPINLOCK(&(*cond)->lock);
610 /* Process according to condition variable type: */
611 switch ((*cond)->c_type) {
612 /* Fast condition variable: */
614 /* Increment the sequence number: */
618 * Enter a loop to bring all threads off the
621 while ((pthread = cond_queue_deq(*cond)) != NULL) {
623 * Wake up the signaled thread:
625 PTHREAD_NEW_STATE(pthread, PS_RUNNING);
628 /* There are no more waiting threads: */
629 (*cond)->c_mutex = NULL;
632 /* Trap invalid condition variable types: */
634 /* Return an invalid argument error: */
639 /* Unlock the condition variable structure: */
640 _SPINUNLOCK(&(*cond)->lock);
643 * Undefer and handle pending signals, yielding if
646 _thread_kern_sig_undefer();
649 /* Return the completion status: */
654 _cond_wait_backout(pthread_t pthread)
658 cond = pthread->data.cond;
661 * Defer signals to protect the scheduling queues
662 * from access by the signal handler:
664 _thread_kern_sig_defer();
666 /* Lock the condition variable structure: */
667 _SPINLOCK(&cond->lock);
669 /* Process according to condition variable type: */
670 switch (cond->c_type) {
671 /* Fast condition variable: */
673 cond_queue_remove(cond, pthread);
675 /* Check for no more waiters: */
676 if (TAILQ_FIRST(&cond->c_queue) == NULL)
677 cond->c_mutex = NULL;
684 /* Unlock the condition variable structure: */
685 _SPINUNLOCK(&cond->lock);
688 * Undefer and handle pending signals, yielding if
691 _thread_kern_sig_undefer();
696 * Dequeue a waiting thread from the head of a condition queue in
697 * descending priority order.
699 static inline pthread_t
700 cond_queue_deq(pthread_cond_t cond)
704 while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
705 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
706 pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
707 if ((pthread->timeout == 0) && (pthread->interrupted == 0))
709 * Only exit the loop when we find a thread
710 * that hasn't timed out or been canceled;
711 * those threads are already running and don't
712 * need their run state changed.
721 * Remove a waiting thread from a condition queue in descending priority
725 cond_queue_remove(pthread_cond_t cond, pthread_t pthread)
728 * Because pthread_cond_timedwait() can timeout as well
729 * as be signaled by another thread, it is necessary to
730 * guard against removing the thread from the queue if
731 * it isn't in the queue.
733 if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
734 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
735 pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
740 * Enqueue a waiting thread to a condition queue in descending priority
744 cond_queue_enq(pthread_cond_t cond, pthread_t pthread)
746 pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head);
748 PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
751 * For the common case of all threads having equal priority,
752 * we perform a quick check against the priority of the thread
753 * at the tail of the queue.
755 if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
756 TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
758 tid = TAILQ_FIRST(&cond->c_queue);
759 while (pthread->active_priority <= tid->active_priority)
760 tid = TAILQ_NEXT(tid, sqe);
761 TAILQ_INSERT_BEFORE(tid, pthread, sqe);
763 pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
764 pthread->data.cond = cond;