thr_cond.c revision 165110
1100966Siwasaki/* 2100966Siwasaki * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 3100966Siwasaki * All rights reserved. 4100966Siwasaki * 5167802Sjkim * Redistribution and use in source and binary forms, with or without 6100966Siwasaki * modification, are permitted provided that the following conditions 7100966Siwasaki * are met: 8100966Siwasaki * 1. Redistributions of source code must retain the above copyright 9100966Siwasaki * notice unmodified, this list of conditions, and the following 10100966Siwasaki * disclaimer. 11100966Siwasaki * 2. Redistributions in binary form must reproduce the above copyright 12100966Siwasaki * notice, this list of conditions and the following disclaimer in the 13167802Sjkim * documentation and/or other materials provided with the distribution. 14100966Siwasaki * 15100966Siwasaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16100966Siwasaki * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17100966Siwasaki * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18100966Siwasaki * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19100966Siwasaki * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20100966Siwasaki * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21100966Siwasaki * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22100966Siwasaki * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23100966Siwasaki * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24100966Siwasaki * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25100966Siwasaki * 26100966Siwasaki * $FreeBSD: head/lib/libthr/thread/thr_cond.c 165110 2006-12-12 03:08:49Z davidxu $ 27100966Siwasaki */ 28100966Siwasaki 29100966Siwasaki#include "namespace.h" 30100966Siwasaki#include <stdlib.h> 31100966Siwasaki#include <errno.h> 32100966Siwasaki#include <string.h> 33100966Siwasaki#include <pthread.h> 34100966Siwasaki#include <limits.h> 35100966Siwasaki#include "un-namespace.h" 36100966Siwasaki 37100966Siwasaki#include "thr_private.h" 38100966Siwasaki 39100966Siwasaki/* 40100966Siwasaki * Prototypes 41100966Siwasaki */ 42100966Siwasakiint __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); 43100966Siwasakiint __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 44100966Siwasaki const struct timespec * abstime); 45100966Siwasakistatic int cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); 46100966Siwasakistatic int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, 47100966Siwasaki const struct timespec *abstime, int cancel); 48100966Siwasakistatic int cond_signal_common(pthread_cond_t *cond, int broadcast); 49100966Siwasaki 50100966Siwasaki/* 51100966Siwasaki * Double underscore versions are cancellation points. Single underscore 52100966Siwasaki * versions are not and are provided for libc internal usage (which 53100966Siwasaki * shouldn't introduce cancellation points). 54100966Siwasaki */ 55100966Siwasaki__weak_reference(__pthread_cond_wait, pthread_cond_wait); 56100966Siwasaki__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait); 57100966Siwasaki 58100966Siwasaki__weak_reference(_pthread_cond_init, pthread_cond_init); 59100966Siwasaki__weak_reference(_pthread_cond_destroy, pthread_cond_destroy); 60100966Siwasaki__weak_reference(_pthread_cond_signal, pthread_cond_signal); 61100966Siwasaki__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); 62100966Siwasaki 63100966Siwasakistatic int 64100966Siwasakicond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 65100966Siwasaki{ 66100966Siwasaki pthread_cond_t pcond; 67100966Siwasaki int rval = 0; 68100966Siwasaki 69100966Siwasaki if ((pcond = (pthread_cond_t) 70100966Siwasaki calloc(1, sizeof(struct pthread_cond))) == NULL) { 71100966Siwasaki rval = ENOMEM; 72100966Siwasaki } else { 73100966Siwasaki /* 74100966Siwasaki * Initialise the condition variable structure: 75100966Siwasaki */ 76100966Siwasaki if (cond_attr == NULL || *cond_attr == NULL) { 77100966Siwasaki pcond->c_pshared = 0; 78100966Siwasaki pcond->c_clockid = CLOCK_REALTIME; 79100966Siwasaki } else { 80100966Siwasaki pcond->c_pshared = (*cond_attr)->c_pshared; 81100966Siwasaki pcond->c_clockid = (*cond_attr)->c_clockid; 82100966Siwasaki } 83100966Siwasaki _thr_umutex_init(&pcond->c_lock); 84100966Siwasaki *cond = pcond; 85100966Siwasaki } 86100966Siwasaki /* Return the completion status: */ 87100966Siwasaki return (rval); 88100966Siwasaki} 89100966Siwasaki 90100966Siwasakistatic int 91100966Siwasakiinit_static(struct pthread *thread, pthread_cond_t *cond) 92100966Siwasaki{ 93100966Siwasaki int ret; 94100966Siwasaki 95100966Siwasaki THR_LOCK_ACQUIRE(thread, &_cond_static_lock); 96100966Siwasaki 97100966Siwasaki if (*cond == NULL) 98100966Siwasaki ret = cond_init(cond, NULL); 99100966Siwasaki else 100100966Siwasaki ret = 0; 101100966Siwasaki 102100966Siwasaki THR_LOCK_RELEASE(thread, &_cond_static_lock); 103100966Siwasaki 104100966Siwasaki return (ret); 105100966Siwasaki} 106100966Siwasaki 107100966Siwasakiint 108100966Siwasaki_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 109100966Siwasaki{ 110100966Siwasaki 111100966Siwasaki *cond = NULL; 112100966Siwasaki return (cond_init(cond, cond_attr)); 113100966Siwasaki} 114100966Siwasaki 115100966Siwasakiint 116100966Siwasaki_pthread_cond_destroy(pthread_cond_t *cond) 117100966Siwasaki{ 118100966Siwasaki struct pthread *curthread = _get_curthread(); 119100966Siwasaki struct pthread_cond *cv; 120100966Siwasaki int rval = 0; 121151600Sobrien 122151600Sobrien if (*cond == NULL) 123151600Sobrien rval = EINVAL; 124100966Siwasaki else { 125100966Siwasaki cv = *cond; 126100966Siwasaki THR_UMUTEX_LOCK(curthread, &cv->c_lock); 127100966Siwasaki /* 128100966Siwasaki * NULL the caller's pointer now that the condition 129100966Siwasaki * variable has been destroyed: 130100966Siwasaki */ 131100966Siwasaki *cond = NULL; 132100966Siwasaki THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 133100966Siwasaki 134100966Siwasaki /* 135151937Sjkim * Free the memory allocated for the condition 136151937Sjkim * variable structure: 137100966Siwasaki */ 138100966Siwasaki free(cv); 139151937Sjkim } 140100966Siwasaki /* Return the completion status: */ 141100966Siwasaki return (rval); 142100966Siwasaki} 143100966Siwasaki 144100966Siwasakistruct cond_cancel_info 145100966Siwasaki{ 146100966Siwasaki pthread_mutex_t *mutex; 147100966Siwasaki pthread_cond_t *cond; 148100966Siwasaki int count; 149100966Siwasaki}; 150100966Siwasaki 151100966Siwasakistatic void 152100966Siwasakicond_cancel_handler(void *arg) 153100966Siwasaki{ 154100966Siwasaki struct pthread *curthread = _get_curthread(); 155100966Siwasaki struct cond_cancel_info *info = (struct cond_cancel_info *)arg; 156100966Siwasaki pthread_cond_t cv; 157100966Siwasaki 158100966Siwasaki if (info->cond != NULL) { 159100966Siwasaki cv = *(info->cond); 160100966Siwasaki THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 161100966Siwasaki } 162100966Siwasaki _mutex_cv_lock(info->mutex, info->count); 163167802Sjkim} 164100966Siwasaki 165100966Siwasakistatic int 166100966Siwasakicond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, 167100966Siwasaki const struct timespec *abstime, int cancel) 168100966Siwasaki{ 169100966Siwasaki struct pthread *curthread = _get_curthread(); 170100966Siwasaki struct timespec ts, ts2, *tsp; 171100966Siwasaki struct cond_cancel_info info; 172100966Siwasaki pthread_cond_t cv; 173100966Siwasaki int ret = 0; 174100966Siwasaki 175100966Siwasaki /* 176100966Siwasaki * If the condition variable is statically initialized, 177100966Siwasaki * perform the dynamic initialization: 178100966Siwasaki */ 179100966Siwasaki if (__predict_false(*cond == NULL && 180100966Siwasaki (ret = init_static(curthread, cond)) != 0)) 181100966Siwasaki return (ret); 182100966Siwasaki 183100966Siwasaki cv = *cond; 184100966Siwasaki THR_UMUTEX_LOCK(curthread, &cv->c_lock); 185100966Siwasaki ret = _mutex_cv_unlock(mutex, &info.count); 186100966Siwasaki if (ret) { 187100966Siwasaki THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 188100966Siwasaki return (ret); 189100966Siwasaki } 190100966Siwasaki 191100966Siwasaki info.mutex = mutex; 192100966Siwasaki info.cond = cond; 193100966Siwasaki 194100966Siwasaki if (abstime != NULL) { 195100966Siwasaki clock_gettime(cv->c_clockid, &ts); 196100966Siwasaki TIMESPEC_SUB(&ts2, abstime, &ts); 197167802Sjkim tsp = &ts2; 198100966Siwasaki } else 199100966Siwasaki tsp = NULL; 200100966Siwasaki 201100966Siwasaki if (cancel) { 202100966Siwasaki THR_CLEANUP_PUSH(curthread, cond_cancel_handler, &info); 203100966Siwasaki _thr_cancel_enter_defer(curthread); 204100966Siwasaki ret = _thr_ucond_wait(&cv->c_kerncv, &cv->c_lock, tsp, 1); 205100966Siwasaki info.cond = NULL; 206100966Siwasaki _thr_cancel_leave_defer(curthread, ret); 207100966Siwasaki THR_CLEANUP_POP(curthread, 0); 208100966Siwasaki } else { 209100966Siwasaki ret = _thr_ucond_wait(&cv->c_kerncv, &cv->c_lock, tsp, 0); 210167802Sjkim } 211167802Sjkim if (ret == EINTR) 212100966Siwasaki ret = 0; 213100966Siwasaki _mutex_cv_lock(mutex, info.count); 214100966Siwasaki return (ret); 215100966Siwasaki} 216100966Siwasaki 217100966Siwasakiint 218100966Siwasaki_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 219100966Siwasaki{ 220100966Siwasaki 221100966Siwasaki return (cond_wait_common(cond, mutex, NULL, 0)); 222100966Siwasaki} 223100966Siwasaki 224100966Siwasakiint 225100966Siwasaki__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 226100966Siwasaki{ 227167802Sjkim 228100966Siwasaki return (cond_wait_common(cond, mutex, NULL, 1)); 229167802Sjkim} 230100966Siwasaki 231100966Siwasakiint 232100966Siwasaki_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 233100966Siwasaki const struct timespec * abstime) 234100966Siwasaki{ 235128212Snjl 236128212Snjl if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 237100966Siwasaki abstime->tv_nsec >= 1000000000) 238100966Siwasaki return (EINVAL); 239128212Snjl 240100966Siwasaki return (cond_wait_common(cond, mutex, abstime, 0)); 241100966Siwasaki} 242100966Siwasaki 243100966Siwasakiint 244100966Siwasaki__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 245100966Siwasaki const struct timespec *abstime) 246100966Siwasaki{ 247100966Siwasaki 248100966Siwasaki if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 249100966Siwasaki abstime->tv_nsec >= 1000000000) 250100966Siwasaki return (EINVAL); 251100966Siwasaki 252100966Siwasaki return (cond_wait_common(cond, mutex, abstime, 1)); 253100966Siwasaki} 254100966Siwasaki 255100966Siwasakistatic int 256100966Siwasakicond_signal_common(pthread_cond_t *cond, int broadcast) 257100966Siwasaki{ 258167802Sjkim struct pthread *curthread = _get_curthread(); 259100966Siwasaki pthread_cond_t cv; 260100966Siwasaki int ret = 0; 261100966Siwasaki 262100966Siwasaki /* 263167802Sjkim * If the condition variable is statically initialized, perform dynamic 264100966Siwasaki * initialization. 265100966Siwasaki */ 266167802Sjkim if (__predict_false(*cond == NULL && 267129684Snjl (ret = init_static(curthread, cond)) != 0)) 268167802Sjkim return (ret); 269167802Sjkim 270167802Sjkim cv = *cond; 271167802Sjkim THR_UMUTEX_LOCK(curthread, &cv->c_lock); 272167802Sjkim if (!broadcast) 273167802Sjkim ret = _thr_ucond_signal(&cv->c_kerncv); 274167802Sjkim else 275167802Sjkim ret = _thr_ucond_broadcast(&cv->c_kerncv); 276167802Sjkim THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 277167802Sjkim return (ret); 278167802Sjkim} 279167802Sjkim 280167802Sjkimint 281167802Sjkim_pthread_cond_signal(pthread_cond_t * cond) 282167802Sjkim{ 283167802Sjkim 284167802Sjkim return (cond_signal_common(cond, 0)); 285167802Sjkim} 286100966Siwasaki 287167802Sjkimint 288167802Sjkim_pthread_cond_broadcast(pthread_cond_t * cond) 289100966Siwasaki{ 290100966Siwasaki 291100966Siwasaki return (cond_signal_common(cond, 1)); 292100966Siwasaki} 293100966Siwasaki