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); 46a224a391SMike Makonnen static int cond_signal(pthread_cond_t *, int); 47dd3b229eSMike Makonnen static int cond_wait_common(pthread_cond_t *, 48dd3b229eSMike Makonnen pthread_mutex_t *, const struct timespec *); 49bb535300SJeff Roberson 50bb535300SJeff Roberson __weak_reference(_pthread_cond_init, pthread_cond_init); 51bb535300SJeff Roberson __weak_reference(_pthread_cond_destroy, pthread_cond_destroy); 52bb535300SJeff Roberson __weak_reference(_pthread_cond_wait, pthread_cond_wait); 53bb535300SJeff Roberson __weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait); 54bb535300SJeff Roberson __weak_reference(_pthread_cond_signal, pthread_cond_signal); 55bb535300SJeff Roberson __weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); 56bb535300SJeff Roberson 57bb535300SJeff Roberson #define COND_LOCK(c) \ 58bb535300SJeff Roberson do { \ 59bb535300SJeff Roberson if (umtx_lock(&(c)->c_lock, curthread->thr_id)) \ 60bb535300SJeff Roberson abort(); \ 61bb535300SJeff Roberson } while (0) 62bb535300SJeff Roberson 63bb535300SJeff Roberson #define COND_UNLOCK(c) \ 64bb535300SJeff Roberson do { \ 65bb535300SJeff Roberson if (umtx_unlock(&(c)->c_lock, curthread->thr_id)) \ 66bb535300SJeff Roberson abort(); \ 67bb535300SJeff Roberson } while (0) 68bb535300SJeff Roberson 69bb535300SJeff Roberson 70bb535300SJeff Roberson /* Reinitialize a condition variable to defaults. */ 71bb535300SJeff Roberson int 72bb535300SJeff Roberson _cond_reinit(pthread_cond_t *cond) 73bb535300SJeff Roberson { 74bb535300SJeff Roberson if (cond == NULL) 75bb535300SJeff Roberson return (EINVAL); 76bb535300SJeff Roberson 77bb535300SJeff Roberson if (*cond == NULL) 78bb535300SJeff Roberson return (pthread_cond_init(cond, NULL)); 79bb535300SJeff Roberson 80bb535300SJeff Roberson /* 81bb535300SJeff Roberson * Initialize the condition variable structure: 82bb535300SJeff Roberson */ 83bb535300SJeff Roberson TAILQ_INIT(&(*cond)->c_queue); 84bb535300SJeff Roberson (*cond)->c_flags = COND_FLAGS_INITED; 85bb535300SJeff Roberson (*cond)->c_type = COND_TYPE_FAST; 86bb535300SJeff Roberson (*cond)->c_mutex = NULL; 87bb535300SJeff Roberson (*cond)->c_seqno = 0; 88bb535300SJeff Roberson bzero(&(*cond)->c_lock, sizeof((*cond)->c_lock)); 89bb535300SJeff Roberson 90bb535300SJeff Roberson return (0); 91bb535300SJeff Roberson } 92bb535300SJeff Roberson 93bb535300SJeff Roberson int 94bb535300SJeff Roberson _pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 95bb535300SJeff Roberson { 96bb535300SJeff Roberson enum pthread_cond_type type; 97bb535300SJeff Roberson pthread_cond_t pcond; 98bb535300SJeff Roberson 99bb535300SJeff Roberson if (cond == NULL) 100bb535300SJeff Roberson return (EINVAL); 101bb535300SJeff Roberson 102bb535300SJeff Roberson /* 103bb535300SJeff Roberson * Check if a pointer to a condition variable attribute 104bb535300SJeff Roberson * structure was passed by the caller: 105bb535300SJeff Roberson */ 106bb535300SJeff Roberson if (cond_attr != NULL && *cond_attr != NULL) 107bb535300SJeff Roberson type = (*cond_attr)->c_type; 108bb535300SJeff Roberson else 109bb535300SJeff Roberson /* Default to a fast condition variable: */ 110bb535300SJeff Roberson type = COND_TYPE_FAST; 111bb535300SJeff Roberson 112bb535300SJeff Roberson /* Process according to condition variable type: */ 113bb535300SJeff Roberson switch (type) { 114bb535300SJeff Roberson case COND_TYPE_FAST: 115bb535300SJeff Roberson break; 116bb535300SJeff Roberson default: 117bb535300SJeff Roberson return (EINVAL); 118bb535300SJeff Roberson break; 119bb535300SJeff Roberson } 120bb535300SJeff Roberson 121bb535300SJeff Roberson if ((pcond = (pthread_cond_t) 122bb535300SJeff Roberson malloc(sizeof(struct pthread_cond))) == NULL) 123bb535300SJeff Roberson return (ENOMEM); 124bb535300SJeff Roberson /* 125bb535300SJeff Roberson * Initialise the condition variable 126bb535300SJeff Roberson * structure: 127bb535300SJeff Roberson */ 128bb535300SJeff Roberson TAILQ_INIT(&pcond->c_queue); 129bb535300SJeff Roberson pcond->c_flags |= COND_FLAGS_INITED; 130bb535300SJeff Roberson pcond->c_type = type; 131bb535300SJeff Roberson pcond->c_mutex = NULL; 132bb535300SJeff Roberson pcond->c_seqno = 0; 133bb535300SJeff Roberson bzero(&pcond->c_lock, sizeof(pcond->c_lock)); 134bb535300SJeff Roberson 135bb535300SJeff Roberson *cond = pcond; 136bb535300SJeff Roberson 137bb535300SJeff Roberson return (0); 138bb535300SJeff Roberson } 139bb535300SJeff Roberson 140bb535300SJeff Roberson int 141bb535300SJeff Roberson _pthread_cond_destroy(pthread_cond_t *cond) 142bb535300SJeff Roberson { 143bb535300SJeff Roberson if (cond == NULL || *cond == NULL) 144bb535300SJeff Roberson return (EINVAL); 145bb535300SJeff Roberson 146bb535300SJeff Roberson COND_LOCK(*cond); 147bb535300SJeff Roberson 148bb535300SJeff Roberson /* 149bb535300SJeff Roberson * Free the memory allocated for the condition 150bb535300SJeff Roberson * variable structure: 151bb535300SJeff Roberson */ 152bb535300SJeff Roberson free(*cond); 153bb535300SJeff Roberson 154bb535300SJeff Roberson /* 155bb535300SJeff Roberson * NULL the caller's pointer now that the condition 156bb535300SJeff Roberson * variable has been destroyed: 157bb535300SJeff Roberson */ 158bb535300SJeff Roberson *cond = NULL; 159bb535300SJeff Roberson 160bb535300SJeff Roberson return (0); 161bb535300SJeff Roberson } 162bb535300SJeff Roberson 163bb535300SJeff Roberson int 164bb535300SJeff Roberson _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 165bb535300SJeff Roberson { 166bb535300SJeff Roberson int rval; 167bb535300SJeff Roberson 168dd3b229eSMike Makonnen rval = cond_wait_common(cond, mutex, NULL); 169bb535300SJeff Roberson 170bb535300SJeff Roberson /* This should never happen. */ 171bb535300SJeff Roberson if (rval == ETIMEDOUT) 172bb535300SJeff Roberson abort(); 173bb535300SJeff Roberson 174bb535300SJeff Roberson return (rval); 175bb535300SJeff Roberson } 176bb535300SJeff Roberson 177bb535300SJeff Roberson int 178bb535300SJeff Roberson _pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 179bb535300SJeff Roberson const struct timespec * abstime) 180bb535300SJeff Roberson { 181dd3b229eSMike Makonnen if (abstime == NULL || abstime->tv_nsec >= 1000000000) 182dd3b229eSMike Makonnen return (EINVAL); 183dd3b229eSMike Makonnen 184dd3b229eSMike Makonnen return (cond_wait_common(cond, mutex, abstime)); 185dd3b229eSMike Makonnen } 186dd3b229eSMike Makonnen 187dd3b229eSMike Makonnen static int 188dd3b229eSMike Makonnen cond_wait_common(pthread_cond_t * cond, pthread_mutex_t * mutex, 189dd3b229eSMike Makonnen const struct timespec * abstime) 190dd3b229eSMike Makonnen { 191bb535300SJeff Roberson int rval = 0; 192bb535300SJeff Roberson int done = 0; 193bb535300SJeff Roberson int seqno; 194bb535300SJeff Roberson int mtxrval; 195bb535300SJeff Roberson 196bb535300SJeff Roberson 197bb535300SJeff Roberson _thread_enter_cancellation_point(); 198bb535300SJeff Roberson 199a224a391SMike Makonnen if (cond == NULL) 200a224a391SMike Makonnen return (EINVAL); 201bb535300SJeff Roberson /* 202bb535300SJeff Roberson * If the condition variable is statically initialized, perform dynamic 203bb535300SJeff Roberson * initialization. 204bb535300SJeff Roberson */ 205bb535300SJeff Roberson if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) 206bb535300SJeff Roberson return (rval); 207bb535300SJeff Roberson 208bb535300SJeff Roberson 209bb535300SJeff Roberson COND_LOCK(*cond); 210bb535300SJeff Roberson 211bb535300SJeff Roberson /* 212bb535300SJeff Roberson * If the condvar was statically allocated, properly 213bb535300SJeff Roberson * initialize the tail queue. 214bb535300SJeff Roberson */ 215bb535300SJeff Roberson if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { 216bb535300SJeff Roberson TAILQ_INIT(&(*cond)->c_queue); 217bb535300SJeff Roberson (*cond)->c_flags |= COND_FLAGS_INITED; 218bb535300SJeff Roberson } 219bb535300SJeff Roberson 220bb535300SJeff Roberson /* Process according to condition variable type. */ 221bb535300SJeff Roberson 222bb535300SJeff Roberson switch ((*cond)->c_type) { 223bb535300SJeff Roberson /* Fast condition variable: */ 224bb535300SJeff Roberson case COND_TYPE_FAST: 225bb535300SJeff Roberson if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && 226bb535300SJeff Roberson ((*cond)->c_mutex != *mutex))) { 227bb535300SJeff Roberson COND_UNLOCK(*cond); 228bb535300SJeff Roberson rval = EINVAL; 229bb535300SJeff Roberson break; 230bb535300SJeff Roberson } 231bb535300SJeff Roberson /* Remember the mutex */ 232bb535300SJeff Roberson (*cond)->c_mutex = *mutex; 233bb535300SJeff Roberson 234bb535300SJeff Roberson if ((rval = _mutex_cv_unlock(mutex)) != 0) { 235bb535300SJeff Roberson if (rval == -1){ 236bb535300SJeff Roberson printf("foo"); 237bb535300SJeff Roberson fflush(stdout); 238bb535300SJeff Roberson abort(); 239bb535300SJeff Roberson } 240bb535300SJeff Roberson 241bb535300SJeff Roberson COND_UNLOCK(*cond); 242bb535300SJeff Roberson break; 243bb535300SJeff Roberson } 244bb535300SJeff Roberson 245bb535300SJeff Roberson /* 246a224a391SMike Makonnen * We need to protect the queue operations. It also 247a224a391SMike Makonnen * protects c_seqno and the pthread flag fields. This is 248a224a391SMike Makonnen * dropped before calling _thread_suspend() and reaquired 249a224a391SMike Makonnen * when we return. 250bb535300SJeff Roberson */ 251bb535300SJeff Roberson 252a224a391SMike Makonnen _thread_critical_enter(curthread); 253bb535300SJeff Roberson /* 254a224a391SMike Makonnen * c_seqno is protected. 255bb535300SJeff Roberson */ 256bb535300SJeff Roberson seqno = (*cond)->c_seqno; 257bb535300SJeff Roberson 258bb535300SJeff Roberson do { 259bb535300SJeff Roberson /* 260bb535300SJeff Roberson * Queue the running thread on the condition 261bb535300SJeff Roberson * variable. 262bb535300SJeff Roberson */ 263bb535300SJeff Roberson cond_queue_enq(*cond, curthread); 264bb535300SJeff Roberson 265bb535300SJeff Roberson if (curthread->cancelflags & PTHREAD_CANCELLING) { 266bb535300SJeff Roberson /* 267bb535300SJeff Roberson * POSIX Says that we must relock the mutex 268bb535300SJeff Roberson * even if we're being canceled. 269bb535300SJeff Roberson */ 270a224a391SMike Makonnen _thread_critical_exit(curthread); 271a224a391SMike Makonnen COND_UNLOCK(*cond); 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); 278a224a391SMike Makonnen _thread_critical_exit(curthread); 279a224a391SMike Makonnen COND_UNLOCK(*cond); 280dd3b229eSMike Makonnen rval = _thread_suspend(curthread, (struct timespec *)abstime); 281bb535300SJeff Roberson if (rval == -1) { 282bb535300SJeff Roberson printf("foo"); 283bb535300SJeff Roberson fflush(stdout); 284bb535300SJeff Roberson abort(); 285bb535300SJeff Roberson } 286a224a391SMike Makonnen COND_LOCK(*cond); 287a224a391SMike Makonnen _thread_critical_enter(curthread); 288bb535300SJeff Roberson 289bb535300SJeff Roberson done = (seqno != (*cond)->c_seqno); 290bb535300SJeff Roberson 291a224a391SMike Makonnen /* 292a224a391SMike Makonnen * If we timed out, this will remove us from the 293a224a391SMike Makonnen * queue. Otherwise, if we were signaled it does 294a224a391SMike Makonnen * nothing because this thread won't be on the queue. 295a224a391SMike Makonnen */ 296bb535300SJeff Roberson cond_queue_remove(*cond, curthread); 297bb535300SJeff Roberson 298bb535300SJeff Roberson } while ((done == 0) && (rval == 0)); 299bb535300SJeff Roberson /* 300bb535300SJeff Roberson * If we timed out someone still may have signaled us 301bb535300SJeff Roberson * before we got a chance to run again. We check for 302bb535300SJeff Roberson * this by looking to see if our state is RUNNING. 303bb535300SJeff Roberson */ 304bb535300SJeff Roberson if (rval == EAGAIN) { 305bb535300SJeff Roberson if (curthread->state != PS_RUNNING) { 306bb535300SJeff Roberson PTHREAD_SET_STATE(curthread, PS_RUNNING); 307bb535300SJeff Roberson rval = ETIMEDOUT; 308bb535300SJeff Roberson } else 309bb535300SJeff Roberson rval = 0; 310bb535300SJeff Roberson } 311a224a391SMike Makonnen _thread_critical_exit(curthread); 312a224a391SMike Makonnen COND_UNLOCK(*cond); 313bb535300SJeff Roberson 314bb535300SJeff Roberson mtxrval = _mutex_cv_lock(mutex); 315bb535300SJeff Roberson 316bb535300SJeff Roberson /* 317bb535300SJeff Roberson * If the mutex failed return that error, otherwise we're 318bb535300SJeff Roberson * returning ETIMEDOUT. 319bb535300SJeff Roberson */ 320bb535300SJeff Roberson if (mtxrval == -1) { 321bb535300SJeff Roberson printf("foo"); 322bb535300SJeff Roberson fflush(stdout); 323bb535300SJeff Roberson abort(); 324bb535300SJeff Roberson } 325bb535300SJeff Roberson if (mtxrval != 0) 326bb535300SJeff Roberson rval = mtxrval; 327bb535300SJeff Roberson 328bb535300SJeff Roberson break; 329bb535300SJeff Roberson 330bb535300SJeff Roberson /* Trap invalid condition variable types: */ 331bb535300SJeff Roberson default: 332bb535300SJeff Roberson COND_UNLOCK(*cond); 333bb535300SJeff Roberson rval = EINVAL; 334bb535300SJeff Roberson break; 335bb535300SJeff Roberson } 336bb535300SJeff Roberson 337bb535300SJeff Roberson _thread_leave_cancellation_point(); 338bb535300SJeff Roberson 339bb535300SJeff Roberson return (rval); 340bb535300SJeff Roberson } 341bb535300SJeff Roberson 342bb535300SJeff Roberson int 343bb535300SJeff Roberson _pthread_cond_signal(pthread_cond_t * cond) 344bb535300SJeff Roberson { 345a224a391SMike Makonnen return (cond_signal(cond, 0)); 346bb535300SJeff Roberson } 347bb535300SJeff Roberson 348bb535300SJeff Roberson int 349bb535300SJeff Roberson _pthread_cond_broadcast(pthread_cond_t * cond) 350bb535300SJeff Roberson { 351a224a391SMike Makonnen return (cond_signal(cond, 1)); 352a224a391SMike Makonnen } 353a224a391SMike Makonnen 354a224a391SMike Makonnen static int 355a224a391SMike Makonnen cond_signal(pthread_cond_t * cond, int broadcast) 356a224a391SMike Makonnen { 357bb535300SJeff Roberson int rval = 0; 358bb535300SJeff Roberson pthread_t pthread; 359bb535300SJeff Roberson 360bb535300SJeff Roberson if (cond == NULL) 361bb535300SJeff Roberson return (EINVAL); 362bb535300SJeff Roberson /* 363bb535300SJeff Roberson * If the condition variable is statically initialized, perform dynamic 364bb535300SJeff Roberson * initialization. 365bb535300SJeff Roberson */ 366bb535300SJeff Roberson if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) 367bb535300SJeff Roberson return (rval); 368bb535300SJeff Roberson 369bb535300SJeff Roberson COND_LOCK(*cond); 370bb535300SJeff Roberson 371bb535300SJeff Roberson /* Process according to condition variable type: */ 372bb535300SJeff Roberson switch ((*cond)->c_type) { 373bb535300SJeff Roberson /* Fast condition variable: */ 374bb535300SJeff Roberson case COND_TYPE_FAST: 375bb535300SJeff Roberson (*cond)->c_seqno++; 376bb535300SJeff Roberson 377bb535300SJeff Roberson /* 378a224a391SMike Makonnen * Enter a loop to bring all (or only one) threads off the 379bb535300SJeff Roberson * condition queue: 380bb535300SJeff Roberson */ 381a224a391SMike Makonnen do { 382bb535300SJeff Roberson /* 383a224a391SMike Makonnen * Wake up the signaled thread. It will be returned 384a224a391SMike Makonnen * to us locked, and with signals disabled. 385bb535300SJeff Roberson */ 386a224a391SMike Makonnen if ((pthread = cond_queue_deq(*cond)) != NULL) { 387bb535300SJeff Roberson PTHREAD_NEW_STATE(pthread, PS_RUNNING); 388a224a391SMike Makonnen _thread_critical_exit(pthread); 389bb535300SJeff Roberson } 390a224a391SMike Makonnen } while (broadcast && pthread != NULL); 391bb535300SJeff Roberson 392bb535300SJeff Roberson break; 393bb535300SJeff Roberson 394bb535300SJeff Roberson /* Trap invalid condition variable types: */ 395bb535300SJeff Roberson default: 396bb535300SJeff Roberson rval = EINVAL; 397bb535300SJeff Roberson break; 398bb535300SJeff Roberson } 399bb535300SJeff Roberson 400bb535300SJeff Roberson COND_UNLOCK(*cond); 401bb535300SJeff Roberson 402bb535300SJeff Roberson 403bb535300SJeff Roberson return (rval); 404bb535300SJeff Roberson } 405bb535300SJeff Roberson 406bb535300SJeff Roberson void 407bb535300SJeff Roberson _cond_wait_backout(pthread_t pthread) 408bb535300SJeff Roberson { 409bb535300SJeff Roberson pthread_cond_t cond; 410bb535300SJeff Roberson 411bb535300SJeff Roberson cond = pthread->data.cond; 412bb535300SJeff Roberson if (cond == NULL) 413bb535300SJeff Roberson return; 414bb535300SJeff Roberson 415bb535300SJeff Roberson COND_LOCK(cond); 416bb535300SJeff Roberson 417bb535300SJeff Roberson /* Process according to condition variable type: */ 418bb535300SJeff Roberson switch (cond->c_type) { 419bb535300SJeff Roberson /* Fast condition variable: */ 420bb535300SJeff Roberson case COND_TYPE_FAST: 421a224a391SMike Makonnen _thread_critical_enter(curthread); 422bb535300SJeff Roberson 423bb535300SJeff Roberson cond_queue_remove(cond, pthread); 424bb535300SJeff Roberson 425a224a391SMike Makonnen _thread_critical_exit(curthread); 426bb535300SJeff Roberson break; 427bb535300SJeff Roberson 428bb535300SJeff Roberson default: 429bb535300SJeff Roberson break; 430bb535300SJeff Roberson } 431bb535300SJeff Roberson 432bb535300SJeff Roberson COND_UNLOCK(cond); 433bb535300SJeff Roberson } 434bb535300SJeff Roberson 435bb535300SJeff Roberson /* 436bb535300SJeff Roberson * Dequeue a waiting thread from the head of a condition queue in 437bb535300SJeff Roberson * descending priority order. 438bb535300SJeff Roberson */ 439bb535300SJeff Roberson static pthread_t 440bb535300SJeff Roberson cond_queue_deq(pthread_cond_t cond) 441bb535300SJeff Roberson { 442bb535300SJeff Roberson pthread_t pthread; 443bb535300SJeff Roberson 444bb535300SJeff Roberson while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { 445a224a391SMike Makonnen _thread_critical_enter(pthread); 446bb535300SJeff Roberson TAILQ_REMOVE(&cond->c_queue, pthread, sqe); 447bb535300SJeff Roberson cond_queue_remove(cond, pthread); 448bb535300SJeff Roberson if ((pthread->cancelflags & PTHREAD_CANCELLING) == 0 && 449bb535300SJeff Roberson pthread->state == PS_COND_WAIT) 450bb535300SJeff Roberson /* 451bb535300SJeff Roberson * Only exit the loop when we find a thread 452bb535300SJeff Roberson * that hasn't timed out or been canceled; 453bb535300SJeff Roberson * those threads are already running and don't 454bb535300SJeff Roberson * need their run state changed. 455bb535300SJeff Roberson */ 456bb535300SJeff Roberson break; 457a224a391SMike Makonnen else 458a224a391SMike Makonnen _thread_critical_exit(pthread); 459bb535300SJeff Roberson } 460bb535300SJeff Roberson 461bb535300SJeff Roberson return(pthread); 462bb535300SJeff Roberson } 463bb535300SJeff Roberson 464bb535300SJeff Roberson /* 465bb535300SJeff Roberson * Remove a waiting thread from a condition queue in descending priority 466bb535300SJeff Roberson * order. 467bb535300SJeff Roberson */ 468bb535300SJeff Roberson static void 469bb535300SJeff Roberson cond_queue_remove(pthread_cond_t cond, pthread_t pthread) 470bb535300SJeff Roberson { 471bb535300SJeff Roberson /* 472bb535300SJeff Roberson * Because pthread_cond_timedwait() can timeout as well 473bb535300SJeff Roberson * as be signaled by another thread, it is necessary to 474bb535300SJeff Roberson * guard against removing the thread from the queue if 475bb535300SJeff Roberson * it isn't in the queue. 476bb535300SJeff Roberson */ 477bb535300SJeff Roberson if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) { 478bb535300SJeff Roberson TAILQ_REMOVE(&cond->c_queue, pthread, sqe); 479bb535300SJeff Roberson pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; 480bb535300SJeff Roberson } 481bb535300SJeff Roberson /* Check for no more waiters. */ 482bb535300SJeff Roberson if (TAILQ_FIRST(&cond->c_queue) == NULL) 483bb535300SJeff Roberson cond->c_mutex = NULL; 484bb535300SJeff Roberson } 485bb535300SJeff Roberson 486bb535300SJeff Roberson /* 487bb535300SJeff Roberson * Enqueue a waiting thread to a condition queue in descending priority 488bb535300SJeff Roberson * order. 489bb535300SJeff Roberson */ 490bb535300SJeff Roberson static void 491bb535300SJeff Roberson cond_queue_enq(pthread_cond_t cond, pthread_t pthread) 492bb535300SJeff Roberson { 493bb535300SJeff Roberson pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head); 4946439d4c2SMike Makonnen char *name; 495bb535300SJeff Roberson 4966439d4c2SMike Makonnen name = pthread->name ? pthread->name : "unknown"; 4976439d4c2SMike Makonnen if ((pthread->flags & PTHREAD_FLAGS_IN_CONDQ) != 0) 4986439d4c2SMike Makonnen _thread_printf(2, "Thread (%s:%u) already on condq\n", 4996439d4c2SMike Makonnen pthread->name, pthread->uniqueid); 5006439d4c2SMike Makonnen if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) 5016439d4c2SMike Makonnen _thread_printf(2, "Thread (%s:%u) already on mutexq\n", 5026439d4c2SMike Makonnen pthread->name, pthread->uniqueid); 503bb535300SJeff Roberson PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread); 504bb535300SJeff Roberson 505bb535300SJeff Roberson /* 506bb535300SJeff Roberson * For the common case of all threads having equal priority, 507bb535300SJeff Roberson * we perform a quick check against the priority of the thread 508bb535300SJeff Roberson * at the tail of the queue. 509bb535300SJeff Roberson */ 510bb535300SJeff Roberson if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) 511bb535300SJeff Roberson TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe); 512bb535300SJeff Roberson else { 513bb535300SJeff Roberson tid = TAILQ_FIRST(&cond->c_queue); 514bb535300SJeff Roberson while (pthread->active_priority <= tid->active_priority) 515bb535300SJeff Roberson tid = TAILQ_NEXT(tid, sqe); 516bb535300SJeff Roberson TAILQ_INSERT_BEFORE(tid, pthread, sqe); 517bb535300SJeff Roberson } 518bb535300SJeff Roberson pthread->flags |= PTHREAD_FLAGS_IN_CONDQ; 519bb535300SJeff Roberson pthread->data.cond = cond; 520bb535300SJeff Roberson } 521