1 /* $NetBSD: pthread_cond.c,v 1.42 2008/04/28 20:23:01 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Nathan J. Williams and Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: pthread_cond.c,v 1.42 2008/04/28 20:23:01 martin Exp $"); 34 35 #include <errno.h> 36 #include <sys/time.h> 37 #include <sys/types.h> 38 39 #include "pthread.h" 40 #include "pthread_int.h" 41 42 int _sys_nanosleep(const struct timespec *, struct timespec *); 43 44 extern int pthread__started; 45 46 static int pthread_cond_wait_nothread(pthread_t, pthread_mutex_t *, 47 const struct timespec *); 48 49 __strong_alias(__libc_cond_init,pthread_cond_init) 50 __strong_alias(__libc_cond_signal,pthread_cond_signal) 51 __strong_alias(__libc_cond_broadcast,pthread_cond_broadcast) 52 __strong_alias(__libc_cond_wait,pthread_cond_wait) 53 __strong_alias(__libc_cond_timedwait,pthread_cond_timedwait) 54 __strong_alias(__libc_cond_destroy,pthread_cond_destroy) 55 56 int 57 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) 58 { 59 60 pthread__error(EINVAL, "Invalid condition variable attribute", 61 (attr == NULL) || (attr->ptca_magic == _PT_CONDATTR_MAGIC)); 62 63 cond->ptc_magic = _PT_COND_MAGIC; 64 pthread_lockinit(&cond->ptc_lock); 65 PTQ_INIT(&cond->ptc_waiters); 66 cond->ptc_mutex = NULL; 67 68 return 0; 69 } 70 71 72 int 73 pthread_cond_destroy(pthread_cond_t *cond) 74 { 75 76 pthread__error(EINVAL, "Invalid condition variable", 77 cond->ptc_magic == _PT_COND_MAGIC); 78 pthread__error(EBUSY, "Destroying condition variable in use", 79 cond->ptc_mutex == NULL); 80 81 cond->ptc_magic = _PT_COND_DEAD; 82 83 return 0; 84 } 85 86 87 int 88 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 89 { 90 pthread_t self; 91 92 pthread__error(EINVAL, "Invalid condition variable", 93 cond->ptc_magic == _PT_COND_MAGIC); 94 pthread__error(EINVAL, "Invalid mutex", 95 mutex->ptm_magic == _PT_MUTEX_MAGIC); 96 pthread__error(EPERM, "Mutex not locked in condition wait", 97 mutex->ptm_owner != NULL); 98 99 self = pthread__self(); 100 101 /* Just hang out for a while if threads aren't running yet. */ 102 if (__predict_false(pthread__started == 0)) 103 return pthread_cond_wait_nothread(self, mutex, NULL); 104 105 if (__predict_false(self->pt_cancel)) 106 pthread__cancelled(); 107 108 /* 109 * Note this thread as waiting on the CV. To ensure good 110 * performance it's critical that the spinlock is held for 111 * as short a time as possible - that means no system calls. 112 */ 113 pthread__spinlock(self, &cond->ptc_lock); 114 #ifdef ERRORCHECK 115 if (cond->ptc_mutex == NULL) 116 cond->ptc_mutex = mutex; 117 else { 118 pthread__error(EINVAL, 119 "Multiple mutexes used for condition wait", 120 cond->ptc_mutex == mutex); 121 } 122 #else 123 cond->ptc_mutex = mutex; 124 #endif 125 PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep); 126 self->pt_signalled = 0; 127 self->pt_sleeponq = 1; 128 self->pt_sleepobj = &cond->ptc_waiters; 129 pthread__spinunlock(self, &cond->ptc_lock); 130 131 /* 132 * Before releasing the mutex, note that this thread is 133 * about to block by setting the willpark flag. If there 134 * is a single waiter on the mutex, setting the flag will 135 * defer restarting it until calling into the kernel to 136 * park, saving a syscall & involuntary context switch. 137 */ 138 self->pt_willpark = 1; 139 pthread_mutex_unlock(mutex); 140 (void)pthread__park(self, &cond->ptc_lock, &cond->ptc_waiters, 141 NULL, 1, __UNVOLATILE(&mutex->ptm_waiters)); 142 pthread_mutex_lock(mutex); 143 144 /* 145 * If we awoke abnormally the waiters list will have been 146 * made empty by the current thread (in pthread__park()), 147 * so we can check the value safely without locking. 148 * 149 * Otherwise, it will have been updated by whichever thread 150 * last issued a wakeup. 151 */ 152 if (PTQ_EMPTY(&cond->ptc_waiters) && cond->ptc_mutex != NULL) { 153 pthread__spinlock(self, &cond->ptc_lock); 154 if (PTQ_EMPTY(&cond->ptc_waiters)) 155 cond->ptc_mutex = NULL; 156 pthread__spinunlock(self, &cond->ptc_lock); 157 } 158 159 /* 160 * If we have cancelled then exit. POSIX dictates that the 161 * mutex must be held when we action the cancellation. 162 */ 163 if (__predict_false(self->pt_cancel)) { 164 if (self->pt_signalled) 165 pthread_cond_signal(cond); 166 pthread__cancelled(); 167 } 168 169 return 0; 170 } 171 172 int 173 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 174 const struct timespec *abstime) 175 { 176 pthread_t self; 177 int retval; 178 179 pthread__error(EINVAL, "Invalid condition variable", 180 cond->ptc_magic == _PT_COND_MAGIC); 181 pthread__error(EINVAL, "Invalid mutex", 182 mutex->ptm_magic == _PT_MUTEX_MAGIC); 183 pthread__error(EPERM, "Mutex not locked in condition wait", 184 mutex->ptm_owner != NULL); 185 pthread__error(EINVAL, "Invalid wait time", 186 (abstime->tv_sec >= 0) && 187 (abstime->tv_nsec >= 0) && (abstime->tv_nsec < 1000000000)); 188 189 self = pthread__self(); 190 191 /* Just hang out for a while if threads aren't running yet. */ 192 if (__predict_false(pthread__started == 0)) 193 return pthread_cond_wait_nothread(self, mutex, abstime); 194 195 if (__predict_false(self->pt_cancel)) 196 pthread__cancelled(); 197 198 /* 199 * Note this thread as waiting on the CV. To ensure good 200 * performance it's critical that the spinlock is held for 201 * as short a time as possible - that means no system calls. 202 */ 203 pthread__spinlock(self, &cond->ptc_lock); 204 #ifdef ERRORCHECK 205 if (cond->ptc_mutex == NULL) 206 cond->ptc_mutex = mutex; 207 else { 208 pthread__error(EINVAL, 209 "Multiple mutexes used for condition wait", 210 cond->ptc_mutex == mutex); 211 } 212 #else 213 cond->ptc_mutex = mutex; 214 #endif 215 PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep); 216 self->pt_signalled = 0; 217 self->pt_sleeponq = 1; 218 self->pt_sleepobj = &cond->ptc_waiters; 219 pthread__spinunlock(self, &cond->ptc_lock); 220 221 /* 222 * Before releasing the mutex, note that this thread is 223 * about to block by setting the willpark flag. If there 224 * is a single waiter on the mutex, setting the flag will 225 * defer restarting it until calling into the kernel to 226 * park, saving a syscall & involuntary context switch. 227 */ 228 self->pt_willpark = 1; 229 pthread_mutex_unlock(mutex); 230 retval = pthread__park(self, &cond->ptc_lock, &cond->ptc_waiters, 231 abstime, 1, __UNVOLATILE(&mutex->ptm_waiters)); 232 pthread_mutex_lock(mutex); 233 234 /* 235 * If we awoke abnormally the waiters list will have been 236 * made empty by the current thread (in pthread__park()), 237 * so we can check the value safely without locking. 238 * 239 * Otherwise, it will have been updated by whichever thread 240 * last issued a wakeup. 241 */ 242 if (PTQ_EMPTY(&cond->ptc_waiters) && cond->ptc_mutex != NULL) { 243 pthread__spinlock(self, &cond->ptc_lock); 244 if (PTQ_EMPTY(&cond->ptc_waiters)) 245 cond->ptc_mutex = NULL; 246 pthread__spinunlock(self, &cond->ptc_lock); 247 } 248 249 /* 250 * If we have cancelled then exit. POSIX dictates that the 251 * mutex must be held when we action the cancellation. 252 */ 253 if (__predict_false(self->pt_cancel | retval)) { 254 if (self->pt_signalled) 255 pthread_cond_signal(cond); 256 if (self->pt_cancel) 257 pthread__cancelled(); 258 } 259 260 return retval; 261 } 262 263 int 264 pthread_cond_signal(pthread_cond_t *cond) 265 { 266 pthread_t self, signaled; 267 pthread_mutex_t *mutex; 268 269 pthread__error(EINVAL, "Invalid condition variable", 270 cond->ptc_magic == _PT_COND_MAGIC); 271 272 if (PTQ_EMPTY(&cond->ptc_waiters)) 273 return 0; 274 275 self = pthread__self(); 276 pthread__spinlock(self, &cond->ptc_lock); 277 278 /* 279 * Find a thread that is still blocked (no pending wakeup). 280 * A wakeup can be pending if we have interrupted unpark_all 281 * as it releases the interlock. 282 */ 283 PTQ_FOREACH(signaled, &cond->ptc_waiters, pt_sleep) { 284 if (signaled->pt_sleepobj != NULL) 285 break; 286 } 287 if (__predict_false(signaled == NULL)) { 288 cond->ptc_mutex = NULL; 289 pthread__spinunlock(self, &cond->ptc_lock); 290 return 0; 291 } 292 293 /* 294 * Pull the thread off the queue, and set pt_signalled. 295 * 296 * After resuming execution, the thread must check to see if it 297 * has been restarted as a result of pthread_cond_signal(). If it 298 * has, but cannot take the wakeup (because of eg a timeout) then 299 * try to ensure that another thread sees it. This is necessary 300 * because there may be multiple waiters, and at least one should 301 * take the wakeup if possible. 302 */ 303 PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep); 304 mutex = cond->ptc_mutex; 305 if (PTQ_EMPTY(&cond->ptc_waiters)) 306 cond->ptc_mutex = NULL; 307 signaled->pt_signalled = 1; 308 309 /* 310 * For all valid uses of pthread_cond_signal(), the caller will 311 * hold the mutex that the target is using to synchronize with. 312 * To avoid the target awakening and immediatley blocking on the 313 * mutex, transfer the thread to be awoken to the current thread's 314 * deferred wakeup list. The waiter will be set running when the 315 * caller (this thread) releases the mutex. 316 */ 317 if (mutex != NULL && self->pt_nwaiters < pthread__unpark_max && 318 pthread__mutex_deferwake(self, mutex)) { 319 signaled->pt_sleepobj = NULL; 320 signaled->pt_sleeponq = 0; 321 pthread__spinunlock(self, &cond->ptc_lock); 322 self->pt_waiters[self->pt_nwaiters++] = signaled->pt_lid; 323 } else { 324 pthread__unpark(self, &cond->ptc_lock, 325 &cond->ptc_waiters, signaled); 326 } 327 328 return 0; 329 } 330 331 332 int 333 pthread_cond_broadcast(pthread_cond_t *cond) 334 { 335 pthread_t self, signaled, next; 336 pthread_mutex_t *mutex; 337 338 pthread__error(EINVAL, "Invalid condition variable", 339 cond->ptc_magic == _PT_COND_MAGIC); 340 341 if (PTQ_EMPTY(&cond->ptc_waiters)) 342 return 0; 343 344 self = pthread__self(); 345 pthread__spinlock(self, &cond->ptc_lock); 346 mutex = cond->ptc_mutex; 347 cond->ptc_mutex = NULL; 348 349 /* 350 * Try to defer waking threads (see pthread_cond_signal()). 351 * Only transfer waiters for which there is no pending wakeup. 352 */ 353 if (mutex != NULL && pthread__mutex_deferwake(self, mutex)) { 354 for (signaled = PTQ_FIRST(&cond->ptc_waiters); 355 signaled != NULL; 356 signaled = next) { 357 next = PTQ_NEXT(signaled, pt_sleep); 358 if (__predict_false(signaled->pt_sleepobj == NULL)) 359 continue; 360 if (self->pt_nwaiters == pthread__unpark_max) { 361 /* Overflow, take the slow path. */ 362 break; 363 } 364 PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep); 365 signaled->pt_sleepobj = NULL; 366 signaled->pt_sleeponq = 0; 367 self->pt_waiters[self->pt_nwaiters++] = 368 signaled->pt_lid; 369 } 370 if (signaled == NULL) { 371 /* Anything more to do? */ 372 pthread__spinunlock(self, &cond->ptc_lock); 373 return 0; 374 } 375 } 376 pthread__unpark_all(self, &cond->ptc_lock, &cond->ptc_waiters); 377 return 0; 378 } 379 380 381 int 382 pthread_condattr_init(pthread_condattr_t *attr) 383 { 384 385 attr->ptca_magic = _PT_CONDATTR_MAGIC; 386 387 return 0; 388 } 389 390 391 int 392 pthread_condattr_destroy(pthread_condattr_t *attr) 393 { 394 395 pthread__error(EINVAL, "Invalid condition variable attribute", 396 attr->ptca_magic == _PT_CONDATTR_MAGIC); 397 398 attr->ptca_magic = _PT_CONDATTR_DEAD; 399 400 return 0; 401 } 402 403 /* Utility routine to hang out for a while if threads haven't started yet. */ 404 static int 405 pthread_cond_wait_nothread(pthread_t self, pthread_mutex_t *mutex, 406 const struct timespec *abstime) 407 { 408 struct timespec now, diff; 409 int retval; 410 411 if (abstime == NULL) { 412 diff.tv_sec = 99999999; 413 diff.tv_nsec = 0; 414 } else { 415 clock_gettime(CLOCK_REALTIME, &now); 416 if (timespeccmp(abstime, &now, <)) 417 timespecclear(&diff); 418 else 419 timespecsub(abstime, &now, &diff); 420 } 421 422 do { 423 pthread__testcancel(self); 424 pthread_mutex_unlock(mutex); 425 retval = _sys_nanosleep(&diff, NULL); 426 pthread_mutex_lock(mutex); 427 } while (abstime == NULL && retval == 0); 428 pthread__testcancel(self); 429 430 if (retval == 0) 431 return ETIMEDOUT; 432 else 433 /* spurious wakeup */ 434 return 0; 435 } 436