diff options
Diffstat (limited to 'mit-pthreads/pthreads/cond.c')
-rw-r--r-- | mit-pthreads/pthreads/cond.c | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/mit-pthreads/pthreads/cond.c b/mit-pthreads/pthreads/cond.c new file mode 100644 index 00000000000..8dacd0397ce --- /dev/null +++ b/mit-pthreads/pthreads/cond.c @@ -0,0 +1,437 @@ +/* ==== cond.c ============================================================ + * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Chris Provenzano. + * 4. The name of Chris Provenzano may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Description : Condition variable functions. + * + * 1.00 93/10/28 proven + * -Started coding this file. + */ + +#ifndef lint +static const char rcsid[] = "$Id$"; +#endif + +#include <pthread.h> +#include <sys/time.h> +#include <stdlib.h> +#include <timers.h> +#include <errno.h> + +#ifndef ETIME +#define ETIME ETIMEDOUT +#endif + +/* ========================================================================== + * pthread_cond_is_debug() + * + * Check that cond is a debug cond and if so returns entry number into + * array of debug condes. + */ +static int pthread_cond_debug_count = 0; +static pthread_cond_t ** pthread_cond_debug_ptrs = NULL; +static pthread_mutex_t pthread_cond_debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +static inline int pthread_cond_is_debug(pthread_cond_t * cond) +{ + int i; + + for (i = 0; i < pthread_cond_debug_count; i++) { + if (pthread_cond_debug_ptrs[i] == cond) { + return(i); + } + } + return(NOTOK); +} +/* ========================================================================== + * pthread_cond_init() + * + * In this implementation I don't need to allocate memory. + * ENOMEM, EAGAIN should never be returned. Arch that have + * weird constraints may need special coding. + */ +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) +{ + enum pthread_condtype type; + + /* Only check if attr specifies some mutex type other than fast */ + if ((cond_attr) && (cond_attr->c_type != COND_TYPE_FAST)) { + if (cond_attr->c_type >= COND_TYPE_MAX) { + return(EINVAL); + } + type = cond_attr->c_type; + } else { + type = COND_TYPE_FAST; + } + + switch (type) { + case COND_TYPE_FAST: + case COND_TYPE_COUNTING_FAST: + break; + case COND_TYPE_DEBUG: + pthread_mutex_lock(&pthread_cond_debug_mutex); + if (pthread_cond_is_debug(cond) == NOTOK) { + pthread_cond_t ** new; + + if ((new = (pthread_cond_t **)realloc(pthread_cond_debug_ptrs, + (pthread_cond_debug_count + 1) * (sizeof(void *)))) == NULL) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + return(ENOMEM); + } + pthread_cond_debug_ptrs = new; + pthread_cond_debug_ptrs[pthread_cond_debug_count++] = cond; + } else { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + return(EBUSY); + } + pthread_mutex_unlock(&pthread_cond_debug_mutex); + break; + case COND_TYPE_STATIC_FAST: + defualt: + return(EINVAL); + break; + } + + /* Set all other paramaters */ + pthread_queue_init(&cond->c_queue); + cond->c_flags |= COND_FLAGS_INITED; + cond->c_type = type; + return(OK); +} + +/* ========================================================================== + * pthread_cond_destroy() + */ +int pthread_cond_destroy(pthread_cond_t *cond) +{ + int i; + + /* Only check if cond is of type other than fast */ + switch(cond->c_type) { + case COND_TYPE_FAST: + case COND_TYPE_COUNTING_FAST: + break; + case COND_TYPE_DEBUG: + if (pthread_queue_get(&(cond->c_queue))) { + return(EBUSY); + } + pthread_mutex_lock(&pthread_cond_debug_mutex); + if ((i = pthread_cond_is_debug(cond)) == NOTOK) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + return(EINVAL); + } + + /* Remove the cond from the list of debug condition variables */ + pthread_cond_debug_ptrs[i] = + pthread_cond_debug_ptrs[--pthread_cond_debug_count]; + pthread_cond_debug_ptrs[pthread_cond_debug_count] = NULL; + pthread_mutex_unlock(&pthread_cond_debug_mutex); + break; + case COND_TYPE_STATIC_FAST: + default: + return(EINVAL); + break; + } + + /* Cleanup cond, others might want to use it. */ + pthread_queue_init(&cond->c_queue); + cond->c_flags = 0; + return(OK); +} + +/* ========================================================================== + * pthread_cond_wait() + */ +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + int rval; + + pthread_sched_prevent(); + switch (cond->c_type) { + case COND_TYPE_DEBUG: + pthread_mutex_lock(&pthread_cond_debug_mutex); + if (pthread_cond_is_debug(cond) == NOTOK) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + pthread_sched_resume(); + return(EINVAL); + } + pthread_mutex_unlock(&pthread_cond_debug_mutex); + + /* + * Fast condition variables do not check for any error conditions. + */ + case COND_TYPE_FAST: + case COND_TYPE_STATIC_FAST: + pthread_queue_enq(&cond->c_queue, pthread_run); + pthread_mutex_unlock(mutex); + + pthread_run->data.mutex = mutex; + + SET_PF_WAIT_EVENT(pthread_run); + SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + CLEAR_PF_DONE_EVENT(pthread_run); + + pthread_run->data.mutex = NULL; + + rval = pthread_mutex_lock(mutex); + return(rval); + break; + case COND_TYPE_COUNTING_FAST: + { + int count = mutex->m_data.m_count; + + pthread_queue_enq(&cond->c_queue, pthread_run); + pthread_mutex_unlock(mutex); + mutex->m_data.m_count = 1; + + pthread_run->data.mutex = mutex; + + SET_PF_WAIT_EVENT(pthread_run); + SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + CLEAR_PF_DONE_EVENT(pthread_run); + + pthread_run->data.mutex = NULL; + + rval = pthread_mutex_lock(mutex); + mutex->m_data.m_count = count; + return(rval); + break; + } + default: + rval = EINVAL; + break; + } + pthread_sched_resume(); + return(rval); +} + +/* ========================================================================== + * pthread_cond_timedwait() + */ +int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec * abstime) +{ + struct timespec current_time, new_time; + int rval = OK; + + pthread_sched_prevent(); + machdep_gettimeofday(& current_time); + + switch (cond->c_type) { + case COND_TYPE_DEBUG: + pthread_mutex_lock(&pthread_cond_debug_mutex); + if (pthread_cond_is_debug(cond) == NOTOK) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + pthread_sched_resume(); + return(EINVAL); + } + pthread_mutex_unlock(&pthread_cond_debug_mutex); + + /* + * Fast condition variables do not check for any error conditions. + */ + case COND_TYPE_FAST: + case COND_TYPE_STATIC_FAST: + + /* Set pthread wakeup time*/ + pthread_run->wakeup_time = *abstime; + + /* Install us on the sleep queue */ + sleep_schedule (¤t_time, &(pthread_run->wakeup_time)); + + pthread_queue_enq(&cond->c_queue, pthread_run); + SET_PF_WAIT_EVENT(pthread_run); + pthread_mutex_unlock(mutex); + + pthread_run->data.mutex = mutex; + + SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + + pthread_run->data.mutex = NULL; + + /* Remove ourselves from sleep queue. If we fail then we timedout */ + if (sleep_cancel(pthread_run) == NOTOK) { + SET_ERRNO(ETIME); + rval = ETIME; + } + + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_mutex_lock(mutex); + return(rval); + break; + case COND_TYPE_COUNTING_FAST: + { + int count = mutex->m_data.m_count; + + /* Set pthread wakeup time*/ + pthread_run->wakeup_time = *abstime; + + /* Install us on the sleep queue */ + sleep_schedule (¤t_time, &(pthread_run->wakeup_time)); + + pthread_queue_enq(&cond->c_queue, pthread_run); + SET_PF_WAIT_EVENT(pthread_run); + pthread_mutex_unlock(mutex); + + pthread_run->data.mutex = mutex; + + SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ + /* Reschedule will unlock pthread_run */ + pthread_resched_resume(PS_COND_WAIT); + CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ + + pthread_run->data.mutex = NULL; + + /* Remove ourselves from sleep queue. If we fail then we timedout */ + if (sleep_cancel(pthread_run) == NOTOK) { + SET_ERRNO(ETIME); + rval = ETIME; + } + + CLEAR_PF_DONE_EVENT(pthread_run); + pthread_mutex_lock(mutex); + mutex->m_data.m_count = count; + return(rval); + break; + } + default: + rval = EINVAL; + break; + } + pthread_sched_resume(); + return(rval); +} + +/* ========================================================================== + * pthread_cond_signal() + */ +int pthread_cond_signal(pthread_cond_t *cond) +{ + struct pthread *pthread; + int rval; + + pthread_sched_prevent(); + switch (cond->c_type) { + case COND_TYPE_DEBUG: + pthread_mutex_lock(&pthread_cond_debug_mutex); + if (pthread_cond_is_debug(cond) == NOTOK) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + pthread_sched_resume(); + return(EINVAL); + } + pthread_mutex_unlock(&pthread_cond_debug_mutex); + + case COND_TYPE_FAST: + case COND_TYPE_STATIC_FAST: + if (pthread = pthread_queue_deq(&cond->c_queue)) { + if ((SET_PF_DONE_EVENT(pthread)) == OK) { + pthread_sched_other_resume(pthread); + } else { + pthread_sched_resume(); + } + return(OK); + } + rval = OK; + break; + default: + rval = EINVAL; + break; + } + pthread_sched_resume(); + return(rval); +} + +/* ========================================================================== + * pthread_cond_broadcast() + * + * Not much different then the above routine. + */ +int pthread_cond_broadcast(pthread_cond_t *cond) +{ + struct pthread * pthread, * high_pthread, * low_pthread; + int rval; + + pthread_sched_prevent(); + switch (cond->c_type) { + case COND_TYPE_DEBUG: + pthread_mutex_lock(&pthread_cond_debug_mutex); + if (pthread_cond_is_debug(cond) == NOTOK) { + pthread_mutex_unlock(&pthread_cond_debug_mutex); + pthread_sched_resume(); + return(EINVAL); + } + pthread_mutex_unlock(&pthread_cond_debug_mutex); + + case COND_TYPE_FAST: + case COND_TYPE_STATIC_FAST: + if (pthread = pthread_queue_deq(&cond->c_queue)) { + pthread->state = PS_RUNNING; + high_pthread = pthread; + + while (pthread = pthread_queue_deq(&cond->c_queue)) { + if (pthread->pthread_priority > + high_pthread->pthread_priority) { + low_pthread = high_pthread; + high_pthread = pthread; + } else { + low_pthread = pthread; + } + if ((SET_PF_DONE_EVENT(low_pthread)) == OK) { + pthread_prio_queue_enq(pthread_current_prio_queue, + low_pthread); + low_pthread->state = PS_RUNNING; + } + } + if ((SET_PF_DONE_EVENT(high_pthread)) == OK) { + pthread_sched_other_resume(high_pthread); + } else { + pthread_sched_resume(); + } + return(OK); + } + rval = OK; + break; + default: + rval = EINVAL; + break; + } + pthread_sched_resume(); + return(rval); +} + |