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