thr_cond.c revision 113786
1/* 2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 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, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by John Birrell. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD: head/lib/libkse/thread/thr_cond.c 113786 2003-04-21 04:02:56Z deischen $ 33 */ 34#include <stdlib.h> 35#include <errno.h> 36#include <string.h> 37#include <pthread.h> 38#include "thr_private.h" 39 40#define THR_IN_CONDQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0) 41#define THR_IN_CONDQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0) 42#define THR_CONDQ_SET(thr) (thr)->sflags |= THR_FLAGS_IN_SYNCQ 43#define THR_CONDQ_CLEAR(thr) (thr)->sflags &= ~THR_FLAGS_IN_SYNCQ 44 45/* 46 * Prototypes 47 */ 48static inline struct pthread *cond_queue_deq(pthread_cond_t); 49static inline void cond_queue_remove(pthread_cond_t, pthread_t); 50static inline void cond_queue_enq(pthread_cond_t, pthread_t); 51 52__weak_reference(_pthread_cond_init, pthread_cond_init); 53__weak_reference(_pthread_cond_destroy, pthread_cond_destroy); 54__weak_reference(_pthread_cond_wait, pthread_cond_wait); 55__weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait); 56__weak_reference(_pthread_cond_signal, pthread_cond_signal); 57__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); 58 59 60int 61_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 62{ 63 enum pthread_cond_type type; 64 pthread_cond_t pcond; 65 int flags; 66 int rval = 0; 67 68 if (cond == NULL) 69 rval = EINVAL; 70 else { 71 /* 72 * Check if a pointer to a condition variable attribute 73 * structure was passed by the caller: 74 */ 75 if (cond_attr != NULL && *cond_attr != NULL) { 76 /* Default to a fast condition variable: */ 77 type = (*cond_attr)->c_type; 78 flags = (*cond_attr)->c_flags; 79 } else { 80 /* Default to a fast condition variable: */ 81 type = COND_TYPE_FAST; 82 flags = 0; 83 } 84 85 /* Process according to condition variable type: */ 86 switch (type) { 87 /* Fast condition variable: */ 88 case COND_TYPE_FAST: 89 /* Nothing to do here. */ 90 break; 91 92 /* Trap invalid condition variable types: */ 93 default: 94 /* Return an invalid argument error: */ 95 rval = EINVAL; 96 break; 97 } 98 99 /* Check for no errors: */ 100 if (rval == 0) { 101 if ((pcond = (pthread_cond_t) 102 malloc(sizeof(struct pthread_cond))) == NULL) { 103 rval = ENOMEM; 104 } else if (_lock_init(&pcond->c_lock, LCK_ADAPTIVE, 105 _thr_lock_wait, _thr_lock_wakeup) != 0) { 106 free(pcond); 107 rval = ENOMEM; 108 } else { 109 /* 110 * Initialise the condition variable 111 * structure: 112 */ 113 TAILQ_INIT(&pcond->c_queue); 114 pcond->c_flags |= COND_FLAGS_INITED; 115 pcond->c_type = type; 116 pcond->c_mutex = NULL; 117 pcond->c_seqno = 0; 118 *cond = pcond; 119 } 120 } 121 } 122 /* Return the completion status: */ 123 return (rval); 124} 125 126int 127_pthread_cond_destroy(pthread_cond_t *cond) 128{ 129 struct pthread_cond *cv; 130 struct pthread *curthread = _get_curthread(); 131 int rval = 0; 132 133 if (cond == NULL || *cond == NULL) 134 rval = EINVAL; 135 else { 136 /* Lock the condition variable structure: */ 137 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock); 138 139 /* 140 * NULL the caller's pointer now that the condition 141 * variable has been destroyed: 142 */ 143 cv = *cond; 144 *cond = NULL; 145 146 /* Unlock the condition variable structure: */ 147 THR_LOCK_RELEASE(curthread, &cv->c_lock); 148 149 /* 150 * Free the memory allocated for the condition 151 * variable structure: 152 */ 153 free(cv); 154 155 } 156 /* Return the completion status: */ 157 return (rval); 158} 159 160int 161_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 162{ 163 struct pthread *curthread = _get_curthread(); 164 int rval = 0; 165 int done = 0; 166 int interrupted = 0; 167 int unlock_mutex = 1; 168 int seqno; 169 170 _thr_enter_cancellation_point(curthread); 171 172 if (cond == NULL) { 173 _thr_leave_cancellation_point(curthread); 174 return (EINVAL); 175 } 176 177 /* 178 * If the condition variable is statically initialized, 179 * perform the dynamic initialization: 180 */ 181 if (*cond == NULL && 182 (rval = pthread_cond_init(cond, NULL)) != 0) { 183 _thr_leave_cancellation_point(curthread); 184 return (rval); 185 } 186 187 /* 188 * Enter a loop waiting for a condition signal or broadcast 189 * to wake up this thread. A loop is needed in case the waiting 190 * thread is interrupted by a signal to execute a signal handler. 191 * It is not (currently) possible to remain in the waiting queue 192 * while running a handler. Instead, the thread is interrupted 193 * and backed out of the waiting queue prior to executing the 194 * signal handler. 195 */ 196 do { 197 /* Lock the condition variable structure: */ 198 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock); 199 200 /* 201 * If the condvar was statically allocated, properly 202 * initialize the tail queue. 203 */ 204 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { 205 TAILQ_INIT(&(*cond)->c_queue); 206 (*cond)->c_flags |= COND_FLAGS_INITED; 207 } 208 209 /* Process according to condition variable type: */ 210 switch ((*cond)->c_type) { 211 /* Fast condition variable: */ 212 case COND_TYPE_FAST: 213 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && 214 ((*cond)->c_mutex != *mutex))) { 215 /* Unlock the condition variable structure: */ 216 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); 217 218 /* Return invalid argument error: */ 219 rval = EINVAL; 220 } else { 221 /* Reset the timeout and interrupted flags: */ 222 curthread->timeout = 0; 223 curthread->interrupted = 0; 224 225 /* 226 * Queue the running thread for the condition 227 * variable: 228 */ 229 cond_queue_enq(*cond, curthread); 230 231 /* Remember the mutex and sequence number: */ 232 (*cond)->c_mutex = *mutex; 233 seqno = (*cond)->c_seqno; 234 235 /* Wait forever: */ 236 curthread->wakeup_time.tv_sec = -1; 237 238 /* Unlock the mutex: */ 239 if ((unlock_mutex != 0) && 240 ((rval = _mutex_cv_unlock(mutex)) != 0)) { 241 /* 242 * Cannot unlock the mutex, so remove 243 * the running thread from the condition 244 * variable queue: 245 */ 246 cond_queue_remove(*cond, curthread); 247 248 /* Check for no more waiters: */ 249 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 250 (*cond)->c_mutex = NULL; 251 252 /* Unlock the condition variable structure: */ 253 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); 254 } 255 else { 256 /* 257 * Don't unlock the mutex the next 258 * time through the loop (if the 259 * thread has to be requeued after 260 * handling a signal). 261 */ 262 unlock_mutex = 0; 263 264 /* 265 * This thread is active and is in a 266 * critical region (holding the cv 267 * lock); we should be able to safely 268 * set the state. 269 */ 270 THR_SET_STATE(curthread, PS_COND_WAIT); 271 272 /* Remember the CV: */ 273 curthread->data.cond = *cond; 274 275 /* Unlock the CV structure: */ 276 THR_LOCK_RELEASE(curthread, 277 &(*cond)->c_lock); 278 279 /* Schedule the next thread: */ 280 _thr_sched_switch(curthread); 281 282 curthread->data.cond = NULL; 283 284 /* 285 * XXX - This really isn't a good check 286 * since there can be more than one 287 * thread waiting on the CV. Signals 288 * sent to threads waiting on mutexes 289 * or CVs should really be deferred 290 * until the threads are no longer 291 * waiting, but POSIX says that signals 292 * should be sent "as soon as possible". 293 */ 294 done = (seqno != (*cond)->c_seqno); 295 296 if (THR_IN_SYNCQ(curthread)) { 297 /* 298 * Lock the condition variable 299 * while removing the thread. 300 */ 301 THR_LOCK_ACQUIRE(curthread, 302 &(*cond)->c_lock); 303 304 cond_queue_remove(*cond, 305 curthread); 306 307 /* Check for no more waiters: */ 308 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 309 (*cond)->c_mutex = NULL; 310 311 THR_LOCK_RELEASE(curthread, 312 &(*cond)->c_lock); 313 } 314 315 /* 316 * Save the interrupted flag; locking 317 * the mutex may destroy it. 318 */ 319 interrupted = curthread->interrupted; 320 321 /* 322 * Note that even though this thread may 323 * have been canceled, POSIX requires 324 * that the mutex be reaquired prior to 325 * cancellation. 326 */ 327 if (done != 0) 328 rval = _mutex_cv_lock(mutex); 329 } 330 } 331 break; 332 333 /* Trap invalid condition variable types: */ 334 default: 335 /* Unlock the condition variable structure: */ 336 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); 337 338 /* Return an invalid argument error: */ 339 rval = EINVAL; 340 break; 341 } 342 343 if ((interrupted != 0) && (curthread->continuation != NULL)) 344 curthread->continuation((void *) curthread); 345 } while ((done == 0) && (rval == 0)); 346 347 _thr_leave_cancellation_point(curthread); 348 349 /* Return the completion status: */ 350 return (rval); 351} 352 353int 354__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 355{ 356 struct pthread *curthread = _get_curthread(); 357 int ret; 358 359 _thr_enter_cancellation_point(curthread); 360 ret = _pthread_cond_wait(cond, mutex); 361 _thr_leave_cancellation_point(curthread); 362 return (ret); 363} 364 365int 366_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 367 const struct timespec * abstime) 368{ 369 struct pthread *curthread = _get_curthread(); 370 int rval = 0; 371 int done = 0; 372 int interrupted = 0; 373 int unlock_mutex = 1; 374 int seqno; 375 376 _thr_enter_cancellation_point(curthread); 377 378 if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 379 abstime->tv_nsec >= 1000000000) { 380 _thr_leave_cancellation_point(curthread); 381 return (EINVAL); 382 } 383 /* 384 * If the condition variable is statically initialized, perform dynamic 385 * initialization. 386 */ 387 if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) { 388 _thr_leave_cancellation_point(curthread); 389 return (rval); 390 } 391 392 /* 393 * Enter a loop waiting for a condition signal or broadcast 394 * to wake up this thread. A loop is needed in case the waiting 395 * thread is interrupted by a signal to execute a signal handler. 396 * It is not (currently) possible to remain in the waiting queue 397 * while running a handler. Instead, the thread is interrupted 398 * and backed out of the waiting queue prior to executing the 399 * signal handler. 400 */ 401 do { 402 /* Lock the condition variable structure: */ 403 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock); 404 405 /* 406 * If the condvar was statically allocated, properly 407 * initialize the tail queue. 408 */ 409 if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { 410 TAILQ_INIT(&(*cond)->c_queue); 411 (*cond)->c_flags |= COND_FLAGS_INITED; 412 } 413 414 /* Process according to condition variable type: */ 415 switch ((*cond)->c_type) { 416 /* Fast condition variable: */ 417 case COND_TYPE_FAST: 418 if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && 419 ((*cond)->c_mutex != *mutex))) { 420 /* Return invalid argument error: */ 421 rval = EINVAL; 422 423 /* Unlock the condition variable structure: */ 424 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); 425 } else { 426 /* Set the wakeup time: */ 427 curthread->wakeup_time.tv_sec = abstime->tv_sec; 428 curthread->wakeup_time.tv_nsec = 429 abstime->tv_nsec; 430 431 /* Reset the timeout and interrupted flags: */ 432 curthread->timeout = 0; 433 curthread->interrupted = 0; 434 435 /* 436 * Queue the running thread for the condition 437 * variable: 438 */ 439 cond_queue_enq(*cond, curthread); 440 441 /* Remember the mutex and sequence number: */ 442 (*cond)->c_mutex = *mutex; 443 seqno = (*cond)->c_seqno; 444 445 /* Unlock the mutex: */ 446 if ((unlock_mutex != 0) && 447 ((rval = _mutex_cv_unlock(mutex)) != 0)) { 448 /* 449 * Cannot unlock the mutex; remove the 450 * running thread from the condition 451 * variable queue: 452 */ 453 cond_queue_remove(*cond, curthread); 454 455 /* Check for no more waiters: */ 456 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 457 (*cond)->c_mutex = NULL; 458 459 /* Unlock the condition variable structure: */ 460 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); 461 } else { 462 /* 463 * Don't unlock the mutex the next 464 * time through the loop (if the 465 * thread has to be requeued after 466 * handling a signal). 467 */ 468 unlock_mutex = 0; 469 470 /* 471 * This thread is active and is in a 472 * critical region (holding the cv 473 * lock); we should be able to safely 474 * set the state. 475 */ 476 THR_SET_STATE(curthread, PS_COND_WAIT); 477 478 /* Remember the CV: */ 479 curthread->data.cond = *cond; 480 481 /* Unlock the CV structure: */ 482 THR_LOCK_RELEASE(curthread, 483 &(*cond)->c_lock); 484 485 /* Schedule the next thread: */ 486 _thr_sched_switch(curthread); 487 488 curthread->data.cond = NULL; 489 490 /* 491 * XXX - This really isn't a good check 492 * since there can be more than one 493 * thread waiting on the CV. Signals 494 * sent to threads waiting on mutexes 495 * or CVs should really be deferred 496 * until the threads are no longer 497 * waiting, but POSIX says that signals 498 * should be sent "as soon as possible". 499 */ 500 done = (seqno != (*cond)->c_seqno); 501 502 if (THR_IN_CONDQ(curthread)) { 503 /* 504 * Lock the condition variable 505 * while removing the thread. 506 */ 507 THR_LOCK_ACQUIRE(curthread, 508 &(*cond)->c_lock); 509 510 cond_queue_remove(*cond, 511 curthread); 512 513 /* Check for no more waiters: */ 514 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 515 (*cond)->c_mutex = NULL; 516 517 THR_LOCK_RELEASE(curthread, 518 &(*cond)->c_lock); 519 } 520 521 /* 522 * Save the interrupted flag; locking 523 * the mutex may destroy it. 524 */ 525 interrupted = curthread->interrupted; 526 if (curthread->timeout != 0) { 527 /* The wait timedout. */ 528 rval = ETIMEDOUT; 529 (void)_mutex_cv_lock(mutex); 530 } else if ((interrupted == 0) || 531 (done != 0)) 532 rval = _mutex_cv_lock(mutex); 533 } 534 } 535 break; 536 537 /* Trap invalid condition variable types: */ 538 default: 539 /* Unlock the condition variable structure: */ 540 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); 541 542 /* Return an invalid argument error: */ 543 rval = EINVAL; 544 break; 545 } 546 547 if ((interrupted != 0) && (curthread->continuation != NULL)) 548 curthread->continuation((void *)curthread); 549 } while ((done == 0) && (rval == 0)); 550 551 _thr_leave_cancellation_point(curthread); 552 553 /* Return the completion status: */ 554 return (rval); 555} 556 557int 558__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 559 const struct timespec *abstime) 560{ 561 struct pthread *curthread = _get_curthread(); 562 int ret; 563 564 _thr_enter_cancellation_point(curthread); 565 ret = _pthread_cond_timedwait(cond, mutex, abstime); 566 _thr_leave_cancellation_point(curthread); 567 return (ret); 568} 569 570 571int 572_pthread_cond_signal(pthread_cond_t * cond) 573{ 574 struct pthread *curthread = _get_curthread(); 575 struct pthread *pthread; 576 int rval = 0; 577 578 if (cond == NULL) 579 rval = EINVAL; 580 /* 581 * If the condition variable is statically initialized, perform dynamic 582 * initialization. 583 */ 584 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) { 585 /* Lock the condition variable structure: */ 586 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock); 587 588 /* Process according to condition variable type: */ 589 switch ((*cond)->c_type) { 590 /* Fast condition variable: */ 591 case COND_TYPE_FAST: 592 /* Increment the sequence number: */ 593 (*cond)->c_seqno++; 594 595 /* 596 * Wakeups have to be done with the CV lock held; 597 * otherwise there is a race condition where the 598 * thread can timeout, run on another KSE, and enter 599 * another blocking state (including blocking on a CV). 600 */ 601 if ((pthread = TAILQ_FIRST(&(*cond)->c_queue)) 602 != NULL) { 603 THR_SCHED_LOCK(curthread, pthread); 604 cond_queue_remove(*cond, pthread); 605 _thr_setrunnable_unlocked(pthread); 606 THR_SCHED_UNLOCK(curthread, pthread); 607 } 608 /* Check for no more waiters: */ 609 if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) 610 (*cond)->c_mutex = NULL; 611 break; 612 613 /* Trap invalid condition variable types: */ 614 default: 615 /* Return an invalid argument error: */ 616 rval = EINVAL; 617 break; 618 } 619 620 /* Unlock the condition variable structure: */ 621 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); 622 } 623 624 /* Return the completion status: */ 625 return (rval); 626} 627 628int 629_pthread_cond_broadcast(pthread_cond_t * cond) 630{ 631 struct pthread *curthread = _get_curthread(); 632 struct pthread *pthread; 633 int rval = 0; 634 635 if (cond == NULL) 636 rval = EINVAL; 637 /* 638 * If the condition variable is statically initialized, perform dynamic 639 * initialization. 640 */ 641 else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) { 642 /* Lock the condition variable structure: */ 643 THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock); 644 645 /* Process according to condition variable type: */ 646 switch ((*cond)->c_type) { 647 /* Fast condition variable: */ 648 case COND_TYPE_FAST: 649 /* Increment the sequence number: */ 650 (*cond)->c_seqno++; 651 652 /* 653 * Enter a loop to bring all threads off the 654 * condition queue: 655 */ 656 while ((pthread = TAILQ_FIRST(&(*cond)->c_queue)) 657 != NULL) { 658 THR_SCHED_LOCK(curthread, pthread); 659 cond_queue_remove(*cond, pthread); 660 _thr_setrunnable_unlocked(pthread); 661 THR_SCHED_UNLOCK(curthread, pthread); 662 } 663 664 /* There are no more waiting threads: */ 665 (*cond)->c_mutex = NULL; 666 break; 667 668 /* Trap invalid condition variable types: */ 669 default: 670 /* Return an invalid argument error: */ 671 rval = EINVAL; 672 break; 673 } 674 675 /* Unlock the condition variable structure: */ 676 THR_LOCK_RELEASE(curthread, &(*cond)->c_lock); 677 } 678 679 /* Return the completion status: */ 680 return (rval); 681} 682 683void 684_cond_wait_backout(struct pthread *curthread) 685{ 686 pthread_cond_t cond; 687 688 cond = curthread->data.cond; 689 if (cond != NULL) { 690 /* Lock the condition variable structure: */ 691 THR_LOCK_ACQUIRE(curthread, &cond->c_lock); 692 693 /* Process according to condition variable type: */ 694 switch (cond->c_type) { 695 /* Fast condition variable: */ 696 case COND_TYPE_FAST: 697 cond_queue_remove(cond, curthread); 698 699 /* Check for no more waiters: */ 700 if (TAILQ_FIRST(&cond->c_queue) == NULL) 701 cond->c_mutex = NULL; 702 break; 703 704 default: 705 break; 706 } 707 708 /* Unlock the condition variable structure: */ 709 THR_LOCK_RELEASE(curthread, &cond->c_lock); 710 } 711} 712 713/* 714 * Dequeue a waiting thread from the head of a condition queue in 715 * descending priority order. 716 */ 717static inline struct pthread * 718cond_queue_deq(pthread_cond_t cond) 719{ 720 struct pthread *pthread; 721 722 while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { 723 TAILQ_REMOVE(&cond->c_queue, pthread, sqe); 724 THR_CONDQ_SET(pthread); 725 if ((pthread->timeout == 0) && (pthread->interrupted == 0)) 726 /* 727 * Only exit the loop when we find a thread 728 * that hasn't timed out or been canceled; 729 * those threads are already running and don't 730 * need their run state changed. 731 */ 732 break; 733 } 734 735 return (pthread); 736} 737 738/* 739 * Remove a waiting thread from a condition queue in descending priority 740 * order. 741 */ 742static inline void 743cond_queue_remove(pthread_cond_t cond, struct pthread *pthread) 744{ 745 /* 746 * Because pthread_cond_timedwait() can timeout as well 747 * as be signaled by another thread, it is necessary to 748 * guard against removing the thread from the queue if 749 * it isn't in the queue. 750 */ 751 if (THR_IN_CONDQ(pthread)) { 752 TAILQ_REMOVE(&cond->c_queue, pthread, sqe); 753 THR_CONDQ_CLEAR(pthread); 754 } 755} 756 757/* 758 * Enqueue a waiting thread to a condition queue in descending priority 759 * order. 760 */ 761static inline void 762cond_queue_enq(pthread_cond_t cond, struct pthread *pthread) 763{ 764 struct pthread *tid = TAILQ_LAST(&cond->c_queue, cond_head); 765 766 THR_ASSERT(!THR_IN_SYNCQ(pthread), 767 "cond_queue_enq: thread already queued!"); 768 769 /* 770 * For the common case of all threads having equal priority, 771 * we perform a quick check against the priority of the thread 772 * at the tail of the queue. 773 */ 774 if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) 775 TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe); 776 else { 777 tid = TAILQ_FIRST(&cond->c_queue); 778 while (pthread->active_priority <= tid->active_priority) 779 tid = TAILQ_NEXT(tid, sqe); 780 TAILQ_INSERT_BEFORE(tid, pthread, sqe); 781 } 782 THR_CONDQ_SET(pthread); 783 pthread->data.cond = cond; 784} 785