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. 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.
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
38 #include "thr_private.h"
40 #define THR_IN_CONDQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
41 #define THR_CONDQ_SET(thr) (thr)->sflags |= THR_FLAGS_IN_SYNCQ
42 #define THR_CONDQ_CLEAR(thr) (thr)->sflags &= ~THR_FLAGS_IN_SYNCQ
47 static inline struct pthread *cond_queue_deq(pthread_cond_t);
48 static inline void cond_queue_remove(pthread_cond_t, pthread_t);
49 static inline void cond_queue_enq(pthread_cond_t, pthread_t);
50 static void cond_wait_backout(void *);
51 static inline void check_continuation(struct pthread *,
52 struct pthread_cond *, pthread_mutex_t *);
55 * Double underscore versions are cancellation points. Single underscore
56 * versions are not and are provided for libc internal usage (which
57 * shouldn't introduce cancellation points).
59 __weak_reference(__pthread_cond_wait, pthread_cond_wait);
60 __weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
62 __weak_reference(_pthread_cond_init, pthread_cond_init);
63 __weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
64 __weak_reference(_pthread_cond_signal, pthread_cond_signal);
65 __weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
69 _pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
71 enum pthread_cond_type type;
80 * Check if a pointer to a condition variable attribute
81 * structure was passed by the caller:
83 if (cond_attr != NULL && *cond_attr != NULL) {
84 /* Default to a fast condition variable: */
85 type = (*cond_attr)->c_type;
86 flags = (*cond_attr)->c_flags;
88 /* Default to a fast condition variable: */
89 type = COND_TYPE_FAST;
93 /* Process according to condition variable type: */
95 /* Fast condition variable: */
97 /* Nothing to do here. */
100 /* Trap invalid condition variable types: */
102 /* Return an invalid argument error: */
107 /* Check for no errors: */
109 if ((pcond = (pthread_cond_t)
110 malloc(sizeof(struct pthread_cond))) == NULL) {
112 } else if (_lock_init(&pcond->c_lock, LCK_ADAPTIVE,
113 _thr_lock_wait, _thr_lock_wakeup) != 0) {
118 * Initialise the condition variable
121 TAILQ_INIT(&pcond->c_queue);
122 pcond->c_flags = COND_FLAGS_INITED;
123 pcond->c_type = type;
124 pcond->c_mutex = NULL;
130 /* Return the completion status: */
135 _pthread_cond_destroy(pthread_cond_t *cond)
137 struct pthread_cond *cv;
138 struct pthread *curthread = _get_curthread();
141 if (cond == NULL || *cond == NULL)
144 /* Lock the condition variable structure: */
145 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
148 * NULL the caller's pointer now that the condition
149 * variable has been destroyed:
154 /* Unlock the condition variable structure: */
155 THR_LOCK_RELEASE(curthread, &cv->c_lock);
157 /* Free the cond lock structure: */
158 _lock_destroy(&cv->c_lock);
161 * Free the memory allocated for the condition
162 * variable structure:
167 /* Return the completion status: */
172 _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
174 struct pthread *curthread = _get_curthread();
177 int mutex_locked = 1;
184 * If the condition variable is statically initialized,
185 * perform the dynamic initialization:
188 (rval = pthread_cond_init(cond, NULL)) != 0)
191 if (!_kse_isthreaded())
195 * Enter a loop waiting for a condition signal or broadcast
196 * to wake up this thread. A loop is needed in case the waiting
197 * thread is interrupted by a signal to execute a signal handler.
198 * It is not (currently) possible to remain in the waiting queue
199 * while running a handler. Instead, the thread is interrupted
200 * and backed out of the waiting queue prior to executing the
204 /* Lock the condition variable structure: */
205 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
206 seqno = (*cond)->c_seqno;
209 * If the condvar was statically allocated, properly
210 * initialize the tail queue.
212 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
213 TAILQ_INIT(&(*cond)->c_queue);
214 (*cond)->c_flags |= COND_FLAGS_INITED;
217 /* Process according to condition variable type: */
218 switch ((*cond)->c_type) {
219 /* Fast condition variable: */
221 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
222 ((*cond)->c_mutex != *mutex))) {
223 /* Return invalid argument error: */
226 /* Reset the timeout and interrupted flags: */
227 curthread->timeout = 0;
228 curthread->interrupted = 0;
231 * Queue the running thread for the condition
234 cond_queue_enq(*cond, curthread);
237 curthread->wakeup_time.tv_sec = -1;
239 /* Unlock the mutex: */
241 ((rval = _mutex_cv_unlock(mutex)) != 0)) {
243 * Cannot unlock the mutex, so remove
244 * the running thread from the condition
247 cond_queue_remove(*cond, curthread);
250 /* Remember the mutex: */
251 (*cond)->c_mutex = *mutex;
254 * Don't unlock the mutex the next
255 * time through the loop (if the
256 * thread has to be requeued after
257 * handling a signal).
262 * This thread is active and is in a
263 * critical region (holding the cv
264 * lock); we should be able to safely
267 THR_SCHED_LOCK(curthread, curthread);
268 THR_SET_STATE(curthread, PS_COND_WAIT);
270 /* Remember the CV: */
271 curthread->data.cond = *cond;
272 curthread->sigbackout = cond_wait_backout;
273 THR_SCHED_UNLOCK(curthread, curthread);
275 /* Unlock the CV structure: */
276 THR_LOCK_RELEASE(curthread,
279 /* Schedule the next thread: */
280 _thr_sched_switch(curthread);
283 * XXX - This really isn't a good check
284 * since there can be more than one
285 * thread waiting on the CV. Signals
286 * sent to threads waiting on mutexes
287 * or CVs should really be deferred
288 * until the threads are no longer
289 * waiting, but POSIX says that signals
290 * should be sent "as soon as possible".
292 done = (seqno != (*cond)->c_seqno);
293 if (done && !THR_IN_CONDQ(curthread)) {
295 * The thread is dequeued, so
296 * it is safe to clear these.
298 curthread->data.cond = NULL;
299 curthread->sigbackout = NULL;
300 check_continuation(curthread,
302 return (_mutex_cv_lock(mutex));
305 /* Relock the CV structure: */
306 THR_LOCK_ACQUIRE(curthread,
310 * Clear these after taking the lock to
311 * prevent a race condition where a
312 * signal can arrive before dequeueing
315 curthread->data.cond = NULL;
316 curthread->sigbackout = NULL;
317 done = (seqno != (*cond)->c_seqno);
319 if (THR_IN_CONDQ(curthread)) {
320 cond_queue_remove(*cond,
323 /* Check for no more waiters: */
324 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
325 (*cond)->c_mutex = NULL;
331 /* Trap invalid condition variable types: */
333 /* Return an invalid argument error: */
338 check_continuation(curthread, *cond,
339 mutex_locked ? NULL : mutex);
340 } while ((done == 0) && (rval == 0));
342 /* Unlock the condition variable structure: */
343 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
345 if (mutex_locked == 0)
346 _mutex_cv_lock(mutex);
348 /* Return the completion status: */
352 __strong_reference(_pthread_cond_wait, _thr_cond_wait);
355 __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
357 struct pthread *curthread = _get_curthread();
360 _thr_cancel_enter(curthread);
361 ret = _pthread_cond_wait(cond, mutex);
362 _thr_cancel_leave(curthread, 1);
367 _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
368 const struct timespec * abstime)
370 struct pthread *curthread = _get_curthread();
373 int mutex_locked = 1;
376 THR_ASSERT(curthread->locklevel == 0,
377 "cv_timedwait: locklevel is not zero!");
379 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
380 abstime->tv_nsec >= 1000000000)
383 * If the condition variable is statically initialized, perform dynamic
386 if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
389 if (!_kse_isthreaded())
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
402 /* Lock the condition variable structure: */
403 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
404 seqno = (*cond)->c_seqno;
407 * If the condvar was statically allocated, properly
408 * initialize the tail queue.
410 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
411 TAILQ_INIT(&(*cond)->c_queue);
412 (*cond)->c_flags |= COND_FLAGS_INITED;
415 /* Process according to condition variable type: */
416 switch ((*cond)->c_type) {
417 /* Fast condition variable: */
419 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
420 ((*cond)->c_mutex != *mutex))) {
421 /* Return invalid argument error: */
424 /* Set the wakeup time: */
425 curthread->wakeup_time.tv_sec = abstime->tv_sec;
426 curthread->wakeup_time.tv_nsec =
429 /* Reset the timeout and interrupted flags: */
430 curthread->timeout = 0;
431 curthread->interrupted = 0;
434 * Queue the running thread for the condition
437 cond_queue_enq(*cond, curthread);
439 /* Unlock the mutex: */
441 ((rval = _mutex_cv_unlock(mutex)) != 0)) {
443 * Cannot unlock the mutex; remove the
444 * running thread from the condition
447 cond_queue_remove(*cond, curthread);
449 /* Remember the mutex: */
450 (*cond)->c_mutex = *mutex;
453 * Don't unlock the mutex the next
454 * time through the loop (if the
455 * thread has to be requeued after
456 * handling a signal).
461 * This thread is active and is in a
462 * critical region (holding the cv
463 * lock); we should be able to safely
466 THR_SCHED_LOCK(curthread, curthread);
467 THR_SET_STATE(curthread, PS_COND_WAIT);
469 /* Remember the CV: */
470 curthread->data.cond = *cond;
471 curthread->sigbackout = cond_wait_backout;
472 THR_SCHED_UNLOCK(curthread, curthread);
474 /* Unlock the CV structure: */
475 THR_LOCK_RELEASE(curthread,
478 /* Schedule the next thread: */
479 _thr_sched_switch(curthread);
482 * XXX - This really isn't a good check
483 * since there can be more than one
484 * thread waiting on the CV. Signals
485 * sent to threads waiting on mutexes
486 * or CVs should really be deferred
487 * until the threads are no longer
488 * waiting, but POSIX says that signals
489 * should be sent "as soon as possible".
491 done = (seqno != (*cond)->c_seqno);
492 if (done && !THR_IN_CONDQ(curthread)) {
494 * The thread is dequeued, so
495 * it is safe to clear these.
497 curthread->data.cond = NULL;
498 curthread->sigbackout = NULL;
499 check_continuation(curthread,
501 return (_mutex_cv_lock(mutex));
504 /* Relock the CV structure: */
505 THR_LOCK_ACQUIRE(curthread,
509 * Clear these after taking the lock to
510 * prevent a race condition where a
511 * signal can arrive before dequeueing
514 curthread->data.cond = NULL;
515 curthread->sigbackout = NULL;
517 done = (seqno != (*cond)->c_seqno);
519 if (THR_IN_CONDQ(curthread)) {
520 cond_queue_remove(*cond,
523 /* Check for no more waiters: */
524 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
525 (*cond)->c_mutex = NULL;
528 if (curthread->timeout != 0) {
529 /* The wait timedout. */
536 /* Trap invalid condition variable types: */
538 /* Return an invalid argument error: */
543 check_continuation(curthread, *cond,
544 mutex_locked ? NULL : mutex);
545 } while ((done == 0) && (rval == 0));
547 /* Unlock the condition variable structure: */
548 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
550 if (mutex_locked == 0)
551 _mutex_cv_lock(mutex);
553 /* Return the completion status: */
558 __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
559 const struct timespec *abstime)
561 struct pthread *curthread = _get_curthread();
564 _thr_cancel_enter(curthread);
565 ret = _pthread_cond_timedwait(cond, mutex, abstime);
566 _thr_cancel_leave(curthread, 1);
572 _pthread_cond_signal(pthread_cond_t * cond)
574 struct pthread *curthread = _get_curthread();
575 struct pthread *pthread;
576 struct kse_mailbox *kmbx;
579 THR_ASSERT(curthread->locklevel == 0,
580 "cv_timedwait: locklevel is not zero!");
584 * If the condition variable is statically initialized, perform dynamic
587 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
588 /* Lock the condition variable structure: */
589 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
591 /* Process according to condition variable type: */
592 switch ((*cond)->c_type) {
593 /* Fast condition variable: */
595 /* Increment the sequence number: */
599 * Wakeups have to be done with the CV lock held;
600 * otherwise there is a race condition where the
601 * thread can timeout, run on another KSE, and enter
602 * another blocking state (including blocking on a CV).
604 if ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
606 THR_SCHED_LOCK(curthread, pthread);
607 cond_queue_remove(*cond, pthread);
608 pthread->sigbackout = NULL;
609 if ((pthread->kseg == curthread->kseg) &&
610 (pthread->active_priority >
611 curthread->active_priority))
612 curthread->critical_yield = 1;
613 kmbx = _thr_setrunnable_unlocked(pthread);
614 THR_SCHED_UNLOCK(curthread, pthread);
618 /* Check for no more waiters: */
619 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
620 (*cond)->c_mutex = NULL;
623 /* Trap invalid condition variable types: */
625 /* Return an invalid argument error: */
630 /* Unlock the condition variable structure: */
631 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
634 /* Return the completion status: */
638 __strong_reference(_pthread_cond_signal, _thr_cond_signal);
641 _pthread_cond_broadcast(pthread_cond_t * cond)
643 struct pthread *curthread = _get_curthread();
644 struct pthread *pthread;
645 struct kse_mailbox *kmbx;
648 THR_ASSERT(curthread->locklevel == 0,
649 "cv_timedwait: locklevel is not zero!");
653 * If the condition variable is statically initialized, perform dynamic
656 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
657 /* Lock the condition variable structure: */
658 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
660 /* Process according to condition variable type: */
661 switch ((*cond)->c_type) {
662 /* Fast condition variable: */
664 /* Increment the sequence number: */
668 * Enter a loop to bring all threads off the
671 while ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
673 THR_SCHED_LOCK(curthread, pthread);
674 cond_queue_remove(*cond, pthread);
675 pthread->sigbackout = NULL;
676 if ((pthread->kseg == curthread->kseg) &&
677 (pthread->active_priority >
678 curthread->active_priority))
679 curthread->critical_yield = 1;
680 kmbx = _thr_setrunnable_unlocked(pthread);
681 THR_SCHED_UNLOCK(curthread, pthread);
686 /* There are no more waiting threads: */
687 (*cond)->c_mutex = NULL;
690 /* Trap invalid condition variable types: */
692 /* Return an invalid argument error: */
697 /* Unlock the condition variable structure: */
698 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
701 /* Return the completion status: */
705 __strong_reference(_pthread_cond_broadcast, _thr_cond_broadcast);
708 check_continuation(struct pthread *curthread, struct pthread_cond *cond,
709 pthread_mutex_t *mutex)
711 if ((curthread->interrupted != 0) &&
712 (curthread->continuation != NULL)) {
714 /* Unlock the condition variable structure: */
715 THR_LOCK_RELEASE(curthread, &cond->c_lock);
717 * Note that even though this thread may have been
718 * canceled, POSIX requires that the mutex be
719 * reaquired prior to cancellation.
722 _mutex_cv_lock(mutex);
723 curthread->continuation((void *) curthread);
724 PANIC("continuation returned in pthread_cond_wait.\n");
729 cond_wait_backout(void *arg)
731 struct pthread *curthread = (struct pthread *)arg;
734 cond = curthread->data.cond;
736 /* Lock the condition variable structure: */
737 THR_LOCK_ACQUIRE(curthread, &cond->c_lock);
739 /* Process according to condition variable type: */
740 switch (cond->c_type) {
741 /* Fast condition variable: */
743 cond_queue_remove(cond, curthread);
745 /* Check for no more waiters: */
746 if (TAILQ_FIRST(&cond->c_queue) == NULL)
747 cond->c_mutex = NULL;
754 /* Unlock the condition variable structure: */
755 THR_LOCK_RELEASE(curthread, &cond->c_lock);
757 /* No need to call this again. */
758 curthread->sigbackout = NULL;
762 * Dequeue a waiting thread from the head of a condition queue in
763 * descending priority order.
765 static inline struct pthread *
766 cond_queue_deq(pthread_cond_t cond)
768 struct pthread *pthread;
770 while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
771 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
772 THR_CONDQ_CLEAR(pthread);
773 if ((pthread->timeout == 0) && (pthread->interrupted == 0))
775 * Only exit the loop when we find a thread
776 * that hasn't timed out or been canceled;
777 * those threads are already running and don't
778 * need their run state changed.
787 * Remove a waiting thread from a condition queue in descending priority
791 cond_queue_remove(pthread_cond_t cond, struct pthread *pthread)
794 * Because pthread_cond_timedwait() can timeout as well
795 * as be signaled by another thread, it is necessary to
796 * guard against removing the thread from the queue if
797 * it isn't in the queue.
799 if (THR_IN_CONDQ(pthread)) {
800 TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
801 THR_CONDQ_CLEAR(pthread);
806 * Enqueue a waiting thread to a condition queue in descending priority
810 cond_queue_enq(pthread_cond_t cond, struct pthread *pthread)
812 struct pthread *tid = TAILQ_LAST(&cond->c_queue, cond_head);
814 THR_ASSERT(!THR_IN_SYNCQ(pthread),
815 "cond_queue_enq: thread already queued!");
818 * For the common case of all threads having equal priority,
819 * we perform a quick check against the priority of the thread
820 * at the tail of the queue.
822 if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
823 TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
825 tid = TAILQ_FIRST(&cond->c_queue);
826 while (pthread->active_priority <= tid->active_priority)
827 tid = TAILQ_NEXT(tid, sqe);
828 TAILQ_INSERT_BEFORE(tid, pthread, sqe);
830 THR_CONDQ_SET(pthread);
831 pthread->data.cond = cond;