1/* 2 * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 *
| 1/* 2 * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 *
|
26 * $FreeBSD: head/lib/libthr/thread/thr_cond.c 177854 2008-04-02 08:33:42Z davidxu $
| 26 * $FreeBSD: head/lib/libthr/thread/thr_cond.c 211524 2010-08-20 05:15:39Z davidxu $
|
27 */ 28 29#include "namespace.h" 30#include <stdlib.h> 31#include <errno.h> 32#include <string.h> 33#include <pthread.h> 34#include <limits.h> 35#include "un-namespace.h" 36 37#include "thr_private.h" 38 39/* 40 * Prototypes 41 */ 42int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); 43int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 44 const struct timespec * abstime); 45static int cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); 46static int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, 47 const struct timespec *abstime, int cancel); 48static int cond_signal_common(pthread_cond_t *cond, int broadcast); 49 50/* 51 * Double underscore versions are cancellation points. Single underscore 52 * versions are not and are provided for libc internal usage (which 53 * shouldn't introduce cancellation points). 54 */ 55__weak_reference(__pthread_cond_wait, pthread_cond_wait); 56__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait); 57 58__weak_reference(_pthread_cond_init, pthread_cond_init); 59__weak_reference(_pthread_cond_destroy, pthread_cond_destroy); 60__weak_reference(_pthread_cond_signal, pthread_cond_signal); 61__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); 62 63static int 64cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 65{ 66 pthread_cond_t pcond; 67 int rval = 0; 68 69 if ((pcond = (pthread_cond_t) 70 calloc(1, sizeof(struct pthread_cond))) == NULL) { 71 rval = ENOMEM; 72 } else { 73 /* 74 * Initialise the condition variable structure: 75 */ 76 if (cond_attr == NULL || *cond_attr == NULL) { 77 pcond->c_pshared = 0; 78 pcond->c_clockid = CLOCK_REALTIME; 79 } else { 80 pcond->c_pshared = (*cond_attr)->c_pshared; 81 pcond->c_clockid = (*cond_attr)->c_clockid; 82 } 83 _thr_umutex_init(&pcond->c_lock); 84 *cond = pcond; 85 } 86 /* Return the completion status: */ 87 return (rval); 88} 89 90static int 91init_static(struct pthread *thread, pthread_cond_t *cond) 92{ 93 int ret; 94 95 THR_LOCK_ACQUIRE(thread, &_cond_static_lock); 96 97 if (*cond == NULL) 98 ret = cond_init(cond, NULL); 99 else 100 ret = 0; 101 102 THR_LOCK_RELEASE(thread, &_cond_static_lock); 103 104 return (ret); 105} 106 107int 108_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 109{ 110 111 *cond = NULL; 112 return (cond_init(cond, cond_attr)); 113} 114 115int 116_pthread_cond_destroy(pthread_cond_t *cond) 117{ 118 struct pthread *curthread = _get_curthread(); 119 struct pthread_cond *cv; 120 int rval = 0; 121 122 if (*cond == NULL) 123 rval = EINVAL; 124 else { 125 cv = *cond; 126 THR_UMUTEX_LOCK(curthread, &cv->c_lock); 127 /* 128 * NULL the caller's pointer now that the condition 129 * variable has been destroyed: 130 */ 131 *cond = NULL; 132 THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 133 134 /* 135 * Free the memory allocated for the condition 136 * variable structure: 137 */ 138 free(cv); 139 } 140 /* Return the completion status: */ 141 return (rval); 142} 143 144struct cond_cancel_info 145{ 146 pthread_mutex_t *mutex; 147 pthread_cond_t *cond; 148 int count; 149}; 150 151static void 152cond_cancel_handler(void *arg) 153{ 154 struct pthread *curthread = _get_curthread(); 155 struct cond_cancel_info *info = (struct cond_cancel_info *)arg; 156 pthread_cond_t cv; 157 158 if (info->cond != NULL) { 159 cv = *(info->cond); 160 THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 161 } 162 _mutex_cv_lock(info->mutex, info->count); 163} 164
| 27 */ 28 29#include "namespace.h" 30#include <stdlib.h> 31#include <errno.h> 32#include <string.h> 33#include <pthread.h> 34#include <limits.h> 35#include "un-namespace.h" 36 37#include "thr_private.h" 38 39/* 40 * Prototypes 41 */ 42int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); 43int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 44 const struct timespec * abstime); 45static int cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); 46static int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, 47 const struct timespec *abstime, int cancel); 48static int cond_signal_common(pthread_cond_t *cond, int broadcast); 49 50/* 51 * Double underscore versions are cancellation points. Single underscore 52 * versions are not and are provided for libc internal usage (which 53 * shouldn't introduce cancellation points). 54 */ 55__weak_reference(__pthread_cond_wait, pthread_cond_wait); 56__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait); 57 58__weak_reference(_pthread_cond_init, pthread_cond_init); 59__weak_reference(_pthread_cond_destroy, pthread_cond_destroy); 60__weak_reference(_pthread_cond_signal, pthread_cond_signal); 61__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); 62 63static int 64cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 65{ 66 pthread_cond_t pcond; 67 int rval = 0; 68 69 if ((pcond = (pthread_cond_t) 70 calloc(1, sizeof(struct pthread_cond))) == NULL) { 71 rval = ENOMEM; 72 } else { 73 /* 74 * Initialise the condition variable structure: 75 */ 76 if (cond_attr == NULL || *cond_attr == NULL) { 77 pcond->c_pshared = 0; 78 pcond->c_clockid = CLOCK_REALTIME; 79 } else { 80 pcond->c_pshared = (*cond_attr)->c_pshared; 81 pcond->c_clockid = (*cond_attr)->c_clockid; 82 } 83 _thr_umutex_init(&pcond->c_lock); 84 *cond = pcond; 85 } 86 /* Return the completion status: */ 87 return (rval); 88} 89 90static int 91init_static(struct pthread *thread, pthread_cond_t *cond) 92{ 93 int ret; 94 95 THR_LOCK_ACQUIRE(thread, &_cond_static_lock); 96 97 if (*cond == NULL) 98 ret = cond_init(cond, NULL); 99 else 100 ret = 0; 101 102 THR_LOCK_RELEASE(thread, &_cond_static_lock); 103 104 return (ret); 105} 106 107int 108_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 109{ 110 111 *cond = NULL; 112 return (cond_init(cond, cond_attr)); 113} 114 115int 116_pthread_cond_destroy(pthread_cond_t *cond) 117{ 118 struct pthread *curthread = _get_curthread(); 119 struct pthread_cond *cv; 120 int rval = 0; 121 122 if (*cond == NULL) 123 rval = EINVAL; 124 else { 125 cv = *cond; 126 THR_UMUTEX_LOCK(curthread, &cv->c_lock); 127 /* 128 * NULL the caller's pointer now that the condition 129 * variable has been destroyed: 130 */ 131 *cond = NULL; 132 THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 133 134 /* 135 * Free the memory allocated for the condition 136 * variable structure: 137 */ 138 free(cv); 139 } 140 /* Return the completion status: */ 141 return (rval); 142} 143 144struct cond_cancel_info 145{ 146 pthread_mutex_t *mutex; 147 pthread_cond_t *cond; 148 int count; 149}; 150 151static void 152cond_cancel_handler(void *arg) 153{ 154 struct pthread *curthread = _get_curthread(); 155 struct cond_cancel_info *info = (struct cond_cancel_info *)arg; 156 pthread_cond_t cv; 157 158 if (info->cond != NULL) { 159 cv = *(info->cond); 160 THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 161 } 162 _mutex_cv_lock(info->mutex, info->count); 163} 164
|
| 165/* 166 * Cancellation behaivor: 167 * Thread may be canceled at start, if thread is canceled, it means it 168 * did not get a wakeup from pthread_cond_signal(), otherwise, it is 169 * not canceled. 170 * Thread cancellation never cause wakeup from pthread_cond_signal() 171 * to be lost. 172 */
|
165static int 166cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, 167 const struct timespec *abstime, int cancel) 168{ 169 struct pthread *curthread = _get_curthread(); 170 struct timespec ts, ts2, *tsp; 171 struct cond_cancel_info info; 172 pthread_cond_t cv; 173 int ret = 0; 174 175 /* 176 * If the condition variable is statically initialized, 177 * perform the dynamic initialization: 178 */ 179 if (__predict_false(*cond == NULL && 180 (ret = init_static(curthread, cond)) != 0)) 181 return (ret); 182
| 173static int 174cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, 175 const struct timespec *abstime, int cancel) 176{ 177 struct pthread *curthread = _get_curthread(); 178 struct timespec ts, ts2, *tsp; 179 struct cond_cancel_info info; 180 pthread_cond_t cv; 181 int ret = 0; 182 183 /* 184 * If the condition variable is statically initialized, 185 * perform the dynamic initialization: 186 */ 187 if (__predict_false(*cond == NULL && 188 (ret = init_static(curthread, cond)) != 0)) 189 return (ret); 190
|
| 191 _thr_testcancel(curthread); 192
|
183 cv = *cond; 184 THR_UMUTEX_LOCK(curthread, &cv->c_lock); 185 ret = _mutex_cv_unlock(mutex, &info.count); 186 if (ret) { 187 THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 188 return (ret); 189 } 190 191 info.mutex = mutex; 192 info.cond = cond; 193 194 if (abstime != NULL) { 195 clock_gettime(cv->c_clockid, &ts); 196 TIMESPEC_SUB(&ts2, abstime, &ts); 197 tsp = &ts2; 198 } else 199 tsp = NULL; 200 201 if (cancel) { 202 THR_CLEANUP_PUSH(curthread, cond_cancel_handler, &info);
| 193 cv = *cond; 194 THR_UMUTEX_LOCK(curthread, &cv->c_lock); 195 ret = _mutex_cv_unlock(mutex, &info.count); 196 if (ret) { 197 THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 198 return (ret); 199 } 200 201 info.mutex = mutex; 202 info.cond = cond; 203 204 if (abstime != NULL) { 205 clock_gettime(cv->c_clockid, &ts); 206 TIMESPEC_SUB(&ts2, abstime, &ts); 207 tsp = &ts2; 208 } else 209 tsp = NULL; 210 211 if (cancel) { 212 THR_CLEANUP_PUSH(curthread, cond_cancel_handler, &info);
|
203 _thr_cancel_enter_defer(curthread);
| 213 _thr_cancel_enter_defer(curthread, 0);
|
204 ret = _thr_ucond_wait(&cv->c_kerncv, &cv->c_lock, tsp, 1); 205 info.cond = NULL;
| 214 ret = _thr_ucond_wait(&cv->c_kerncv, &cv->c_lock, tsp, 1); 215 info.cond = NULL;
|
206 _thr_cancel_leave_defer(curthread, ret);
| 216 _thr_cancel_leave_defer(curthread, (ret != 0));
|
207 THR_CLEANUP_POP(curthread, 0); 208 } else { 209 ret = _thr_ucond_wait(&cv->c_kerncv, &cv->c_lock, tsp, 0); 210 } 211 if (ret == EINTR) 212 ret = 0; 213 _mutex_cv_lock(mutex, info.count); 214 return (ret); 215} 216 217int 218_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 219{ 220 221 return (cond_wait_common(cond, mutex, NULL, 0)); 222} 223 224int 225__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 226{ 227 228 return (cond_wait_common(cond, mutex, NULL, 1)); 229} 230 231int 232_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 233 const struct timespec * abstime) 234{ 235 236 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 237 abstime->tv_nsec >= 1000000000) 238 return (EINVAL); 239 240 return (cond_wait_common(cond, mutex, abstime, 0)); 241} 242 243int 244__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 245 const struct timespec *abstime) 246{ 247 248 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 249 abstime->tv_nsec >= 1000000000) 250 return (EINVAL); 251 252 return (cond_wait_common(cond, mutex, abstime, 1)); 253} 254 255static int 256cond_signal_common(pthread_cond_t *cond, int broadcast) 257{ 258 struct pthread *curthread = _get_curthread(); 259 pthread_cond_t cv; 260 int ret = 0; 261 262 /* 263 * If the condition variable is statically initialized, perform dynamic 264 * initialization. 265 */ 266 if (__predict_false(*cond == NULL && 267 (ret = init_static(curthread, cond)) != 0)) 268 return (ret); 269 270 cv = *cond; 271 THR_UMUTEX_LOCK(curthread, &cv->c_lock); 272 if (!broadcast) 273 ret = _thr_ucond_signal(&cv->c_kerncv); 274 else 275 ret = _thr_ucond_broadcast(&cv->c_kerncv); 276 THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 277 return (ret); 278} 279 280int 281_pthread_cond_signal(pthread_cond_t * cond) 282{ 283 284 return (cond_signal_common(cond, 0)); 285} 286 287int 288_pthread_cond_broadcast(pthread_cond_t * cond) 289{ 290 291 return (cond_signal_common(cond, 1)); 292}
| 217 THR_CLEANUP_POP(curthread, 0); 218 } else { 219 ret = _thr_ucond_wait(&cv->c_kerncv, &cv->c_lock, tsp, 0); 220 } 221 if (ret == EINTR) 222 ret = 0; 223 _mutex_cv_lock(mutex, info.count); 224 return (ret); 225} 226 227int 228_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 229{ 230 231 return (cond_wait_common(cond, mutex, NULL, 0)); 232} 233 234int 235__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 236{ 237 238 return (cond_wait_common(cond, mutex, NULL, 1)); 239} 240 241int 242_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 243 const struct timespec * abstime) 244{ 245 246 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 247 abstime->tv_nsec >= 1000000000) 248 return (EINVAL); 249 250 return (cond_wait_common(cond, mutex, abstime, 0)); 251} 252 253int 254__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 255 const struct timespec *abstime) 256{ 257 258 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 259 abstime->tv_nsec >= 1000000000) 260 return (EINVAL); 261 262 return (cond_wait_common(cond, mutex, abstime, 1)); 263} 264 265static int 266cond_signal_common(pthread_cond_t *cond, int broadcast) 267{ 268 struct pthread *curthread = _get_curthread(); 269 pthread_cond_t cv; 270 int ret = 0; 271 272 /* 273 * If the condition variable is statically initialized, perform dynamic 274 * initialization. 275 */ 276 if (__predict_false(*cond == NULL && 277 (ret = init_static(curthread, cond)) != 0)) 278 return (ret); 279 280 cv = *cond; 281 THR_UMUTEX_LOCK(curthread, &cv->c_lock); 282 if (!broadcast) 283 ret = _thr_ucond_signal(&cv->c_kerncv); 284 else 285 ret = _thr_ucond_broadcast(&cv->c_kerncv); 286 THR_UMUTEX_UNLOCK(curthread, &cv->c_lock); 287 return (ret); 288} 289 290int 291_pthread_cond_signal(pthread_cond_t * cond) 292{ 293 294 return (cond_signal_common(cond, 0)); 295} 296 297int 298_pthread_cond_broadcast(pthread_cond_t * cond) 299{ 300 301 return (cond_signal_common(cond, 1)); 302}
|