thr_cond.c revision 58094
113546Sjulian/* 213546Sjulian * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 313546Sjulian * All rights reserved. 413546Sjulian * 513546Sjulian * Redistribution and use in source and binary forms, with or without 613546Sjulian * modification, are permitted provided that the following conditions 713546Sjulian * are met: 813546Sjulian * 1. Redistributions of source code must retain the above copyright 913546Sjulian * notice, this list of conditions and the following disclaimer. 1013546Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1113546Sjulian * notice, this list of conditions and the following disclaimer in the 1213546Sjulian * documentation and/or other materials provided with the distribution. 1313546Sjulian * 3. All advertising materials mentioning features or use of this software 1413546Sjulian * must display the following acknowledgement: 1513546Sjulian * This product includes software developed by John Birrell. 1613546Sjulian * 4. Neither the name of the author nor the names of any co-contributors 1713546Sjulian * may be used to endorse or promote products derived from this software 1813546Sjulian * without specific prior written permission. 1913546Sjulian * 2013546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 2113546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2213546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2344963Sjb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2413546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2513546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2613546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2713546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2813546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2913546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3013546Sjulian * SUCH DAMAGE. 3113546Sjulian * 3250476Speter * $FreeBSD: head/lib/libkse/thread/thr_cond.c 58094 2000-03-15 13:59:27Z deischen $ 3313546Sjulian */ 3413546Sjulian#include <stdlib.h> 3513546Sjulian#include <errno.h> 3636830Sjb#include <string.h> 3713546Sjulian#ifdef _THREAD_SAFE 3813546Sjulian#include <pthread.h> 3913546Sjulian#include "pthread_private.h" 4013546Sjulian 4144963Sjb/* 4244963Sjb * Prototypes 4344963Sjb */ 4444963Sjbstatic inline pthread_t cond_queue_deq(pthread_cond_t); 4544963Sjbstatic inline void cond_queue_remove(pthread_cond_t, pthread_t); 4644963Sjbstatic inline void cond_queue_enq(pthread_cond_t, pthread_t); 4744963Sjb 4848046Sjb/* Reinitialize a condition variable to defaults. */ 4948046Sjbint 5048046Sjb_cond_reinit(pthread_cond_t * cond) 5148046Sjb{ 5248046Sjb int ret = 0; 5344963Sjb 5448046Sjb if (cond == NULL) 5548046Sjb ret = EINVAL; 5648046Sjb else if (*cond == NULL) 5748046Sjb ret = pthread_cond_init(cond, NULL); 5848046Sjb else { 5948046Sjb /* 6048046Sjb * Initialize the condition variable structure: 6148046Sjb */ 6248046Sjb TAILQ_INIT(&(*cond)->c_queue); 6348046Sjb (*cond)->c_flags = COND_FLAGS_INITED; 6448046Sjb (*cond)->c_type = COND_TYPE_FAST; 6548046Sjb (*cond)->c_mutex = NULL; 6648046Sjb memset(&(*cond)->lock, 0, sizeof((*cond)->lock)); 6748046Sjb } 6848046Sjb return (ret); 6948046Sjb} 7048046Sjb 7113546Sjulianint 7213546Sjulianpthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr) 7313546Sjulian{ 7413546Sjulian enum pthread_cond_type type; 7517706Sjulian pthread_cond_t pcond; 7613546Sjulian int rval = 0; 7713546Sjulian 7835509Sjb if (cond == NULL) 7931402Salex rval = EINVAL; 8035509Sjb else { 8117706Sjulian /* 8224827Sjb * Check if a pointer to a condition variable attribute 8324827Sjb * structure was passed by the caller: 8417706Sjulian */ 8517706Sjulian if (cond_attr != NULL && *cond_attr != NULL) { 8617706Sjulian /* Default to a fast condition variable: */ 8717706Sjulian type = (*cond_attr)->c_type; 8817706Sjulian } else { 8917706Sjulian /* Default to a fast condition variable: */ 9017706Sjulian type = COND_TYPE_FAST; 9117706Sjulian } 9213546Sjulian 9317706Sjulian /* Process according to condition variable type: */ 9417706Sjulian switch (type) { 9524827Sjb /* Fast condition variable: */ 9617706Sjulian case COND_TYPE_FAST: 9717706Sjulian /* Nothing to do here. */ 9817706Sjulian break; 9913546Sjulian 10024827Sjb /* Trap invalid condition variable types: */ 10117706Sjulian default: 10217706Sjulian /* Return an invalid argument error: */ 10331402Salex rval = EINVAL; 10417706Sjulian break; 10517706Sjulian } 10613546Sjulian 10717706Sjulian /* Check for no errors: */ 10817706Sjulian if (rval == 0) { 10924827Sjb if ((pcond = (pthread_cond_t) 11024827Sjb malloc(sizeof(struct pthread_cond))) == NULL) { 11131402Salex rval = ENOMEM; 11217706Sjulian } else { 11317706Sjulian /* 11417706Sjulian * Initialise the condition variable 11517706Sjulian * structure: 11617706Sjulian */ 11744963Sjb TAILQ_INIT(&pcond->c_queue); 11817706Sjulian pcond->c_flags |= COND_FLAGS_INITED; 11917706Sjulian pcond->c_type = type; 12044963Sjb pcond->c_mutex = NULL; 12136830Sjb memset(&pcond->lock,0,sizeof(pcond->lock)); 12217706Sjulian *cond = pcond; 12317706Sjulian } 12417706Sjulian } 12513546Sjulian } 12613546Sjulian /* Return the completion status: */ 12713546Sjulian return (rval); 12813546Sjulian} 12913546Sjulian 13013546Sjulianint 13113546Sjulianpthread_cond_destroy(pthread_cond_t * cond) 13213546Sjulian{ 13313546Sjulian int rval = 0; 13413546Sjulian 13535509Sjb if (cond == NULL || *cond == NULL) 13631402Salex rval = EINVAL; 13735509Sjb else { 13835509Sjb /* Lock the condition variable structure: */ 13936830Sjb _SPINLOCK(&(*cond)->lock); 14013546Sjulian 14135509Sjb /* 14235509Sjb * Free the memory allocated for the condition 14335509Sjb * variable structure: 14435509Sjb */ 14535509Sjb free(*cond); 14617706Sjulian 14735509Sjb /* 14835509Sjb * NULL the caller's pointer now that the condition 14935509Sjb * variable has been destroyed: 15035509Sjb */ 15135509Sjb *cond = NULL; 15213546Sjulian } 15313546Sjulian /* Return the completion status: */ 15413546Sjulian return (rval); 15513546Sjulian} 15613546Sjulian 15713546Sjulianint 15813546Sjulianpthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) 15913546Sjulian{ 16056277Sjasone int rval = 0; 16156277Sjasone int interrupted = 0; 16213546Sjulian 16356698Sjasone _thread_enter_cancellation_point(); 16456698Sjasone 16535027Sjb if (cond == NULL) 16631402Salex rval = EINVAL; 16735027Sjb 16835027Sjb /* 16935027Sjb * If the condition variable is statically initialized, 17035027Sjb * perform the dynamic initialization: 17135027Sjb */ 17235027Sjb else if (*cond != NULL || 17335027Sjb (rval = pthread_cond_init(cond,NULL)) == 0) { 17453812Salfred 17553812Salfred _thread_enter_cancellation_point(); 17653812Salfred 17748046Sjb /* Lock the condition variable structure: */ 17848046Sjb _SPINLOCK(&(*cond)->lock); 17948046Sjb 18047424Sjb /* 18147424Sjb * If the condvar was statically allocated, properly 18247424Sjb * initialize the tail queue. 18347424Sjb */ 18447424Sjb if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { 18547424Sjb TAILQ_INIT(&(*cond)->c_queue); 18647424Sjb (*cond)->c_flags |= COND_FLAGS_INITED; 18747424Sjb } 18847424Sjb 18917706Sjulian /* Process according to condition variable type: */ 19017706Sjulian switch ((*cond)->c_type) { 19124827Sjb /* Fast condition variable: */ 19217706Sjulian case COND_TYPE_FAST: 19344963Sjb if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && 19444963Sjb ((*cond)->c_mutex != *mutex))) { 19544963Sjb /* Unlock the condition variable structure: */ 19644963Sjb _SPINUNLOCK(&(*cond)->lock); 19740974Sdt 19844963Sjb /* Return invalid argument error: */ 19944963Sjb rval = EINVAL; 20044963Sjb } else { 20153812Salfred /* Reset the timeout and interrupted flags: */ 20244963Sjb _thread_run->timeout = 0; 20353812Salfred _thread_run->interrupted = 0; 20413546Sjulian 20540974Sdt /* 20644963Sjb * Queue the running thread for the condition 20744963Sjb * variable: 20840974Sdt */ 20944963Sjb cond_queue_enq(*cond, _thread_run); 21013546Sjulian 21144963Sjb /* Remember the mutex that is being used: */ 21244963Sjb (*cond)->c_mutex = *mutex; 21335509Sjb 21444963Sjb /* Wait forever: */ 21544963Sjb _thread_run->wakeup_time.tv_sec = -1; 21644963Sjb 21744963Sjb /* Unlock the mutex: */ 21844963Sjb if ((rval = _mutex_cv_unlock(mutex)) != 0) { 21944963Sjb /* 22044963Sjb * Cannot unlock the mutex, so remove 22144963Sjb * the running thread from the condition 22244963Sjb * variable queue: 22344963Sjb */ 22444963Sjb cond_queue_remove(*cond, _thread_run); 22544963Sjb 22644963Sjb /* Check for no more waiters: */ 22744963Sjb if (TAILQ_FIRST(&(*cond)->c_queue) == 22844963Sjb NULL) 22944963Sjb (*cond)->c_mutex = NULL; 23044963Sjb 23144963Sjb /* Unlock the condition variable structure: */ 23244963Sjb _SPINUNLOCK(&(*cond)->lock); 23344963Sjb } 23444963Sjb else { 23544963Sjb /* 23644963Sjb * Schedule the next thread and unlock 23744963Sjb * the condition variable structure: 23844963Sjb */ 23944963Sjb _thread_kern_sched_state_unlock(PS_COND_WAIT, 24044963Sjb &(*cond)->lock, __FILE__, __LINE__); 24144963Sjb 24253812Salfred if (_thread_run->interrupted != 0) { 24353812Salfred /* 24456277Sjasone * Remember that this thread 24556277Sjasone * was interrupted: 24656277Sjasone */ 24756277Sjasone interrupted = 1; 24856277Sjasone 24956277Sjasone /* 25053812Salfred * Lock the condition variable 25153812Salfred * while removing the thread. 25253812Salfred */ 25353812Salfred _SPINLOCK(&(*cond)->lock); 25453812Salfred 25553812Salfred cond_queue_remove(*cond, 25653812Salfred _thread_run); 25753812Salfred 25853812Salfred /* Check for no more waiters: */ 25953812Salfred if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 26053812Salfred (*cond)->c_mutex = NULL; 26153812Salfred 26253812Salfred _SPINUNLOCK(&(*cond)->lock); 26353812Salfred } 26453812Salfred 26553812Salfred /* 26653812Salfred * Note that even though this thread may have 26753812Salfred * been canceled, POSIX requires that the mutex 26853812Salfred * be reaquired prior to cancellation. 26953812Salfred */ 27044963Sjb rval = _mutex_cv_lock(mutex); 27144963Sjb } 27240974Sdt } 27317706Sjulian break; 27413546Sjulian 27524827Sjb /* Trap invalid condition variable types: */ 27617706Sjulian default: 27740974Sdt /* Unlock the condition variable structure: */ 27840974Sdt _SPINUNLOCK(&(*cond)->lock); 27940974Sdt 28017706Sjulian /* Return an invalid argument error: */ 28131402Salex rval = EINVAL; 28217706Sjulian break; 28317706Sjulian } 28453812Salfred 28558094Sdeischen if (interrupted != 0) { 28658094Sdeischen if (_thread_run->continuation != NULL) 28758094Sdeischen _thread_run->continuation((void *) _thread_run); 28858094Sdeischen rval = EINTR; 28958094Sdeischen } 29053812Salfred 29153812Salfred _thread_leave_cancellation_point(); 29213546Sjulian } 29313546Sjulian 29456698Sjasone _thread_leave_cancellation_point(); 29556698Sjasone 29613546Sjulian /* Return the completion status: */ 29713546Sjulian return (rval); 29813546Sjulian} 29913546Sjulian 30013546Sjulianint 30113546Sjulianpthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 30213546Sjulian const struct timespec * abstime) 30313546Sjulian{ 30456277Sjasone int rval = 0; 30556277Sjasone int interrupted = 0; 30613546Sjulian 30756698Sjasone _thread_enter_cancellation_point(); 30856698Sjasone 30950601Sdeischen if (cond == NULL || abstime == NULL) 31050601Sdeischen rval = EINVAL; 31150601Sdeischen 31250065Salfred if (abstime->tv_sec < 0 || 31350601Sdeischen abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) { 31450601Sdeischen errno = EINVAL; 31556698Sjasone _thread_leave_cancellation_point(); 31650601Sdeischen return (-1); 31750601Sdeischen } 31850065Salfred 31935027Sjb /* 32035027Sjb * If the condition variable is statically initialized, 32135027Sjb * perform the dynamic initialization: 32235027Sjb */ 32350601Sdeischen if (*cond != NULL || 32435027Sjb (rval = pthread_cond_init(cond,NULL)) == 0) { 32553812Salfred 32653812Salfred _thread_enter_cancellation_point(); 32753812Salfred 32848046Sjb /* Lock the condition variable structure: */ 32948046Sjb _SPINLOCK(&(*cond)->lock); 33048046Sjb 33147424Sjb /* 33247424Sjb * If the condvar was statically allocated, properly 33347424Sjb * initialize the tail queue. 33447424Sjb */ 33547424Sjb if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { 33647424Sjb TAILQ_INIT(&(*cond)->c_queue); 33747424Sjb (*cond)->c_flags |= COND_FLAGS_INITED; 33847424Sjb } 33947424Sjb 34017706Sjulian /* Process according to condition variable type: */ 34117706Sjulian switch ((*cond)->c_type) { 34224827Sjb /* Fast condition variable: */ 34317706Sjulian case COND_TYPE_FAST: 34444963Sjb if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && 34544963Sjb ((*cond)->c_mutex != *mutex))) { 34644963Sjb /* Return invalid argument error: */ 34744963Sjb rval = EINVAL; 34813546Sjulian 34944963Sjb /* Unlock the condition variable structure: */ 35044963Sjb _SPINUNLOCK(&(*cond)->lock); 35144963Sjb } else { 35244963Sjb /* Set the wakeup time: */ 35344963Sjb _thread_run->wakeup_time.tv_sec = 35444963Sjb abstime->tv_sec; 35544963Sjb _thread_run->wakeup_time.tv_nsec = 35644963Sjb abstime->tv_nsec; 35713546Sjulian 35853812Salfred /* Reset the timeout and interrupted flags: */ 35944963Sjb _thread_run->timeout = 0; 36053812Salfred _thread_run->interrupted = 0; 36113546Sjulian 36217706Sjulian /* 36344963Sjb * Queue the running thread for the condition 36444963Sjb * variable: 36517706Sjulian */ 36644963Sjb cond_queue_enq(*cond, _thread_run); 36740974Sdt 36844963Sjb /* Remember the mutex that is being used: */ 36944963Sjb (*cond)->c_mutex = *mutex; 37013546Sjulian 37144963Sjb /* Unlock the mutex: */ 37244963Sjb if ((rval = _mutex_cv_unlock(mutex)) != 0) { 37344963Sjb /* 37444963Sjb * Cannot unlock the mutex, so remove 37544963Sjb * the running thread from the condition 37644963Sjb * variable queue: 37744963Sjb */ 37844963Sjb cond_queue_remove(*cond, _thread_run); 37944963Sjb 38044963Sjb /* Check for no more waiters: */ 38144963Sjb if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 38244963Sjb (*cond)->c_mutex = NULL; 38344963Sjb 38444963Sjb /* Unlock the condition variable structure: */ 38544963Sjb _SPINUNLOCK(&(*cond)->lock); 38644963Sjb } else { 38744963Sjb /* 38844963Sjb * Schedule the next thread and unlock 38944963Sjb * the condition variable structure: 39044963Sjb */ 39144963Sjb _thread_kern_sched_state_unlock(PS_COND_WAIT, 39244963Sjb &(*cond)->lock, __FILE__, __LINE__); 39344963Sjb 39453812Salfred /* 39553812Salfred * Check if the wait timedout or was 39653812Salfred * interrupted (canceled): 39753812Salfred */ 39853812Salfred if ((_thread_run->timeout == 0) && 39953812Salfred (_thread_run->interrupted == 0)) { 40044963Sjb /* Lock the mutex: */ 40144963Sjb rval = _mutex_cv_lock(mutex); 40253812Salfred 40353812Salfred } else { 40456277Sjasone /* 40556277Sjasone * Remember if this thread was 40656277Sjasone * interrupted: 40756277Sjasone */ 40856277Sjasone interrupted = _thread_run->interrupted; 40956277Sjasone 41044963Sjb /* Lock the condition variable structure: */ 41144963Sjb _SPINLOCK(&(*cond)->lock); 41244963Sjb 41344963Sjb /* 41444963Sjb * The wait timed out; remove 41544963Sjb * the thread from the condition 41644963Sjb * variable queue: 41744963Sjb */ 41844963Sjb cond_queue_remove(*cond, 41944963Sjb _thread_run); 42044963Sjb 42144963Sjb /* Check for no more waiters: */ 42244963Sjb if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 42344963Sjb (*cond)->c_mutex = NULL; 42444963Sjb 42544963Sjb /* Unock the condition variable structure: */ 42644963Sjb _SPINUNLOCK(&(*cond)->lock); 42744963Sjb 42844963Sjb /* Return a timeout error: */ 42944963Sjb rval = ETIMEDOUT; 43044963Sjb 43144963Sjb /* 43253812Salfred * Lock the mutex and ignore any 43353812Salfred * errors. Note that even though 43453812Salfred * this thread may have been 43553812Salfred * canceled, POSIX requires that 43653812Salfred * the mutex be reaquired prior 43753812Salfred * to cancellation. 43844963Sjb */ 43944963Sjb (void)_mutex_cv_lock(mutex); 44044963Sjb } 44117706Sjulian } 44213546Sjulian } 44317706Sjulian break; 44417706Sjulian 44524827Sjb /* Trap invalid condition variable types: */ 44617706Sjulian default: 44740974Sdt /* Unlock the condition variable structure: */ 44840974Sdt _SPINUNLOCK(&(*cond)->lock); 44940974Sdt 45017706Sjulian /* Return an invalid argument error: */ 45131402Salex rval = EINVAL; 45217706Sjulian break; 45313546Sjulian } 45413546Sjulian 45558094Sdeischen if (interrupted != 0) { 45658094Sdeischen if (_thread_run->continuation != NULL) 45758094Sdeischen _thread_run->continuation((void *) _thread_run); 45858094Sdeischen rval = EINTR; 45958094Sdeischen } 46053812Salfred 46153812Salfred _thread_leave_cancellation_point(); 46213546Sjulian } 46313546Sjulian 46456698Sjasone _thread_leave_cancellation_point(); 46556698Sjasone 46613546Sjulian /* Return the completion status: */ 46713546Sjulian return (rval); 46813546Sjulian} 46913546Sjulian 47013546Sjulianint 47113546Sjulianpthread_cond_signal(pthread_cond_t * cond) 47213546Sjulian{ 47313546Sjulian int rval = 0; 47413546Sjulian pthread_t pthread; 47513546Sjulian 47635509Sjb if (cond == NULL || *cond == NULL) 47731402Salex rval = EINVAL; 47835509Sjb else { 47948046Sjb /* 48048046Sjb * Defer signals to protect the scheduling queues 48148046Sjb * from access by the signal handler: 48248046Sjb */ 48348046Sjb _thread_kern_sig_defer(); 48448046Sjb 48535509Sjb /* Lock the condition variable structure: */ 48636830Sjb _SPINLOCK(&(*cond)->lock); 48713546Sjulian 48817706Sjulian /* Process according to condition variable type: */ 48917706Sjulian switch ((*cond)->c_type) { 49024827Sjb /* Fast condition variable: */ 49117706Sjulian case COND_TYPE_FAST: 49253812Salfred if ((pthread = cond_queue_deq(*cond)) != NULL) 49317706Sjulian /* Allow the thread to run: */ 49422315Sjulian PTHREAD_NEW_STATE(pthread,PS_RUNNING); 49544963Sjb 49644963Sjb /* Check for no more waiters: */ 49744963Sjb if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 49844963Sjb (*cond)->c_mutex = NULL; 49917706Sjulian break; 50017706Sjulian 50124827Sjb /* Trap invalid condition variable types: */ 50217706Sjulian default: 50317706Sjulian /* Return an invalid argument error: */ 50431402Salex rval = EINVAL; 50517706Sjulian break; 50613546Sjulian } 50713546Sjulian 50835509Sjb /* Unlock the condition variable structure: */ 50936830Sjb _SPINUNLOCK(&(*cond)->lock); 51048046Sjb 51148046Sjb /* 51248046Sjb * Undefer and handle pending signals, yielding if 51348046Sjb * necessary: 51448046Sjb */ 51548046Sjb _thread_kern_sig_undefer(); 51613546Sjulian } 51713546Sjulian 51813546Sjulian /* Return the completion status: */ 51913546Sjulian return (rval); 52013546Sjulian} 52113546Sjulian 52213546Sjulianint 52313546Sjulianpthread_cond_broadcast(pthread_cond_t * cond) 52413546Sjulian{ 52513546Sjulian int rval = 0; 52613546Sjulian pthread_t pthread; 52713546Sjulian 52835509Sjb if (cond == NULL || *cond == NULL) 52935509Sjb rval = EINVAL; 53035509Sjb else { 53144963Sjb /* 53248046Sjb * Defer signals to protect the scheduling queues 53348046Sjb * from access by the signal handler: 53444963Sjb */ 53548046Sjb _thread_kern_sig_defer(); 53644963Sjb 53735509Sjb /* Lock the condition variable structure: */ 53836830Sjb _SPINLOCK(&(*cond)->lock); 53913546Sjulian 54035509Sjb /* Process according to condition variable type: */ 54135509Sjb switch ((*cond)->c_type) { 54235509Sjb /* Fast condition variable: */ 54335509Sjb case COND_TYPE_FAST: 54435509Sjb /* 54535509Sjb * Enter a loop to bring all threads off the 54635509Sjb * condition queue: 54735509Sjb */ 54844963Sjb while ((pthread = cond_queue_deq(*cond)) != NULL) { 54953812Salfred PTHREAD_NEW_STATE(pthread,PS_RUNNING); 55035509Sjb } 55144963Sjb 55244963Sjb /* There are no more waiting threads: */ 55344963Sjb (*cond)->c_mutex = NULL; 55435509Sjb break; 55535509Sjb 55635509Sjb /* Trap invalid condition variable types: */ 55735509Sjb default: 55835509Sjb /* Return an invalid argument error: */ 55935509Sjb rval = EINVAL; 56035509Sjb break; 56113546Sjulian } 56213546Sjulian 56335509Sjb /* Unlock the condition variable structure: */ 56436830Sjb _SPINUNLOCK(&(*cond)->lock); 56544963Sjb 56648046Sjb /* 56748046Sjb * Undefer and handle pending signals, yielding if 56848046Sjb * necessary: 56944963Sjb */ 57048046Sjb _thread_kern_sig_undefer(); 57113546Sjulian } 57213546Sjulian 57313546Sjulian /* Return the completion status: */ 57413546Sjulian return (rval); 57513546Sjulian} 57644963Sjb 57744963Sjb/* 57844963Sjb * Dequeue a waiting thread from the head of a condition queue in 57944963Sjb * descending priority order. 58044963Sjb */ 58144963Sjbstatic inline pthread_t 58244963Sjbcond_queue_deq(pthread_cond_t cond) 58344963Sjb{ 58444963Sjb pthread_t pthread; 58544963Sjb 58653812Salfred while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { 58744963Sjb TAILQ_REMOVE(&cond->c_queue, pthread, qe); 58848046Sjb pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; 58953812Salfred if ((pthread->timeout == 0) && (pthread->interrupted == 0)) 59053812Salfred /* 59153812Salfred * Only exit the loop when we find a thread 59253812Salfred * that hasn't timed out or been canceled; 59353812Salfred * those threads are already running and don't 59453812Salfred * need their run state changed. 59553812Salfred */ 59653812Salfred break; 59744963Sjb } 59844963Sjb 59944963Sjb return(pthread); 60044963Sjb} 60144963Sjb 60244963Sjb/* 60344963Sjb * Remove a waiting thread from a condition queue in descending priority 60444963Sjb * order. 60544963Sjb */ 60644963Sjbstatic inline void 60744963Sjbcond_queue_remove(pthread_cond_t cond, pthread_t pthread) 60844963Sjb{ 60944963Sjb /* 61044963Sjb * Because pthread_cond_timedwait() can timeout as well 61144963Sjb * as be signaled by another thread, it is necessary to 61244963Sjb * guard against removing the thread from the queue if 61344963Sjb * it isn't in the queue. 61444963Sjb */ 61548046Sjb if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) { 61644963Sjb TAILQ_REMOVE(&cond->c_queue, pthread, qe); 61748046Sjb pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; 61844963Sjb } 61944963Sjb} 62044963Sjb 62144963Sjb/* 62244963Sjb * Enqueue a waiting thread to a condition queue in descending priority 62344963Sjb * order. 62444963Sjb */ 62544963Sjbstatic inline void 62644963Sjbcond_queue_enq(pthread_cond_t cond, pthread_t pthread) 62744963Sjb{ 62844963Sjb pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head); 62944963Sjb 63044963Sjb /* 63144963Sjb * For the common case of all threads having equal priority, 63244963Sjb * we perform a quick check against the priority of the thread 63344963Sjb * at the tail of the queue. 63444963Sjb */ 63544963Sjb if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) 63644963Sjb TAILQ_INSERT_TAIL(&cond->c_queue, pthread, qe); 63744963Sjb else { 63844963Sjb tid = TAILQ_FIRST(&cond->c_queue); 63944963Sjb while (pthread->active_priority <= tid->active_priority) 64044963Sjb tid = TAILQ_NEXT(tid, qe); 64144963Sjb TAILQ_INSERT_BEFORE(tid, pthread, qe); 64244963Sjb } 64348046Sjb pthread->flags |= PTHREAD_FLAGS_IN_CONDQ; 64444963Sjb} 64513546Sjulian#endif 646