thr_cond.c revision 17706
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 2313546Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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 * 3213546Sjulian */ 3313546Sjulian#include <stdlib.h> 3413546Sjulian#include <errno.h> 3513546Sjulian#ifdef _THREAD_SAFE 3613546Sjulian#include <pthread.h> 3713546Sjulian#include "pthread_private.h" 3813546Sjulian 3913546Sjulianint 4013546Sjulianpthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr) 4113546Sjulian{ 4213546Sjulian enum pthread_cond_type type; 4317706Sjulian pthread_cond_t pcond; 4413546Sjulian int rval = 0; 4513546Sjulian 4617706Sjulian if (cond == NULL) { 4717706Sjulian errno = EINVAL; 4817706Sjulian rval = -1; 4913546Sjulian } else { 5017706Sjulian /* 5117706Sjulian * Check if a pointer to a condition variable attribute structure was 5217706Sjulian * passed by the caller: 5317706Sjulian */ 5417706Sjulian if (cond_attr != NULL && *cond_attr != NULL) { 5517706Sjulian /* Default to a fast condition variable: */ 5617706Sjulian type = (*cond_attr)->c_type; 5717706Sjulian } else { 5817706Sjulian /* Default to a fast condition variable: */ 5917706Sjulian type = COND_TYPE_FAST; 6017706Sjulian } 6113546Sjulian 6217706Sjulian /* Process according to condition variable type: */ 6317706Sjulian switch (type) { 6417706Sjulian /* Fast condition variable: */ 6517706Sjulian case COND_TYPE_FAST: 6617706Sjulian /* Nothing to do here. */ 6717706Sjulian break; 6813546Sjulian 6917706Sjulian /* Trap invalid condition variable types: */ 7017706Sjulian default: 7117706Sjulian /* Return an invalid argument error: */ 7217706Sjulian errno = EINVAL; 7317706Sjulian rval = -1; 7417706Sjulian break; 7517706Sjulian } 7613546Sjulian 7717706Sjulian /* Check for no errors: */ 7817706Sjulian if (rval == 0) { 7917706Sjulian if ((pcond = (pthread_cond_t) malloc(sizeof(struct pthread_cond))) == NULL) { 8017706Sjulian errno = ENOMEM; 8117706Sjulian rval = -1; 8217706Sjulian } else { 8317706Sjulian /* 8417706Sjulian * Initialise the condition variable 8517706Sjulian * structure: 8617706Sjulian */ 8717706Sjulian _thread_queue_init(&pcond->c_queue); 8817706Sjulian pcond->c_flags |= COND_FLAGS_INITED; 8917706Sjulian pcond->c_type = type; 9017706Sjulian *cond = pcond; 9117706Sjulian } 9217706Sjulian } 9313546Sjulian } 9413546Sjulian /* Return the completion status: */ 9513546Sjulian return (rval); 9613546Sjulian} 9713546Sjulian 9813546Sjulianint 9913546Sjulianpthread_cond_destroy(pthread_cond_t * cond) 10013546Sjulian{ 10113546Sjulian int rval = 0; 10213546Sjulian 10317706Sjulian if (cond == NULL || *cond == NULL) { 10417706Sjulian errno = EINVAL; 10513546Sjulian rval = -1; 10617706Sjulian } else { 10717706Sjulian /* Process according to condition variable type: */ 10817706Sjulian switch ((*cond)->c_type) { 10917706Sjulian /* Fast condition variable: */ 11017706Sjulian case COND_TYPE_FAST: 11117706Sjulian /* Nothing to do here. */ 11217706Sjulian break; 11313546Sjulian 11417706Sjulian /* Trap invalid condition variable types: */ 11517706Sjulian default: 11617706Sjulian /* Return an invalid argument error: */ 11717706Sjulian errno = EINVAL; 11817706Sjulian rval = -1; 11917706Sjulian break; 12017706Sjulian } 12117706Sjulian 12217706Sjulian /* Check for errors: */ 12317706Sjulian if (rval == 0) { 12417706Sjulian /* Destroy the contents of the condition structure: */ 12517706Sjulian _thread_queue_init(&(*cond)->c_queue); 12617706Sjulian (*cond)->c_flags = 0; 12717706Sjulian free(*cond); 12817706Sjulian *cond = NULL; 12917706Sjulian } 13013546Sjulian } 13113546Sjulian /* Return the completion status: */ 13213546Sjulian return (rval); 13313546Sjulian} 13413546Sjulian 13513546Sjulianint 13613546Sjulianpthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) 13713546Sjulian{ 13813546Sjulian int rval = 0; 13913546Sjulian int status; 14013546Sjulian 14117706Sjulian if (cond == NULL || *cond == NULL) { 14217706Sjulian errno = EINVAL; 14317706Sjulian rval = -1; 14417706Sjulian } else { 14517706Sjulian /* Block signals: */ 14617706Sjulian _thread_kern_sig_block(&status); 14713546Sjulian 14817706Sjulian /* Process according to condition variable type: */ 14917706Sjulian switch ((*cond)->c_type) { 15017706Sjulian /* Fast condition variable: */ 15117706Sjulian case COND_TYPE_FAST: 15217706Sjulian /* Queue the running thread for the condition variable: */ 15317706Sjulian _thread_queue_enq(&(*cond)->c_queue, _thread_run); 15413546Sjulian 15517706Sjulian /* Unlock the mutex: */ 15617706Sjulian pthread_mutex_unlock(mutex); 15713546Sjulian 15817706Sjulian /* Schedule the next thread: */ 15917706Sjulian _thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); 16013546Sjulian 16117706Sjulian /* Block signals: */ 16217706Sjulian _thread_kern_sig_block(NULL); 16313546Sjulian 16417706Sjulian /* Lock the mutex: */ 16517706Sjulian rval = pthread_mutex_lock(mutex); 16617706Sjulian break; 16713546Sjulian 16817706Sjulian /* Trap invalid condition variable types: */ 16917706Sjulian default: 17017706Sjulian /* Return an invalid argument error: */ 17117706Sjulian errno = EINVAL; 17217706Sjulian rval = -1; 17317706Sjulian break; 17417706Sjulian } 17517706Sjulian 17617706Sjulian /* Unblock signals: */ 17717706Sjulian _thread_kern_sig_unblock(status); 17813546Sjulian } 17913546Sjulian 18013546Sjulian /* Return the completion status: */ 18113546Sjulian return (rval); 18213546Sjulian} 18313546Sjulian 18413546Sjulianint 18513546Sjulianpthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 18613546Sjulian const struct timespec * abstime) 18713546Sjulian{ 18813546Sjulian int rval = 0; 18913546Sjulian int status; 19013546Sjulian 19117706Sjulian if (cond == NULL || *cond == NULL) { 19217706Sjulian errno = EINVAL; 19317706Sjulian rval = -1; 19417706Sjulian } else { 19517706Sjulian /* Block signals: */ 19617706Sjulian _thread_kern_sig_block(&status); 19713546Sjulian 19817706Sjulian /* Process according to condition variable type: */ 19917706Sjulian switch ((*cond)->c_type) { 20017706Sjulian /* Fast condition variable: */ 20117706Sjulian case COND_TYPE_FAST: 20217706Sjulian /* Set the wakeup time: */ 20317706Sjulian#if defined(__FreeBSD__) 20417706Sjulian _thread_run->wakeup_time.ts_sec = abstime->ts_sec; 20517706Sjulian _thread_run->wakeup_time.ts_nsec = abstime->ts_nsec; 20617706Sjulian#else 20717706Sjulian _thread_run->wakeup_time.tv_sec = abstime->tv_sec; 20817706Sjulian _thread_run->wakeup_time.tv_nsec = abstime->tv_nsec; 20917706Sjulian#endif 21013546Sjulian 21117706Sjulian /* Reset the timeout flag: */ 21217706Sjulian _thread_run->timeout = 0; 21313546Sjulian 21417706Sjulian /* Queue the running thread for the condition variable: */ 21517706Sjulian _thread_queue_enq(&(*cond)->c_queue, _thread_run); 21613546Sjulian 21717706Sjulian /* Unlock the mutex: */ 21817706Sjulian if ((rval = pthread_mutex_unlock(mutex)) != 0) { 21917706Sjulian /* 22017706Sjulian * Cannot unlock the mutex, so remove the running 22117706Sjulian * thread from the condition variable queue: 22217706Sjulian */ 22317706Sjulian _thread_queue_deq(&(*cond)->c_queue); 22417706Sjulian } else { 22517706Sjulian /* Schedule the next thread: */ 22617706Sjulian _thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); 22713546Sjulian 22817706Sjulian /* Block signals: */ 22917706Sjulian _thread_kern_sig_block(NULL); 23013546Sjulian 23117706Sjulian /* Lock the mutex: */ 23217706Sjulian if ((rval = pthread_mutex_lock(mutex)) != 0) { 23317706Sjulian } 23417706Sjulian /* Check if the wait timed out: */ 23517706Sjulian else if (_thread_run->timeout) { 23617706Sjulian /* Return a timeout error: */ 23717706Sjulian errno = EAGAIN; 23817706Sjulian rval = -1; 23917706Sjulian } 24013546Sjulian } 24117706Sjulian break; 24217706Sjulian 24317706Sjulian /* Trap invalid condition variable types: */ 24417706Sjulian default: 24517706Sjulian /* Return an invalid argument error: */ 24617706Sjulian errno = EINVAL; 24717706Sjulian rval = -1; 24817706Sjulian break; 24913546Sjulian } 25013546Sjulian 25117706Sjulian /* Unblock signals: */ 25217706Sjulian _thread_kern_sig_unblock(status); 25313546Sjulian } 25413546Sjulian 25513546Sjulian /* Return the completion status: */ 25613546Sjulian return (rval); 25713546Sjulian} 25813546Sjulian 25913546Sjulianint 26013546Sjulianpthread_cond_signal(pthread_cond_t * cond) 26113546Sjulian{ 26213546Sjulian int rval = 0; 26313546Sjulian int status; 26413546Sjulian pthread_t pthread; 26513546Sjulian 26617706Sjulian if (cond == NULL || *cond == NULL) { 26717706Sjulian errno = EINVAL; 26817706Sjulian rval = -1; 26917706Sjulian } else { 27017706Sjulian /* Block signals: */ 27117706Sjulian _thread_kern_sig_block(&status); 27213546Sjulian 27317706Sjulian /* Process according to condition variable type: */ 27417706Sjulian switch ((*cond)->c_type) { 27517706Sjulian /* Fast condition variable: */ 27617706Sjulian case COND_TYPE_FAST: 27717706Sjulian /* Bring the next thread off the condition queue: */ 27817706Sjulian if ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) { 27917706Sjulian /* Allow the thread to run: */ 28017706Sjulian pthread->state = PS_RUNNING; 28117706Sjulian } 28217706Sjulian break; 28317706Sjulian 28417706Sjulian /* Trap invalid condition variable types: */ 28517706Sjulian default: 28617706Sjulian /* Return an invalid argument error: */ 28717706Sjulian errno = EINVAL; 28817706Sjulian rval = -1; 28917706Sjulian break; 29013546Sjulian } 29113546Sjulian 29217706Sjulian /* Unblock signals: */ 29317706Sjulian _thread_kern_sig_unblock(status); 29413546Sjulian } 29513546Sjulian 29613546Sjulian /* Return the completion status: */ 29713546Sjulian return (rval); 29813546Sjulian} 29913546Sjulian 30013546Sjulianint 30113546Sjulianpthread_cond_broadcast(pthread_cond_t * cond) 30213546Sjulian{ 30313546Sjulian int rval = 0; 30413546Sjulian int status; 30513546Sjulian pthread_t pthread; 30613546Sjulian 30713546Sjulian /* Block signals: */ 30813546Sjulian _thread_kern_sig_block(&status); 30913546Sjulian 31013546Sjulian /* Process according to condition variable type: */ 31117706Sjulian switch ((*cond)->c_type) { 31213546Sjulian /* Fast condition variable: */ 31313546Sjulian case COND_TYPE_FAST: 31413546Sjulian /* Enter a loop to bring all threads off the condition queue: */ 31517706Sjulian while ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) { 31613546Sjulian /* Allow the thread to run: */ 31713546Sjulian pthread->state = PS_RUNNING; 31813546Sjulian } 31913546Sjulian break; 32013546Sjulian 32113546Sjulian /* Trap invalid condition variable types: */ 32213546Sjulian default: 32313546Sjulian /* Return an invalid argument error: */ 32417706Sjulian errno = EINVAL; 32513546Sjulian rval = -1; 32613546Sjulian break; 32713546Sjulian } 32813546Sjulian 32913546Sjulian /* Unblock signals: */ 33013546Sjulian _thread_kern_sig_unblock(status); 33113546Sjulian 33213546Sjulian /* Return the completion status: */ 33313546Sjulian return (rval); 33413546Sjulian} 33513546Sjulian#endif 336