1bb535300SJeff Roberson /* 2bb535300SJeff Roberson * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 3bb535300SJeff Roberson * All rights reserved. 4bb535300SJeff Roberson * 5bb535300SJeff Roberson * Redistribution and use in source and binary forms, with or without 6bb535300SJeff Roberson * modification, are permitted provided that the following conditions 7bb535300SJeff Roberson * are met: 8bb535300SJeff Roberson * 1. Redistributions of source code must retain the above copyright 9bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer. 10bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 11bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the 12bb535300SJeff Roberson * documentation and/or other materials provided with the distribution. 13bb535300SJeff Roberson * 3. All advertising materials mentioning features or use of this software 14bb535300SJeff Roberson * must display the following acknowledgement: 15bb535300SJeff Roberson * This product includes software developed by John Birrell. 16bb535300SJeff Roberson * 4. Neither the name of the author nor the names of any co-contributors 17bb535300SJeff Roberson * may be used to endorse or promote products derived from this software 18bb535300SJeff Roberson * without specific prior written permission. 19bb535300SJeff Roberson * 20bb535300SJeff Roberson * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21bb535300SJeff Roberson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22bb535300SJeff Roberson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23bb535300SJeff Roberson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24bb535300SJeff Roberson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25bb535300SJeff Roberson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26bb535300SJeff Roberson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27bb535300SJeff Roberson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28bb535300SJeff Roberson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29bb535300SJeff Roberson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30bb535300SJeff Roberson * SUCH DAMAGE. 31bb535300SJeff Roberson * 32bb535300SJeff Roberson * $FreeBSD$ 33bb535300SJeff Roberson */ 34bb535300SJeff Roberson #include <stdlib.h> 35bb535300SJeff Roberson #include <errno.h> 36bb535300SJeff Roberson #include <string.h> 37bb535300SJeff Roberson #include <pthread.h> 38bb535300SJeff Roberson #include "thr_private.h" 39bb535300SJeff Roberson 40bb535300SJeff Roberson /* 41bb535300SJeff Roberson * Prototypes 42bb535300SJeff Roberson */ 43bb535300SJeff Roberson static pthread_t cond_queue_deq(pthread_cond_t); 44bb535300SJeff Roberson static void cond_queue_remove(pthread_cond_t, pthread_t); 45bb535300SJeff Roberson static void cond_queue_enq(pthread_cond_t, pthread_t); 46bb535300SJeff Roberson 47bb535300SJeff Roberson __weak_reference(_pthread_cond_init, pthread_cond_init); 48bb535300SJeff Roberson __weak_reference(_pthread_cond_destroy, pthread_cond_destroy); 49bb535300SJeff Roberson __weak_reference(_pthread_cond_wait, pthread_cond_wait); 50bb535300SJeff Roberson __weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait); 51bb535300SJeff Roberson __weak_reference(_pthread_cond_signal, pthread_cond_signal); 52bb535300SJeff Roberson __weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); 53bb535300SJeff Roberson 54bb535300SJeff Roberson #define COND_LOCK(c) \ 55bb535300SJeff Roberson do { \ 56bb535300SJeff Roberson if (umtx_lock(&(c)->c_lock, curthread->thr_id)) \ 57bb535300SJeff Roberson abort(); \ 58bb535300SJeff Roberson } while (0) 59bb535300SJeff Roberson 60bb535300SJeff Roberson #define COND_UNLOCK(c) \ 61bb535300SJeff Roberson do { \ 62bb535300SJeff Roberson if (umtx_unlock(&(c)->c_lock, curthread->thr_id)) \ 63bb535300SJeff Roberson abort(); \ 64bb535300SJeff Roberson } while (0) 65bb535300SJeff Roberson 66bb535300SJeff Roberson 67bb535300SJeff Roberson /* Reinitialize a condition variable to defaults. */ 68bb535300SJeff Roberson int 69bb535300SJeff Roberson _cond_reinit(pthread_cond_t *cond) 70bb535300SJeff Roberson { 71bb535300SJeff Roberson if (cond == NULL) 72bb535300SJeff Roberson return (EINVAL); 73bb535300SJeff Roberson 74bb535300SJeff Roberson if (*cond == NULL) 75bb535300SJeff Roberson return (pthread_cond_init(cond, NULL)); 76bb535300SJeff Roberson 77bb535300SJeff Roberson /* 78bb535300SJeff Roberson * Initialize the condition variable structure: 79bb535300SJeff Roberson */ 80bb535300SJeff Roberson TAILQ_INIT(&(*cond)->c_queue); 81bb535300SJeff Roberson (*cond)->c_flags = COND_FLAGS_INITED; 82bb535300SJeff Roberson (*cond)->c_type = COND_TYPE_FAST; 83bb535300SJeff Roberson (*cond)->c_mutex = NULL; 84bb535300SJeff Roberson (*cond)->c_seqno = 0; 85bb535300SJeff Roberson bzero(&(*cond)->c_lock, sizeof((*cond)->c_lock)); 86bb535300SJeff Roberson 87bb535300SJeff Roberson return (0); 88bb535300SJeff Roberson } 89bb535300SJeff Roberson 90bb535300SJeff Roberson int 91bb535300SJeff Roberson _pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 92bb535300SJeff Roberson { 93bb535300SJeff Roberson enum pthread_cond_type type; 94bb535300SJeff Roberson pthread_cond_t pcond; 95bb535300SJeff Roberson 96bb535300SJeff Roberson if (cond == NULL) 97bb535300SJeff Roberson return (EINVAL); 98bb535300SJeff Roberson 99bb535300SJeff Roberson /* 100bb535300SJeff Roberson * Check if a pointer to a condition variable attribute 101bb535300SJeff Roberson * structure was passed by the caller: 102bb535300SJeff Roberson */ 103bb535300SJeff Roberson if (cond_attr != NULL && *cond_attr != NULL) 104bb535300SJeff Roberson type = (*cond_attr)->c_type; 105bb535300SJeff Roberson else 106bb535300SJeff Roberson /* Default to a fast condition variable: */ 107bb535300SJeff Roberson type = COND_TYPE_FAST; 108bb535300SJeff Roberson 109bb535300SJeff Roberson /* Process according to condition variable type: */ 110bb535300SJeff Roberson switch (type) { 111bb535300SJeff Roberson case COND_TYPE_FAST: 112bb535300SJeff Roberson break; 113bb535300SJeff Roberson default: 114bb535300SJeff Roberson return (EINVAL); 115bb535300SJeff Roberson break; 116bb535300SJeff Roberson } 117bb535300SJeff Roberson 118bb535300SJeff Roberson if ((pcond = (pthread_cond_t) 119bb535300SJeff Roberson malloc(sizeof(struct pthread_cond))) == NULL) 120bb535300SJeff Roberson return (ENOMEM); 121bb535300SJeff Roberson /* 122bb535300SJeff Roberson * Initialise the condition variable 123bb535300SJeff Roberson * structure: 124bb535300SJeff Roberson */ 125bb535300SJeff Roberson TAILQ_INIT(&pcond->c_queue); 126bb535300SJeff Roberson pcond->c_flags |= COND_FLAGS_INITED; 127bb535300SJeff Roberson pcond->c_type = type; 128bb535300SJeff Roberson pcond->c_mutex = NULL; 129bb535300SJeff Roberson pcond->c_seqno = 0; 130bb535300SJeff Roberson bzero(&pcond->c_lock, sizeof(pcond->c_lock)); 131bb535300SJeff Roberson 132bb535300SJeff Roberson *cond = pcond; 133bb535300SJeff Roberson 134bb535300SJeff Roberson return (0); 135bb535300SJeff Roberson } 136bb535300SJeff Roberson 137bb535300SJeff Roberson int 138bb535300SJeff Roberson _pthread_cond_destroy(pthread_cond_t *cond) 139bb535300SJeff Roberson { 140bb535300SJeff Roberson struct pthread *curthread = _get_curthread(); 141bb535300SJeff Roberson 142bb535300SJeff Roberson if (cond == NULL || *cond == NULL) 143bb535300SJeff Roberson return (EINVAL); 144bb535300SJeff Roberson 145bb535300SJeff Roberson COND_LOCK(*cond); 146bb535300SJeff Roberson 147bb535300SJeff Roberson /* 148bb535300SJeff Roberson * Free the memory allocated for the condition 149bb535300SJeff Roberson * variable structure: 150bb535300SJeff Roberson */ 151bb535300SJeff Roberson free(*cond); 152bb535300SJeff Roberson 153bb535300SJeff Roberson /* 154bb535300SJeff Roberson * NULL the caller's pointer now that the condition 155bb535300SJeff Roberson * variable has been destroyed: 156bb535300SJeff Roberson */ 157bb535300SJeff Roberson *cond = NULL; 158bb535300SJeff Roberson 159bb535300SJeff Roberson return (0); 160bb535300SJeff Roberson } 161bb535300SJeff Roberson 162bb535300SJeff Roberson int 163bb535300SJeff Roberson _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 164bb535300SJeff Roberson { 165bb535300SJeff Roberson int rval; 166bb535300SJeff Roberson struct timespec abstime = { 0, 0 }; 167bb535300SJeff Roberson 168bb535300SJeff Roberson /* 169bb535300SJeff Roberson * XXXTHR This is a hack. Make a pthread_cond_common function that 170bb535300SJeff Roberson * accepts NULL so we don't change posix semantics for timedwait. 171bb535300SJeff Roberson */ 172bb535300SJeff Roberson rval = pthread_cond_timedwait(cond, mutex, &abstime); 173bb535300SJeff Roberson 174bb535300SJeff Roberson /* This should never happen. */ 175bb535300SJeff Roberson if (rval == ETIMEDOUT) 176bb535300SJeff Roberson abort(); 177bb535300SJeff Roberson 178bb535300SJeff Roberson return (rval); 179bb535300SJeff Roberson } 180bb535300SJeff Roberson 181bb535300SJeff Roberson int 182bb535300SJeff Roberson _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 183bb535300SJeff Roberson const struct timespec * abstime) 184bb535300SJeff Roberson { 185bb535300SJeff Roberson struct pthread *curthread = _get_curthread(); 186bb535300SJeff Roberson struct timespec *time; 187bb535300SJeff Roberson int rval = 0; 188bb535300SJeff Roberson int done = 0; 189bb535300SJeff Roberson int seqno; 190bb535300SJeff Roberson int mtxrval; 191bb535300SJeff Roberson 192bb535300SJeff Roberson 193bb535300SJeff Roberson _thread_enter_cancellation_point(); 194bb535300SJeff Roberson 195bb535300SJeff Roberson if (abstime == NULL || abstime->tv_nsec >= 1000000000) 196bb535300SJeff Roberson return (EINVAL); 197bb535300SJeff Roberson 198bb535300SJeff Roberson if (abstime->tv_sec == 0 && abstime->tv_nsec == 0) 199bb535300SJeff Roberson time = NULL; 200bb535300SJeff Roberson else 201bb535300SJeff Roberson time = abstime; 202bb535300SJeff Roberson /* 203bb535300SJeff Roberson * If the condition variable is statically initialized, perform dynamic 204bb535300SJeff Roberson * initialization. 205bb535300SJeff Roberson */ 206bb535300SJeff Roberson if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) 207bb535300SJeff Roberson return (rval); 208bb535300SJeff Roberson 209bb535300SJeff Roberson 210bb535300SJeff Roberson COND_LOCK(*cond); 211bb535300SJeff Roberson 212bb535300SJeff Roberson /* 213bb535300SJeff Roberson * If the condvar was statically allocated, properly 214bb535300SJeff Roberson * initialize the tail queue. 215bb535300SJeff Roberson */ 216bb535300SJeff Roberson if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { 217bb535300SJeff Roberson TAILQ_INIT(&(*cond)->c_queue); 218bb535300SJeff Roberson (*cond)->c_flags |= COND_FLAGS_INITED; 219bb535300SJeff Roberson } 220bb535300SJeff Roberson 221bb535300SJeff Roberson /* Process according to condition variable type. */ 222bb535300SJeff Roberson 223bb535300SJeff Roberson switch ((*cond)->c_type) { 224bb535300SJeff Roberson /* Fast condition variable: */ 225bb535300SJeff Roberson case COND_TYPE_FAST: 226bb535300SJeff Roberson if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && 227bb535300SJeff Roberson ((*cond)->c_mutex != *mutex))) { 228bb535300SJeff Roberson COND_UNLOCK(*cond); 229bb535300SJeff Roberson rval = EINVAL; 230bb535300SJeff Roberson break; 231bb535300SJeff Roberson } 232bb535300SJeff Roberson /* Remember the mutex */ 233bb535300SJeff Roberson (*cond)->c_mutex = *mutex; 234bb535300SJeff Roberson 235bb535300SJeff Roberson if ((rval = _mutex_cv_unlock(mutex)) != 0) { 236bb535300SJeff Roberson if (rval == -1){ 237bb535300SJeff Roberson printf("foo"); 238bb535300SJeff Roberson fflush(stdout); 239bb535300SJeff Roberson abort(); 240bb535300SJeff Roberson } 241bb535300SJeff Roberson 242bb535300SJeff Roberson COND_UNLOCK(*cond); 243bb535300SJeff Roberson break; 244bb535300SJeff Roberson } 245bb535300SJeff Roberson COND_UNLOCK(*cond); 246bb535300SJeff Roberson 247bb535300SJeff Roberson /* 248bb535300SJeff Roberson * We need giant for the queue operations. It also 249bb535300SJeff Roberson * protects seqno and the pthread flag fields. This is 250bb535300SJeff Roberson * dropped and reacquired in _thread_suspend(). 251bb535300SJeff Roberson */ 252bb535300SJeff Roberson 253bb535300SJeff Roberson GIANT_LOCK(curthread); 254bb535300SJeff Roberson /* 255bb535300SJeff Roberson * c_seqno is protected by giant. 256bb535300SJeff Roberson */ 257bb535300SJeff Roberson seqno = (*cond)->c_seqno; 258bb535300SJeff Roberson 259bb535300SJeff Roberson do { 260bb535300SJeff Roberson /* 261bb535300SJeff Roberson * Queue the running thread on the condition 262bb535300SJeff Roberson * variable. 263bb535300SJeff Roberson */ 264bb535300SJeff Roberson cond_queue_enq(*cond, curthread); 265bb535300SJeff Roberson 266bb535300SJeff Roberson if (curthread->cancelflags & PTHREAD_CANCELLING) { 267bb535300SJeff Roberson /* 268bb535300SJeff Roberson * POSIX Says that we must relock the mutex 269bb535300SJeff Roberson * even if we're being canceled. 270bb535300SJeff Roberson */ 271bb535300SJeff Roberson GIANT_UNLOCK(curthread); 272bb535300SJeff Roberson _mutex_cv_lock(mutex); 273bb535300SJeff Roberson pthread_testcancel(); 274bb535300SJeff Roberson PANIC("Shouldn't have come back."); 275bb535300SJeff Roberson } 276bb535300SJeff Roberson 277bb535300SJeff Roberson PTHREAD_SET_STATE(curthread, PS_COND_WAIT); 278bb535300SJeff Roberson rval = _thread_suspend(curthread, time); 279bb535300SJeff Roberson if (rval == -1) { 280bb535300SJeff Roberson printf("foo"); 281bb535300SJeff Roberson fflush(stdout); 282bb535300SJeff Roberson abort(); 283bb535300SJeff Roberson } 284bb535300SJeff Roberson 285bb535300SJeff Roberson done = (seqno != (*cond)->c_seqno); 286bb535300SJeff Roberson 287bb535300SJeff Roberson cond_queue_remove(*cond, curthread); 288bb535300SJeff Roberson 289bb535300SJeff Roberson } while ((done == 0) && (rval == 0)); 290bb535300SJeff Roberson /* 291bb535300SJeff Roberson * If we timed out someone still may have signaled us 292bb535300SJeff Roberson * before we got a chance to run again. We check for 293bb535300SJeff Roberson * this by looking to see if our state is RUNNING. 294bb535300SJeff Roberson */ 295bb535300SJeff Roberson if (rval == EAGAIN) { 296bb535300SJeff Roberson if (curthread->state != PS_RUNNING) { 297bb535300SJeff Roberson PTHREAD_SET_STATE(curthread, PS_RUNNING); 298bb535300SJeff Roberson rval = ETIMEDOUT; 299bb535300SJeff Roberson } else 300bb535300SJeff Roberson rval = 0; 301bb535300SJeff Roberson } 302bb535300SJeff Roberson GIANT_UNLOCK(curthread); 303bb535300SJeff Roberson 304bb535300SJeff Roberson mtxrval = _mutex_cv_lock(mutex); 305bb535300SJeff Roberson 306bb535300SJeff Roberson /* 307bb535300SJeff Roberson * If the mutex failed return that error, otherwise we're 308bb535300SJeff Roberson * returning ETIMEDOUT. 309bb535300SJeff Roberson */ 310bb535300SJeff Roberson if (mtxrval == -1) { 311bb535300SJeff Roberson printf("foo"); 312bb535300SJeff Roberson fflush(stdout); 313bb535300SJeff Roberson abort(); 314bb535300SJeff Roberson } 315bb535300SJeff Roberson if (mtxrval != 0) 316bb535300SJeff Roberson rval = mtxrval; 317bb535300SJeff Roberson 318bb535300SJeff Roberson break; 319bb535300SJeff Roberson 320bb535300SJeff Roberson /* Trap invalid condition variable types: */ 321bb535300SJeff Roberson default: 322bb535300SJeff Roberson COND_UNLOCK(*cond); 323bb535300SJeff Roberson rval = EINVAL; 324bb535300SJeff Roberson break; 325bb535300SJeff Roberson } 326bb535300SJeff Roberson 327bb535300SJeff Roberson /* 328bb535300SJeff Roberson * See if we have to cancel before we retry. We could be 329bb535300SJeff Roberson * canceled with the mutex held here! 330bb535300SJeff Roberson */ 331bb535300SJeff Roberson pthread_testcancel(); 332bb535300SJeff Roberson 333bb535300SJeff Roberson _thread_leave_cancellation_point(); 334bb535300SJeff Roberson 335bb535300SJeff Roberson return (rval); 336bb535300SJeff Roberson } 337bb535300SJeff Roberson 338bb535300SJeff Roberson int 339bb535300SJeff Roberson _pthread_cond_signal(pthread_cond_t * cond) 340bb535300SJeff Roberson { 341bb535300SJeff Roberson struct pthread *curthread = _get_curthread(); 342bb535300SJeff Roberson int rval = 0; 343bb535300SJeff Roberson pthread_t pthread; 344bb535300SJeff Roberson 345bb535300SJeff Roberson if (cond == NULL) 346bb535300SJeff Roberson return (EINVAL); 347bb535300SJeff Roberson /* 348bb535300SJeff Roberson * If the condition variable is statically initialized, perform dynamic 349bb535300SJeff Roberson * initialization. 350bb535300SJeff Roberson */ 351bb535300SJeff Roberson if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) 352bb535300SJeff Roberson return (rval); 353bb535300SJeff Roberson 354bb535300SJeff Roberson 355bb535300SJeff Roberson COND_LOCK(*cond); 356bb535300SJeff Roberson 357bb535300SJeff Roberson /* Process according to condition variable type: */ 358bb535300SJeff Roberson switch ((*cond)->c_type) { 359bb535300SJeff Roberson /* Fast condition variable: */ 360bb535300SJeff Roberson case COND_TYPE_FAST: 361bb535300SJeff Roberson GIANT_LOCK(curthread); 362bb535300SJeff Roberson (*cond)->c_seqno++; 363bb535300SJeff Roberson 364bb535300SJeff Roberson if ((pthread = cond_queue_deq(*cond)) != NULL) { 365bb535300SJeff Roberson /* 366bb535300SJeff Roberson * Wake up the signaled thread: 367bb535300SJeff Roberson */ 368bb535300SJeff Roberson PTHREAD_NEW_STATE(pthread, PS_RUNNING); 369bb535300SJeff Roberson } 370bb535300SJeff Roberson 371bb535300SJeff Roberson GIANT_UNLOCK(curthread); 372bb535300SJeff Roberson break; 373bb535300SJeff Roberson 374bb535300SJeff Roberson /* Trap invalid condition variable types: */ 375bb535300SJeff Roberson default: 376bb535300SJeff Roberson rval = EINVAL; 377bb535300SJeff Roberson break; 378bb535300SJeff Roberson } 379bb535300SJeff Roberson 380bb535300SJeff Roberson 381bb535300SJeff Roberson COND_UNLOCK(*cond); 382bb535300SJeff Roberson 383bb535300SJeff Roberson return (rval); 384bb535300SJeff Roberson } 385bb535300SJeff Roberson 386bb535300SJeff Roberson int 387bb535300SJeff Roberson _pthread_cond_broadcast(pthread_cond_t * cond) 388bb535300SJeff Roberson { 389bb535300SJeff Roberson struct pthread *curthread = _get_curthread(); 390bb535300SJeff Roberson int rval = 0; 391bb535300SJeff Roberson pthread_t pthread; 392bb535300SJeff Roberson 393bb535300SJeff Roberson if (cond == NULL) 394bb535300SJeff Roberson return (EINVAL); 395bb535300SJeff Roberson /* 396bb535300SJeff Roberson * If the condition variable is statically initialized, perform dynamic 397bb535300SJeff Roberson * initialization. 398bb535300SJeff Roberson */ 399bb535300SJeff Roberson if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) 400bb535300SJeff Roberson return (rval); 401bb535300SJeff Roberson 402bb535300SJeff Roberson COND_LOCK(*cond); 403bb535300SJeff Roberson 404bb535300SJeff Roberson /* Process according to condition variable type: */ 405bb535300SJeff Roberson switch ((*cond)->c_type) { 406bb535300SJeff Roberson /* Fast condition variable: */ 407bb535300SJeff Roberson case COND_TYPE_FAST: 408bb535300SJeff Roberson GIANT_LOCK(curthread); 409bb535300SJeff Roberson (*cond)->c_seqno++; 410bb535300SJeff Roberson 411bb535300SJeff Roberson /* 412bb535300SJeff Roberson * Enter a loop to bring all threads off the 413bb535300SJeff Roberson * condition queue: 414bb535300SJeff Roberson */ 415bb535300SJeff Roberson while ((pthread = cond_queue_deq(*cond)) != NULL) { 416bb535300SJeff Roberson /* 417bb535300SJeff Roberson * Wake up the signaled thread: 418bb535300SJeff Roberson */ 419bb535300SJeff Roberson PTHREAD_NEW_STATE(pthread, PS_RUNNING); 420bb535300SJeff Roberson } 421bb535300SJeff Roberson GIANT_UNLOCK(curthread); 422bb535300SJeff Roberson 423bb535300SJeff Roberson /* There are no more waiting threads: */ 424bb535300SJeff Roberson (*cond)->c_mutex = NULL; 425bb535300SJeff Roberson 426bb535300SJeff Roberson break; 427bb535300SJeff Roberson 428bb535300SJeff Roberson /* Trap invalid condition variable types: */ 429bb535300SJeff Roberson default: 430bb535300SJeff Roberson rval = EINVAL; 431bb535300SJeff Roberson break; 432bb535300SJeff Roberson } 433bb535300SJeff Roberson 434bb535300SJeff Roberson COND_UNLOCK(*cond); 435bb535300SJeff Roberson 436bb535300SJeff Roberson 437bb535300SJeff Roberson return (rval); 438bb535300SJeff Roberson } 439bb535300SJeff Roberson 440bb535300SJeff Roberson void 441bb535300SJeff Roberson _cond_wait_backout(pthread_t pthread) 442bb535300SJeff Roberson { 443bb535300SJeff Roberson struct pthread *curthread = _get_curthread(); 444bb535300SJeff Roberson pthread_cond_t cond; 445bb535300SJeff Roberson 446bb535300SJeff Roberson cond = pthread->data.cond; 447bb535300SJeff Roberson if (cond == NULL) 448bb535300SJeff Roberson return; 449bb535300SJeff Roberson 450bb535300SJeff Roberson COND_LOCK(cond); 451bb535300SJeff Roberson 452bb535300SJeff Roberson /* Process according to condition variable type: */ 453bb535300SJeff Roberson switch (cond->c_type) { 454bb535300SJeff Roberson /* Fast condition variable: */ 455bb535300SJeff Roberson case COND_TYPE_FAST: 456bb535300SJeff Roberson GIANT_LOCK(curthread); 457bb535300SJeff Roberson 458bb535300SJeff Roberson cond_queue_remove(cond, pthread); 459bb535300SJeff Roberson 460bb535300SJeff Roberson GIANT_UNLOCK(curthread); 461bb535300SJeff Roberson break; 462bb535300SJeff Roberson 463bb535300SJeff Roberson default: 464bb535300SJeff Roberson break; 465bb535300SJeff Roberson } 466bb535300SJeff Roberson 467bb535300SJeff Roberson COND_UNLOCK(cond); 468bb535300SJeff Roberson } 469bb535300SJeff Roberson 470bb535300SJeff Roberson /* 471bb535300SJeff Roberson * Dequeue a waiting thread from the head of a condition queue in 472bb535300SJeff Roberson * descending priority order. 473bb535300SJeff Roberson */ 474bb535300SJeff Roberson static pthread_t 475bb535300SJeff Roberson cond_queue_deq(pthread_cond_t cond) 476bb535300SJeff Roberson { 477bb535300SJeff Roberson pthread_t pthread; 478bb535300SJeff Roberson 479bb535300SJeff Roberson while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { 480bb535300SJeff Roberson TAILQ_REMOVE(&cond->c_queue, pthread, sqe); 481bb535300SJeff Roberson cond_queue_remove(cond, pthread); 482bb535300SJeff Roberson if ((pthread->cancelflags & PTHREAD_CANCELLING) == 0 && 483bb535300SJeff Roberson pthread->state == PS_COND_WAIT) 484bb535300SJeff Roberson /* 485bb535300SJeff Roberson * Only exit the loop when we find a thread 486bb535300SJeff Roberson * that hasn't timed out or been canceled; 487bb535300SJeff Roberson * those threads are already running and don't 488bb535300SJeff Roberson * need their run state changed. 489bb535300SJeff Roberson */ 490bb535300SJeff Roberson break; 491bb535300SJeff Roberson } 492bb535300SJeff Roberson 493bb535300SJeff Roberson return(pthread); 494bb535300SJeff Roberson } 495bb535300SJeff Roberson 496bb535300SJeff Roberson /* 497bb535300SJeff Roberson * Remove a waiting thread from a condition queue in descending priority 498bb535300SJeff Roberson * order. 499bb535300SJeff Roberson */ 500bb535300SJeff Roberson static void 501bb535300SJeff Roberson cond_queue_remove(pthread_cond_t cond, pthread_t pthread) 502bb535300SJeff Roberson { 503bb535300SJeff Roberson /* 504bb535300SJeff Roberson * Because pthread_cond_timedwait() can timeout as well 505bb535300SJeff Roberson * as be signaled by another thread, it is necessary to 506bb535300SJeff Roberson * guard against removing the thread from the queue if 507bb535300SJeff Roberson * it isn't in the queue. 508bb535300SJeff Roberson */ 509bb535300SJeff Roberson if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) { 510bb535300SJeff Roberson TAILQ_REMOVE(&cond->c_queue, pthread, sqe); 511bb535300SJeff Roberson pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; 512bb535300SJeff Roberson } 513bb535300SJeff Roberson /* Check for no more waiters. */ 514bb535300SJeff Roberson if (TAILQ_FIRST(&cond->c_queue) == NULL) 515bb535300SJeff Roberson cond->c_mutex = NULL; 516bb535300SJeff Roberson } 517bb535300SJeff Roberson 518bb535300SJeff Roberson /* 519bb535300SJeff Roberson * Enqueue a waiting thread to a condition queue in descending priority 520bb535300SJeff Roberson * order. 521bb535300SJeff Roberson */ 522bb535300SJeff Roberson static void 523bb535300SJeff Roberson cond_queue_enq(pthread_cond_t cond, pthread_t pthread) 524bb535300SJeff Roberson { 525bb535300SJeff Roberson pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head); 526bb535300SJeff Roberson 527bb535300SJeff Roberson PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread); 528bb535300SJeff Roberson 529bb535300SJeff Roberson /* 530bb535300SJeff Roberson * For the common case of all threads having equal priority, 531bb535300SJeff Roberson * we perform a quick check against the priority of the thread 532bb535300SJeff Roberson * at the tail of the queue. 533bb535300SJeff Roberson */ 534bb535300SJeff Roberson if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) 535bb535300SJeff Roberson TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe); 536bb535300SJeff Roberson else { 537bb535300SJeff Roberson tid = TAILQ_FIRST(&cond->c_queue); 538bb535300SJeff Roberson while (pthread->active_priority <= tid->active_priority) 539bb535300SJeff Roberson tid = TAILQ_NEXT(tid, sqe); 540bb535300SJeff Roberson TAILQ_INSERT_BEFORE(tid, pthread, sqe); 541bb535300SJeff Roberson } 542bb535300SJeff Roberson pthread->flags |= PTHREAD_FLAGS_IN_CONDQ; 543bb535300SJeff Roberson pthread->data.cond = cond; 544bb535300SJeff Roberson } 545