thr_cond.c revision 75369
1219019Sgabor/* 2219019Sgabor * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 3219019Sgabor * All rights reserved. 4219019Sgabor * 5219019Sgabor * Redistribution and use in source and binary forms, with or without 6219019Sgabor * modification, are permitted provided that the following conditions 7219019Sgabor * are met: 8219019Sgabor * 1. Redistributions of source code must retain the above copyright 9219019Sgabor * notice, this list of conditions and the following disclaimer. 10219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 11219019Sgabor * notice, this list of conditions and the following disclaimer in the 12219019Sgabor * documentation and/or other materials provided with the distribution. 13219019Sgabor * 3. All advertising materials mentioning features or use of this software 14219019Sgabor * must display the following acknowledgement: 15219019Sgabor * This product includes software developed by John Birrell. 16219019Sgabor * 4. Neither the name of the author nor the names of any co-contributors 17219019Sgabor * may be used to endorse or promote products derived from this software 18219019Sgabor * without specific prior written permission. 19219019Sgabor * 20219019Sgabor * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23219019Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30219019Sgabor * SUCH DAMAGE. 31219019Sgabor * 32219019Sgabor * $FreeBSD: head/lib/libkse/thread/thr_cond.c 75369 2001-04-10 04:19:21Z deischen $ 33219019Sgabor */ 34219019Sgabor#include <stdlib.h> 35219019Sgabor#include <errno.h> 36219019Sgabor#include <string.h> 37219019Sgabor#include <pthread.h> 38219019Sgabor#include "pthread_private.h" 39219019Sgabor 40219019Sgabor/* 41219019Sgabor * Prototypes 42219019Sgabor */ 43219019Sgaborstatic inline pthread_t cond_queue_deq(pthread_cond_t); 44219019Sgaborstatic inline void cond_queue_remove(pthread_cond_t, pthread_t); 45219019Sgaborstatic inline void cond_queue_enq(pthread_cond_t, pthread_t); 46219019Sgabor 47219019Sgabor__weak_reference(_pthread_cond_init, pthread_cond_init); 48219019Sgabor__weak_reference(_pthread_cond_destroy, pthread_cond_destroy); 49219019Sgabor__weak_reference(_pthread_cond_wait, pthread_cond_wait); 50219019Sgabor__weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait); 51219019Sgabor__weak_reference(_pthread_cond_signal, pthread_cond_signal); 52219019Sgabor__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); 53219019Sgabor 54219019Sgabor 55219019Sgabor/* Reinitialize a condition variable to defaults. */ 56219019Sgaborint 57219019Sgabor_cond_reinit(pthread_cond_t *cond) 58219019Sgabor{ 59219019Sgabor int ret = 0; 60219019Sgabor 61219019Sgabor if (cond == NULL) 62219019Sgabor ret = EINVAL; 63219019Sgabor else if (*cond == NULL) 64219019Sgabor ret = pthread_cond_init(cond, NULL); 65219019Sgabor else { 66219019Sgabor /* 67219019Sgabor * Initialize the condition variable structure: 68219019Sgabor */ 69219019Sgabor TAILQ_INIT(&(*cond)->c_queue); 70219019Sgabor (*cond)->c_flags = COND_FLAGS_INITED; 71219019Sgabor (*cond)->c_type = COND_TYPE_FAST; 72219019Sgabor (*cond)->c_mutex = NULL; 73219019Sgabor (*cond)->c_seqno = 0; 74219019Sgabor memset(&(*cond)->lock, 0, sizeof((*cond)->lock)); 75219019Sgabor } 76219019Sgabor return (ret); 77219019Sgabor} 78219019Sgabor 79219019Sgaborint 80219019Sgabor_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 81219019Sgabor{ 82219019Sgabor enum pthread_cond_type type; 83219019Sgabor pthread_cond_t pcond; 84219019Sgabor int rval = 0; 85219019Sgabor 86219019Sgabor if (cond == NULL) 87219019Sgabor rval = EINVAL; 88219019Sgabor else { 89219019Sgabor /* 90219019Sgabor * Check if a pointer to a condition variable attribute 91219019Sgabor * structure was passed by the caller: 92219019Sgabor */ 93219019Sgabor if (cond_attr != NULL && *cond_attr != NULL) { 94219019Sgabor /* Default to a fast condition variable: */ 95219019Sgabor type = (*cond_attr)->c_type; 96219019Sgabor } else { 97219019Sgabor /* Default to a fast condition variable: */ 98219019Sgabor type = COND_TYPE_FAST; 99219019Sgabor } 100219019Sgabor 101219019Sgabor /* Process according to condition variable type: */ 102219019Sgabor switch (type) { 103219019Sgabor /* Fast condition variable: */ 104219019Sgabor case COND_TYPE_FAST: 105219019Sgabor /* Nothing to do here. */ 106219019Sgabor break; 107219019Sgabor 108219019Sgabor /* Trap invalid condition variable types: */ 109219019Sgabor default: 110219019Sgabor /* Return an invalid argument error: */ 111219019Sgabor rval = EINVAL; 112219019Sgabor break; 113219019Sgabor } 114219019Sgabor 115219019Sgabor /* Check for no errors: */ 116219019Sgabor if (rval == 0) { 117219019Sgabor if ((pcond = (pthread_cond_t) 118219019Sgabor malloc(sizeof(struct pthread_cond))) == NULL) { 119219019Sgabor rval = ENOMEM; 120219019Sgabor } else { 121219019Sgabor /* 122219019Sgabor * Initialise the condition variable 123219019Sgabor * structure: 124219019Sgabor */ 125219019Sgabor TAILQ_INIT(&pcond->c_queue); 126219019Sgabor pcond->c_flags |= COND_FLAGS_INITED; 127219019Sgabor pcond->c_type = type; 128219019Sgabor pcond->c_mutex = NULL; 129219019Sgabor pcond->c_seqno = 0; 130219019Sgabor memset(&pcond->lock,0,sizeof(pcond->lock)); 131219019Sgabor *cond = pcond; 132219019Sgabor } 133219019Sgabor } 134219019Sgabor } 135219019Sgabor /* Return the completion status: */ 136219019Sgabor return (rval); 137219019Sgabor} 138219019Sgabor 139219019Sgaborint 140219019Sgabor_pthread_cond_destroy(pthread_cond_t *cond) 141219019Sgabor{ 142219019Sgabor int rval = 0; 143219019Sgabor 144219019Sgabor if (cond == NULL || *cond == NULL) 145219019Sgabor rval = EINVAL; 146219019Sgabor else { 147219019Sgabor /* Lock the condition variable structure: */ 148219019Sgabor _SPINLOCK(&(*cond)->lock); 149219019Sgabor 150219019Sgabor /* 151219019Sgabor * Free the memory allocated for the condition 152219019Sgabor * variable structure: 153219019Sgabor */ 154219019Sgabor free(*cond); 155219019Sgabor 156219019Sgabor /* 157219019Sgabor * NULL the caller's pointer now that the condition 158219019Sgabor * variable has been destroyed: 159219019Sgabor */ 160219019Sgabor *cond = NULL; 161219019Sgabor } 162219019Sgabor /* Return the completion status: */ 163219019Sgabor return (rval); 164219019Sgabor} 165219019Sgabor 166219019Sgaborint 167219019Sgabor_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 168219019Sgabor{ 169219019Sgabor struct pthread *curthread = _get_curthread(); 170219019Sgabor int rval = 0; 171219019Sgabor int done = 0; 172219019Sgabor int interrupted = 0; 173219019Sgabor int unlock_mutex = 1; 174219019Sgabor int seqno; 175219019Sgabor 176219019Sgabor _thread_enter_cancellation_point(); 177219019Sgabor 178219019Sgabor if (cond == NULL) 179219019Sgabor return (EINVAL); 180219019Sgabor 181219019Sgabor /* 182219019Sgabor * If the condition variable is statically initialized, 183219019Sgabor * perform the dynamic initialization: 184219019Sgabor */ 185219019Sgabor if (*cond == NULL && 186219019Sgabor (rval = pthread_cond_init(cond, NULL)) != 0) 187219019Sgabor return (rval); 188219019Sgabor 189219019Sgabor /* 190219019Sgabor * Enter a loop waiting for a condition signal or broadcast 191219019Sgabor * to wake up this thread. A loop is needed in case the waiting 192219019Sgabor * thread is interrupted by a signal to execute a signal handler. 193219019Sgabor * It is not (currently) possible to remain in the waiting queue 194219019Sgabor * while running a handler. Instead, the thread is interrupted 195219019Sgabor * and backed out of the waiting queue prior to executing the 196219019Sgabor * signal handler. 197219019Sgabor */ 198219019Sgabor do { 199219019Sgabor /* Lock the condition variable structure: */ 200219019Sgabor _SPINLOCK(&(*cond)->lock); 201219019Sgabor 202219019Sgabor /* 203219019Sgabor * If the condvar was statically allocated, properly 204219019Sgabor * initialize the tail queue. 205219019Sgabor */ 206219019Sgabor if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { 207219019Sgabor TAILQ_INIT(&(*cond)->c_queue); 208219019Sgabor (*cond)->c_flags |= COND_FLAGS_INITED; 209219019Sgabor } 210219019Sgabor 211219019Sgabor /* Process according to condition variable type: */ 212219019Sgabor switch ((*cond)->c_type) { 213219019Sgabor /* Fast condition variable: */ 214219019Sgabor case COND_TYPE_FAST: 215219019Sgabor if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && 216219019Sgabor ((*cond)->c_mutex != *mutex))) { 217219019Sgabor /* Unlock the condition variable structure: */ 218219019Sgabor _SPINUNLOCK(&(*cond)->lock); 219219019Sgabor 220219019Sgabor /* Return invalid argument error: */ 221219019Sgabor rval = EINVAL; 222219019Sgabor } else { 223219019Sgabor /* Reset the timeout and interrupted flags: */ 224219019Sgabor curthread->timeout = 0; 225219019Sgabor curthread->interrupted = 0; 226219019Sgabor 227219019Sgabor /* 228219019Sgabor * Queue the running thread for the condition 229219019Sgabor * variable: 230219019Sgabor */ 231219019Sgabor cond_queue_enq(*cond, curthread); 232219019Sgabor 233219019Sgabor /* Remember the mutex and sequence number: */ 234219019Sgabor (*cond)->c_mutex = *mutex; 235219019Sgabor seqno = (*cond)->c_seqno; 236219019Sgabor 237219019Sgabor /* Wait forever: */ 238219019Sgabor curthread->wakeup_time.tv_sec = -1; 239219019Sgabor 240219019Sgabor /* Unlock the mutex: */ 241219019Sgabor if ((unlock_mutex != 0) && 242219019Sgabor ((rval = _mutex_cv_unlock(mutex)) != 0)) { 243219019Sgabor /* 244219019Sgabor * Cannot unlock the mutex, so remove 245219019Sgabor * the running thread from the condition 246219019Sgabor * variable queue: 247219019Sgabor */ 248219019Sgabor cond_queue_remove(*cond, curthread); 249219019Sgabor 250219019Sgabor /* Check for no more waiters: */ 251219019Sgabor if (TAILQ_FIRST(&(*cond)->c_queue) == 252219019Sgabor NULL) 253219019Sgabor (*cond)->c_mutex = NULL; 254219019Sgabor 255219019Sgabor /* Unlock the condition variable structure: */ 256219019Sgabor _SPINUNLOCK(&(*cond)->lock); 257219019Sgabor } 258219019Sgabor else { 259219019Sgabor /* 260219019Sgabor * Don't unlock the mutex in the event 261219019Sgabor * this thread has to be requeued in 262219019Sgabor * condition variable queue: 263219019Sgabor */ 264219019Sgabor unlock_mutex = 0; 265219019Sgabor 266219019Sgabor /* 267219019Sgabor * Schedule the next thread and unlock 268219019Sgabor * the condition variable structure: 269219019Sgabor */ 270219019Sgabor _thread_kern_sched_state_unlock(PS_COND_WAIT, 271219019Sgabor &(*cond)->lock, __FILE__, __LINE__); 272219019Sgabor 273219019Sgabor done = (seqno != (*cond)->c_seqno); 274219019Sgabor 275219019Sgabor if ((curthread->flags & 276219019Sgabor PTHREAD_FLAGS_IN_CONDQ) != 0) { 277219019Sgabor /* 278219019Sgabor * Lock the condition variable 279219019Sgabor * while removing the thread. 280219019Sgabor */ 281219019Sgabor _SPINLOCK(&(*cond)->lock); 282219019Sgabor 283219019Sgabor cond_queue_remove(*cond, 284219019Sgabor curthread); 285219019Sgabor 286219019Sgabor /* Check for no more waiters: */ 287219019Sgabor if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 288219019Sgabor (*cond)->c_mutex = NULL; 289219019Sgabor 290219019Sgabor _SPINUNLOCK(&(*cond)->lock); 291219019Sgabor } 292219019Sgabor 293219019Sgabor /* 294219019Sgabor * Save the interrupted flag; locking 295219019Sgabor * the mutex will destroy it. 296219019Sgabor */ 297219019Sgabor interrupted = curthread->interrupted; 298219019Sgabor 299219019Sgabor /* 300219019Sgabor * Note that even though this thread may have 301219019Sgabor * been canceled, POSIX requires that the mutex 302219019Sgabor * be reaquired prior to cancellation. 303219019Sgabor */ 304219019Sgabor rval = _mutex_cv_lock(mutex); 305219019Sgabor } 306219019Sgabor } 307219019Sgabor break; 308219019Sgabor 309219019Sgabor /* Trap invalid condition variable types: */ 310219019Sgabor default: 311219019Sgabor /* Unlock the condition variable structure: */ 312219019Sgabor _SPINUNLOCK(&(*cond)->lock); 313219019Sgabor 314219019Sgabor /* Return an invalid argument error: */ 315219019Sgabor rval = EINVAL; 316219019Sgabor break; 317219019Sgabor } 318219019Sgabor 319219019Sgabor if ((interrupted != 0) && (curthread->continuation != NULL)) 320219019Sgabor curthread->continuation((void *) curthread); 321219019Sgabor } while ((done == 0) && (rval == 0)); 322219019Sgabor 323219019Sgabor _thread_leave_cancellation_point(); 324219019Sgabor 325219019Sgabor /* Return the completion status: */ 326219019Sgabor return (rval); 327219019Sgabor} 328219019Sgabor 329219019Sgaborint 330219019Sgabor_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 331219019Sgabor const struct timespec * abstime) 332219019Sgabor{ 333219019Sgabor struct pthread *curthread = _get_curthread(); 334219019Sgabor int rval = 0; 335219019Sgabor int done = 0; 336219019Sgabor int interrupted = 0; 337219019Sgabor int unlock_mutex = 1; 338219019Sgabor int seqno; 339219019Sgabor 340219019Sgabor _thread_enter_cancellation_point(); 341219019Sgabor 342219019Sgabor if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 343219019Sgabor abstime->tv_nsec >= 1000000000) 344219019Sgabor return (EINVAL); 345219019Sgabor /* 346219019Sgabor * If the condition variable is statically initialized, perform dynamic 347219019Sgabor * initialization. 348219019Sgabor */ 349219019Sgabor if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) 350219019Sgabor return (rval); 351219019Sgabor 352219019Sgabor /* 353219019Sgabor * Enter a loop waiting for a condition signal or broadcast 354219019Sgabor * to wake up this thread. A loop is needed in case the waiting 355219019Sgabor * thread is interrupted by a signal to execute a signal handler. 356219019Sgabor * It is not (currently) possible to remain in the waiting queue 357219019Sgabor * while running a handler. Instead, the thread is interrupted 358219019Sgabor * and backed out of the waiting queue prior to executing the 359219019Sgabor * signal handler. 360219019Sgabor */ 361219019Sgabor do { 362219019Sgabor /* Lock the condition variable structure: */ 363219019Sgabor _SPINLOCK(&(*cond)->lock); 364219019Sgabor 365219019Sgabor /* 366219019Sgabor * If the condvar was statically allocated, properly 367219019Sgabor * initialize the tail queue. 368219019Sgabor */ 369219019Sgabor if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { 370219019Sgabor TAILQ_INIT(&(*cond)->c_queue); 371219019Sgabor (*cond)->c_flags |= COND_FLAGS_INITED; 372219019Sgabor } 373219019Sgabor 374219019Sgabor /* Process according to condition variable type: */ 375219019Sgabor switch ((*cond)->c_type) { 376219019Sgabor /* Fast condition variable: */ 377219019Sgabor case COND_TYPE_FAST: 378219019Sgabor if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && 379219019Sgabor ((*cond)->c_mutex != *mutex))) { 380219019Sgabor /* Return invalid argument error: */ 381219019Sgabor rval = EINVAL; 382219019Sgabor 383219019Sgabor /* Unlock the condition variable structure: */ 384219019Sgabor _SPINUNLOCK(&(*cond)->lock); 385219019Sgabor } else { 386219019Sgabor /* Set the wakeup time: */ 387219019Sgabor curthread->wakeup_time.tv_sec = 388219019Sgabor abstime->tv_sec; 389219019Sgabor curthread->wakeup_time.tv_nsec = 390219019Sgabor abstime->tv_nsec; 391219019Sgabor 392219019Sgabor /* Reset the timeout and interrupted flags: */ 393219019Sgabor curthread->timeout = 0; 394219019Sgabor curthread->interrupted = 0; 395219019Sgabor 396219019Sgabor /* 397219019Sgabor * Queue the running thread for the condition 398219019Sgabor * variable: 399219019Sgabor */ 400219019Sgabor cond_queue_enq(*cond, curthread); 401219019Sgabor 402219019Sgabor /* Remember the mutex and sequence number: */ 403219019Sgabor (*cond)->c_mutex = *mutex; 404219019Sgabor seqno = (*cond)->c_seqno; 405219019Sgabor 406219019Sgabor /* Unlock the mutex: */ 407219019Sgabor if ((unlock_mutex != 0) && 408219019Sgabor ((rval = _mutex_cv_unlock(mutex)) != 0)) { 409219019Sgabor /* 410219019Sgabor * Cannot unlock the mutex, so remove 411219019Sgabor * the running thread from the condition 412219019Sgabor * variable queue: 413219019Sgabor */ 414219019Sgabor cond_queue_remove(*cond, curthread); 415219019Sgabor 416219019Sgabor /* Check for no more waiters: */ 417219019Sgabor if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 418 (*cond)->c_mutex = NULL; 419 420 /* Unlock the condition variable structure: */ 421 _SPINUNLOCK(&(*cond)->lock); 422 } else { 423 /* 424 * Don't unlock the mutex in the event 425 * this thread has to be requeued in 426 * condition variable queue: 427 */ 428 unlock_mutex = 0; 429 430 /* 431 * Schedule the next thread and unlock 432 * the condition variable structure: 433 */ 434 _thread_kern_sched_state_unlock(PS_COND_WAIT, 435 &(*cond)->lock, __FILE__, __LINE__); 436 437 done = (seqno != (*cond)->c_seqno); 438 439 /* 440 * Check if the wait timedout, was 441 * interrupted (canceled), or needs to 442 * be resumed after handling a signal. 443 */ 444 if ((curthread->timeout == 0) && 445 (curthread->interrupted == 0) && 446 (done != 0)) { 447 /* Lock the mutex: */ 448 rval = _mutex_cv_lock(mutex); 449 } else { 450 /* Lock the CV structure: */ 451 _SPINLOCK(&(*cond)->lock); 452 453 /* 454 * The wait timed out; remove 455 * the thread from the condition 456 * variable queue: 457 */ 458 cond_queue_remove(*cond, 459 curthread); 460 461 /* Check for no more waiters: */ 462 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 463 (*cond)->c_mutex = NULL; 464 465 /* Unock the CV structure: */ 466 _SPINUNLOCK(&(*cond)->lock); 467 468 /* Return a timeout error: */ 469 if (curthread->timeout != 0) 470 rval = ETIMEDOUT; 471 /* 472 * Save the interrupted flag; 473 * locking the mutex will 474 * destroy it. 475 */ 476 interrupted = curthread->interrupted; 477 478 /* 479 * Lock the mutex and ignore any 480 * errors. Note that even though 481 * this thread may have been 482 * canceled, POSIX requires that 483 * the mutex be reaquired prior 484 * to cancellation. 485 */ 486 (void)_mutex_cv_lock(mutex); 487 } 488 } 489 } 490 break; 491 492 /* Trap invalid condition variable types: */ 493 default: 494 /* Unlock the condition variable structure: */ 495 _SPINUNLOCK(&(*cond)->lock); 496 497 /* Return an invalid argument error: */ 498 rval = EINVAL; 499 break; 500 } 501 502 if ((interrupted != 0) && (curthread->continuation != NULL)) 503 curthread->continuation((void *) curthread); 504 } while ((done == 0) && (rval == 0)); 505 506 _thread_leave_cancellation_point(); 507 508 /* Return the completion status: */ 509 return (rval); 510} 511 512int 513_pthread_cond_signal(pthread_cond_t * cond) 514{ 515 int rval = 0; 516 pthread_t pthread; 517 518 if (cond == NULL) 519 rval = EINVAL; 520 /* 521 * If the condition variable is statically initialized, perform dynamic 522 * initialization. 523 */ 524 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) { 525 /* 526 * Defer signals to protect the scheduling queues 527 * from access by the signal handler: 528 */ 529 _thread_kern_sig_defer(); 530 531 /* Lock the condition variable structure: */ 532 _SPINLOCK(&(*cond)->lock); 533 534 /* Process according to condition variable type: */ 535 switch ((*cond)->c_type) { 536 /* Fast condition variable: */ 537 case COND_TYPE_FAST: 538 /* Increment the sequence number: */ 539 (*cond)->c_seqno++; 540 541 if ((pthread = cond_queue_deq(*cond)) != NULL) { 542 /* 543 * Unless the thread is currently suspended, 544 * allow it to run. If the thread is suspended, 545 * make a note that the thread isn't in a wait 546 * queue any more. 547 */ 548 if (pthread->state != PS_SUSPENDED) 549 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 550 else 551 pthread->suspended = SUSP_NOWAIT; 552 } 553 554 /* Check for no more waiters: */ 555 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 556 (*cond)->c_mutex = NULL; 557 break; 558 559 /* Trap invalid condition variable types: */ 560 default: 561 /* Return an invalid argument error: */ 562 rval = EINVAL; 563 break; 564 } 565 566 /* Unlock the condition variable structure: */ 567 _SPINUNLOCK(&(*cond)->lock); 568 569 /* 570 * Undefer and handle pending signals, yielding if 571 * necessary: 572 */ 573 _thread_kern_sig_undefer(); 574 } 575 576 /* Return the completion status: */ 577 return (rval); 578} 579 580int 581_pthread_cond_broadcast(pthread_cond_t * cond) 582{ 583 int rval = 0; 584 pthread_t pthread; 585 586 if (cond == NULL) 587 rval = EINVAL; 588 /* 589 * If the condition variable is statically initialized, perform dynamic 590 * initialization. 591 */ 592 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) { 593 /* 594 * Defer signals to protect the scheduling queues 595 * from access by the signal handler: 596 */ 597 _thread_kern_sig_defer(); 598 599 /* Lock the condition variable structure: */ 600 _SPINLOCK(&(*cond)->lock); 601 602 /* Process according to condition variable type: */ 603 switch ((*cond)->c_type) { 604 /* Fast condition variable: */ 605 case COND_TYPE_FAST: 606 /* Increment the sequence number: */ 607 (*cond)->c_seqno++; 608 609 /* 610 * Enter a loop to bring all threads off the 611 * condition queue: 612 */ 613 while ((pthread = cond_queue_deq(*cond)) != NULL) { 614 /* 615 * Unless the thread is currently suspended, 616 * allow it to run. If the thread is suspended, 617 * make a note that the thread isn't in a wait 618 * queue any more. 619 */ 620 if (pthread->state != PS_SUSPENDED) 621 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 622 else 623 pthread->suspended = SUSP_NOWAIT; 624 } 625 626 /* There are no more waiting threads: */ 627 (*cond)->c_mutex = NULL; 628 break; 629 630 /* Trap invalid condition variable types: */ 631 default: 632 /* Return an invalid argument error: */ 633 rval = EINVAL; 634 break; 635 } 636 637 /* Unlock the condition variable structure: */ 638 _SPINUNLOCK(&(*cond)->lock); 639 640 /* 641 * Undefer and handle pending signals, yielding if 642 * necessary: 643 */ 644 _thread_kern_sig_undefer(); 645 } 646 647 /* Return the completion status: */ 648 return (rval); 649} 650 651void 652_cond_wait_backout(pthread_t pthread) 653{ 654 pthread_cond_t cond; 655 656 cond = pthread->data.cond; 657 if (cond != NULL) { 658 /* 659 * Defer signals to protect the scheduling queues 660 * from access by the signal handler: 661 */ 662 _thread_kern_sig_defer(); 663 664 /* Lock the condition variable structure: */ 665 _SPINLOCK(&cond->lock); 666 667 /* Process according to condition variable type: */ 668 switch (cond->c_type) { 669 /* Fast condition variable: */ 670 case COND_TYPE_FAST: 671 cond_queue_remove(cond, pthread); 672 673 /* Check for no more waiters: */ 674 if (TAILQ_FIRST(&cond->c_queue) == NULL) 675 cond->c_mutex = NULL; 676 break; 677 678 default: 679 break; 680 } 681 682 /* Unlock the condition variable structure: */ 683 _SPINUNLOCK(&cond->lock); 684 685 /* 686 * Undefer and handle pending signals, yielding if 687 * necessary: 688 */ 689 _thread_kern_sig_undefer(); 690 } 691} 692 693/* 694 * Dequeue a waiting thread from the head of a condition queue in 695 * descending priority order. 696 */ 697static inline pthread_t 698cond_queue_deq(pthread_cond_t cond) 699{ 700 pthread_t pthread; 701 702 while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { 703 TAILQ_REMOVE(&cond->c_queue, pthread, sqe); 704 pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; 705 if ((pthread->timeout == 0) && (pthread->interrupted == 0)) 706 /* 707 * Only exit the loop when we find a thread 708 * that hasn't timed out or been canceled; 709 * those threads are already running and don't 710 * need their run state changed. 711 */ 712 break; 713 } 714 715 return(pthread); 716} 717 718/* 719 * Remove a waiting thread from a condition queue in descending priority 720 * order. 721 */ 722static inline void 723cond_queue_remove(pthread_cond_t cond, pthread_t pthread) 724{ 725 /* 726 * Because pthread_cond_timedwait() can timeout as well 727 * as be signaled by another thread, it is necessary to 728 * guard against removing the thread from the queue if 729 * it isn't in the queue. 730 */ 731 if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) { 732 TAILQ_REMOVE(&cond->c_queue, pthread, sqe); 733 pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; 734 } 735} 736 737/* 738 * Enqueue a waiting thread to a condition queue in descending priority 739 * order. 740 */ 741static inline void 742cond_queue_enq(pthread_cond_t cond, pthread_t pthread) 743{ 744 pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head); 745 746 PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread); 747 748 /* 749 * For the common case of all threads having equal priority, 750 * we perform a quick check against the priority of the thread 751 * at the tail of the queue. 752 */ 753 if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) 754 TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe); 755 else { 756 tid = TAILQ_FIRST(&cond->c_queue); 757 while (pthread->active_priority <= tid->active_priority) 758 tid = TAILQ_NEXT(tid, sqe); 759 TAILQ_INSERT_BEFORE(tid, pthread, sqe); 760 } 761 pthread->flags |= PTHREAD_FLAGS_IN_CONDQ; 762 pthread->data.cond = cond; 763} 764