thr_cond.c revision 63355
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 63355 2000-07-17 22:55:05Z jasone $ 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 } 28953812Salfred 29053812Salfred _thread_leave_cancellation_point(); 29113546Sjulian } 29213546Sjulian 29356698Sjasone _thread_leave_cancellation_point(); 29456698Sjasone 29513546Sjulian /* Return the completion status: */ 29613546Sjulian return (rval); 29713546Sjulian} 29813546Sjulian 29913546Sjulianint 30013546Sjulianpthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 30113546Sjulian const struct timespec * abstime) 30213546Sjulian{ 30356277Sjasone int rval = 0; 30456277Sjasone int interrupted = 0; 30513546Sjulian 30656698Sjasone _thread_enter_cancellation_point(); 30756698Sjasone 30863355Sjasone if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 30963355Sjasone abstime->tv_nsec >= 1000000000) 31050601Sdeischen rval = EINVAL; 31135027Sjb /* 31263355Sjasone * If the condition variable is statically initialized, perform dynamic 31363355Sjasone * initialization. 31435027Sjb */ 31563355Sjasone else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) { 31653812Salfred _thread_enter_cancellation_point(); 31753812Salfred 31848046Sjb /* Lock the condition variable structure: */ 31948046Sjb _SPINLOCK(&(*cond)->lock); 32048046Sjb 32147424Sjb /* 32247424Sjb * If the condvar was statically allocated, properly 32347424Sjb * initialize the tail queue. 32447424Sjb */ 32547424Sjb if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { 32647424Sjb TAILQ_INIT(&(*cond)->c_queue); 32747424Sjb (*cond)->c_flags |= COND_FLAGS_INITED; 32847424Sjb } 32947424Sjb 33017706Sjulian /* Process according to condition variable type: */ 33117706Sjulian switch ((*cond)->c_type) { 33224827Sjb /* Fast condition variable: */ 33317706Sjulian case COND_TYPE_FAST: 33444963Sjb if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && 33544963Sjb ((*cond)->c_mutex != *mutex))) { 33644963Sjb /* Return invalid argument error: */ 33744963Sjb rval = EINVAL; 33813546Sjulian 33944963Sjb /* Unlock the condition variable structure: */ 34044963Sjb _SPINUNLOCK(&(*cond)->lock); 34144963Sjb } else { 34244963Sjb /* Set the wakeup time: */ 34344963Sjb _thread_run->wakeup_time.tv_sec = 34444963Sjb abstime->tv_sec; 34544963Sjb _thread_run->wakeup_time.tv_nsec = 34644963Sjb abstime->tv_nsec; 34713546Sjulian 34853812Salfred /* Reset the timeout and interrupted flags: */ 34944963Sjb _thread_run->timeout = 0; 35053812Salfred _thread_run->interrupted = 0; 35113546Sjulian 35217706Sjulian /* 35344963Sjb * Queue the running thread for the condition 35444963Sjb * variable: 35517706Sjulian */ 35644963Sjb cond_queue_enq(*cond, _thread_run); 35740974Sdt 35844963Sjb /* Remember the mutex that is being used: */ 35944963Sjb (*cond)->c_mutex = *mutex; 36013546Sjulian 36144963Sjb /* Unlock the mutex: */ 36244963Sjb if ((rval = _mutex_cv_unlock(mutex)) != 0) { 36344963Sjb /* 36444963Sjb * Cannot unlock the mutex, so remove 36544963Sjb * the running thread from the condition 36644963Sjb * variable queue: 36744963Sjb */ 36844963Sjb cond_queue_remove(*cond, _thread_run); 36944963Sjb 37044963Sjb /* Check for no more waiters: */ 37144963Sjb if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 37244963Sjb (*cond)->c_mutex = NULL; 37344963Sjb 37444963Sjb /* Unlock the condition variable structure: */ 37544963Sjb _SPINUNLOCK(&(*cond)->lock); 37644963Sjb } else { 37744963Sjb /* 37844963Sjb * Schedule the next thread and unlock 37944963Sjb * the condition variable structure: 38044963Sjb */ 38144963Sjb _thread_kern_sched_state_unlock(PS_COND_WAIT, 38244963Sjb &(*cond)->lock, __FILE__, __LINE__); 38344963Sjb 38453812Salfred /* 38553812Salfred * Check if the wait timedout or was 38653812Salfred * interrupted (canceled): 38753812Salfred */ 38853812Salfred if ((_thread_run->timeout == 0) && 38953812Salfred (_thread_run->interrupted == 0)) { 39044963Sjb /* Lock the mutex: */ 39144963Sjb rval = _mutex_cv_lock(mutex); 39253812Salfred 39353812Salfred } else { 39456277Sjasone /* 39556277Sjasone * Remember if this thread was 39656277Sjasone * interrupted: 39756277Sjasone */ 39856277Sjasone interrupted = _thread_run->interrupted; 39956277Sjasone 40044963Sjb /* Lock the condition variable structure: */ 40144963Sjb _SPINLOCK(&(*cond)->lock); 40244963Sjb 40344963Sjb /* 40444963Sjb * The wait timed out; remove 40544963Sjb * the thread from the condition 40644963Sjb * variable queue: 40744963Sjb */ 40844963Sjb cond_queue_remove(*cond, 40944963Sjb _thread_run); 41044963Sjb 41144963Sjb /* Check for no more waiters: */ 41244963Sjb if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 41344963Sjb (*cond)->c_mutex = NULL; 41444963Sjb 41544963Sjb /* Unock the condition variable structure: */ 41644963Sjb _SPINUNLOCK(&(*cond)->lock); 41744963Sjb 41844963Sjb /* Return a timeout error: */ 41944963Sjb rval = ETIMEDOUT; 42044963Sjb 42144963Sjb /* 42253812Salfred * Lock the mutex and ignore any 42353812Salfred * errors. Note that even though 42453812Salfred * this thread may have been 42553812Salfred * canceled, POSIX requires that 42653812Salfred * the mutex be reaquired prior 42753812Salfred * to cancellation. 42844963Sjb */ 42944963Sjb (void)_mutex_cv_lock(mutex); 43044963Sjb } 43117706Sjulian } 43213546Sjulian } 43317706Sjulian break; 43417706Sjulian 43524827Sjb /* Trap invalid condition variable types: */ 43617706Sjulian default: 43740974Sdt /* Unlock the condition variable structure: */ 43840974Sdt _SPINUNLOCK(&(*cond)->lock); 43940974Sdt 44017706Sjulian /* Return an invalid argument error: */ 44131402Salex rval = EINVAL; 44217706Sjulian break; 44313546Sjulian } 44413546Sjulian 44558094Sdeischen if (interrupted != 0) { 44658094Sdeischen if (_thread_run->continuation != NULL) 44758094Sdeischen _thread_run->continuation((void *) _thread_run); 44858094Sdeischen } 44953812Salfred 45053812Salfred _thread_leave_cancellation_point(); 45113546Sjulian } 45213546Sjulian 45356698Sjasone _thread_leave_cancellation_point(); 45456698Sjasone 45513546Sjulian /* Return the completion status: */ 45613546Sjulian return (rval); 45713546Sjulian} 45813546Sjulian 45913546Sjulianint 46013546Sjulianpthread_cond_signal(pthread_cond_t * cond) 46113546Sjulian{ 46213546Sjulian int rval = 0; 46313546Sjulian pthread_t pthread; 46413546Sjulian 46563355Sjasone if (cond == NULL) 46631402Salex rval = EINVAL; 46763355Sjasone /* 46863355Sjasone * If the condition variable is statically initialized, perform dynamic 46963355Sjasone * initialization. 47063355Sjasone */ 47163355Sjasone else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL) == 0)) { 47248046Sjb /* 47348046Sjb * Defer signals to protect the scheduling queues 47448046Sjb * from access by the signal handler: 47548046Sjb */ 47648046Sjb _thread_kern_sig_defer(); 47748046Sjb 47835509Sjb /* Lock the condition variable structure: */ 47936830Sjb _SPINLOCK(&(*cond)->lock); 48013546Sjulian 48117706Sjulian /* Process according to condition variable type: */ 48217706Sjulian switch ((*cond)->c_type) { 48324827Sjb /* Fast condition variable: */ 48417706Sjulian case COND_TYPE_FAST: 48561681Sjasone if ((pthread = cond_queue_deq(*cond)) != NULL) { 48661681Sjasone /* 48761681Sjasone * Unless the thread is currently suspended, 48861681Sjasone * allow it to run. If the thread is suspended, 48961681Sjasone * make a note that the thread isn't in a wait 49061681Sjasone * queue any more. 49161681Sjasone */ 49261681Sjasone if (pthread->state != PS_SUSPENDED) 49361681Sjasone PTHREAD_NEW_STATE(pthread,PS_RUNNING); 49461681Sjasone else 49561681Sjasone pthread->suspended = SUSP_NOWAIT; 49661681Sjasone } 49744963Sjb 49844963Sjb /* Check for no more waiters: */ 49944963Sjb if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 50044963Sjb (*cond)->c_mutex = NULL; 50117706Sjulian break; 50217706Sjulian 50324827Sjb /* Trap invalid condition variable types: */ 50417706Sjulian default: 50517706Sjulian /* Return an invalid argument error: */ 50631402Salex rval = EINVAL; 50717706Sjulian break; 50813546Sjulian } 50913546Sjulian 51035509Sjb /* Unlock the condition variable structure: */ 51136830Sjb _SPINUNLOCK(&(*cond)->lock); 51248046Sjb 51348046Sjb /* 51448046Sjb * Undefer and handle pending signals, yielding if 51548046Sjb * necessary: 51648046Sjb */ 51748046Sjb _thread_kern_sig_undefer(); 51813546Sjulian } 51913546Sjulian 52013546Sjulian /* Return the completion status: */ 52113546Sjulian return (rval); 52213546Sjulian} 52313546Sjulian 52413546Sjulianint 52513546Sjulianpthread_cond_broadcast(pthread_cond_t * cond) 52613546Sjulian{ 52713546Sjulian int rval = 0; 52813546Sjulian pthread_t pthread; 52913546Sjulian 53063355Sjasone if (cond == NULL) 53135509Sjb rval = EINVAL; 53263355Sjasone /* 53363355Sjasone * If the condition variable is statically initialized, perform dynamic 53463355Sjasone * initialization. 53563355Sjasone */ 53663355Sjasone else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL) == 0)) { 53744963Sjb /* 53848046Sjb * Defer signals to protect the scheduling queues 53948046Sjb * from access by the signal handler: 54044963Sjb */ 54148046Sjb _thread_kern_sig_defer(); 54244963Sjb 54335509Sjb /* Lock the condition variable structure: */ 54436830Sjb _SPINLOCK(&(*cond)->lock); 54513546Sjulian 54635509Sjb /* Process according to condition variable type: */ 54735509Sjb switch ((*cond)->c_type) { 54835509Sjb /* Fast condition variable: */ 54935509Sjb case COND_TYPE_FAST: 55035509Sjb /* 55135509Sjb * Enter a loop to bring all threads off the 55235509Sjb * condition queue: 55335509Sjb */ 55444963Sjb while ((pthread = cond_queue_deq(*cond)) != NULL) { 55561681Sjasone /* 55661681Sjasone * Unless the thread is currently suspended, 55761681Sjasone * allow it to run. If the thread is suspended, 55861681Sjasone * make a note that the thread isn't in a wait 55961681Sjasone * queue any more. 56061681Sjasone */ 56161681Sjasone if (pthread->state != PS_SUSPENDED) 56261681Sjasone PTHREAD_NEW_STATE(pthread,PS_RUNNING); 56361681Sjasone else 56461681Sjasone pthread->suspended = SUSP_NOWAIT; 56535509Sjb } 56644963Sjb 56744963Sjb /* There are no more waiting threads: */ 56844963Sjb (*cond)->c_mutex = NULL; 56935509Sjb break; 57035509Sjb 57135509Sjb /* Trap invalid condition variable types: */ 57235509Sjb default: 57335509Sjb /* Return an invalid argument error: */ 57435509Sjb rval = EINVAL; 57535509Sjb break; 57613546Sjulian } 57713546Sjulian 57835509Sjb /* Unlock the condition variable structure: */ 57936830Sjb _SPINUNLOCK(&(*cond)->lock); 58044963Sjb 58148046Sjb /* 58248046Sjb * Undefer and handle pending signals, yielding if 58348046Sjb * necessary: 58444963Sjb */ 58548046Sjb _thread_kern_sig_undefer(); 58613546Sjulian } 58713546Sjulian 58813546Sjulian /* Return the completion status: */ 58913546Sjulian return (rval); 59013546Sjulian} 59144963Sjb 59244963Sjb/* 59344963Sjb * Dequeue a waiting thread from the head of a condition queue in 59444963Sjb * descending priority order. 59544963Sjb */ 59644963Sjbstatic inline pthread_t 59744963Sjbcond_queue_deq(pthread_cond_t cond) 59844963Sjb{ 59944963Sjb pthread_t pthread; 60044963Sjb 60153812Salfred while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { 60244963Sjb TAILQ_REMOVE(&cond->c_queue, pthread, qe); 60348046Sjb pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; 60453812Salfred if ((pthread->timeout == 0) && (pthread->interrupted == 0)) 60553812Salfred /* 60653812Salfred * Only exit the loop when we find a thread 60753812Salfred * that hasn't timed out or been canceled; 60853812Salfred * those threads are already running and don't 60953812Salfred * need their run state changed. 61053812Salfred */ 61153812Salfred break; 61244963Sjb } 61344963Sjb 61444963Sjb return(pthread); 61544963Sjb} 61644963Sjb 61744963Sjb/* 61844963Sjb * Remove a waiting thread from a condition queue in descending priority 61944963Sjb * order. 62044963Sjb */ 62144963Sjbstatic inline void 62244963Sjbcond_queue_remove(pthread_cond_t cond, pthread_t pthread) 62344963Sjb{ 62444963Sjb /* 62544963Sjb * Because pthread_cond_timedwait() can timeout as well 62644963Sjb * as be signaled by another thread, it is necessary to 62744963Sjb * guard against removing the thread from the queue if 62844963Sjb * it isn't in the queue. 62944963Sjb */ 63048046Sjb if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) { 63144963Sjb TAILQ_REMOVE(&cond->c_queue, pthread, qe); 63248046Sjb pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; 63344963Sjb } 63444963Sjb} 63544963Sjb 63644963Sjb/* 63744963Sjb * Enqueue a waiting thread to a condition queue in descending priority 63844963Sjb * order. 63944963Sjb */ 64044963Sjbstatic inline void 64144963Sjbcond_queue_enq(pthread_cond_t cond, pthread_t pthread) 64244963Sjb{ 64344963Sjb pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head); 64444963Sjb 64544963Sjb /* 64644963Sjb * For the common case of all threads having equal priority, 64744963Sjb * we perform a quick check against the priority of the thread 64844963Sjb * at the tail of the queue. 64944963Sjb */ 65044963Sjb if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) 65144963Sjb TAILQ_INSERT_TAIL(&cond->c_queue, pthread, qe); 65244963Sjb else { 65344963Sjb tid = TAILQ_FIRST(&cond->c_queue); 65444963Sjb while (pthread->active_priority <= tid->active_priority) 65544963Sjb tid = TAILQ_NEXT(tid, qe); 65644963Sjb TAILQ_INSERT_BEFORE(tid, pthread, qe); 65744963Sjb } 65848046Sjb pthread->flags |= PTHREAD_FLAGS_IN_CONDQ; 65944963Sjb} 66013546Sjulian#endif 661