1bb535300SJeff Roberson /* 2a091d823SDavid Xu * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 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 9a091d823SDavid Xu * notice unmodified, this list of conditions, and the following 10a091d823SDavid Xu * disclaimer. 11bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 12bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the 13bb535300SJeff Roberson * documentation and/or other materials provided with the distribution. 14bb535300SJeff Roberson * 15a091d823SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16a091d823SDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17a091d823SDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18a091d823SDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19a091d823SDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20a091d823SDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21a091d823SDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22a091d823SDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23a091d823SDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24a091d823SDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25bb535300SJeff Roberson * 26bb535300SJeff Roberson * $FreeBSD$ 27bb535300SJeff Roberson */ 28a091d823SDavid Xu 2937a6356bSDavid Xu #include "namespace.h" 30bb535300SJeff Roberson #include <stdlib.h> 31bb535300SJeff Roberson #include <errno.h> 32bb535300SJeff Roberson #include <string.h> 33bb535300SJeff Roberson #include <pthread.h> 34a091d823SDavid Xu #include <limits.h> 3537a6356bSDavid Xu #include "un-namespace.h" 36bb535300SJeff Roberson 37a091d823SDavid Xu #include "thr_private.h" 3841f2bd85SMike Makonnen 3941f2bd85SMike Makonnen /* 40bb535300SJeff Roberson * Prototypes 41bb535300SJeff Roberson */ 4237a6356bSDavid Xu int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); 4337a6356bSDavid Xu int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 4437a6356bSDavid Xu const struct timespec * abstime); 45a091d823SDavid Xu static int cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); 46a091d823SDavid Xu static int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, 47a091d823SDavid Xu const struct timespec *abstime, int cancel); 48*d1078b0bSDavid Xu static int cond_signal_common(pthread_cond_t *cond); 49*d1078b0bSDavid Xu static int cond_broadcast_common(pthread_cond_t *cond); 50a091d823SDavid Xu 51a091d823SDavid Xu /* 52a091d823SDavid Xu * Double underscore versions are cancellation points. Single underscore 53a091d823SDavid Xu * versions are not and are provided for libc internal usage (which 54a091d823SDavid Xu * shouldn't introduce cancellation points). 55a091d823SDavid Xu */ 56a091d823SDavid Xu __weak_reference(__pthread_cond_wait, pthread_cond_wait); 57a091d823SDavid Xu __weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait); 58bb535300SJeff Roberson 59bb535300SJeff Roberson __weak_reference(_pthread_cond_init, pthread_cond_init); 60bb535300SJeff Roberson __weak_reference(_pthread_cond_destroy, pthread_cond_destroy); 61bb535300SJeff Roberson __weak_reference(_pthread_cond_signal, pthread_cond_signal); 62bb535300SJeff Roberson __weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); 63bb535300SJeff Roberson 64*d1078b0bSDavid Xu #define CV_PSHARED(cvp) (((cvp)->__flags & USYNC_PROCESS_SHARED) != 0) 65*d1078b0bSDavid Xu 66a091d823SDavid Xu static int 67a091d823SDavid Xu cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 68bb535300SJeff Roberson { 69*d1078b0bSDavid Xu struct pthread_cond *cvp; 70*d1078b0bSDavid Xu int error = 0; 71a091d823SDavid Xu 72*d1078b0bSDavid Xu if ((cvp = (pthread_cond_t) 732bd2c907SDavid Xu calloc(1, sizeof(struct pthread_cond))) == NULL) { 74*d1078b0bSDavid Xu error = ENOMEM; 75a091d823SDavid Xu } else { 76a091d823SDavid Xu /* 77a091d823SDavid Xu * Initialise the condition variable structure: 78a091d823SDavid Xu */ 79a091d823SDavid Xu if (cond_attr == NULL || *cond_attr == NULL) { 80*d1078b0bSDavid Xu cvp->__clock_id = CLOCK_REALTIME; 81a091d823SDavid Xu } else { 82*d1078b0bSDavid Xu if ((*cond_attr)->c_pshared) 83*d1078b0bSDavid Xu cvp->__flags |= USYNC_PROCESS_SHARED; 84*d1078b0bSDavid Xu cvp->__clock_id = (*cond_attr)->c_clockid; 85a091d823SDavid Xu } 86*d1078b0bSDavid Xu *cond = cvp; 87a091d823SDavid Xu } 88*d1078b0bSDavid Xu return (error); 89a091d823SDavid Xu } 90a091d823SDavid Xu 91a091d823SDavid Xu static int 92a091d823SDavid Xu init_static(struct pthread *thread, pthread_cond_t *cond) 93a091d823SDavid Xu { 94a091d823SDavid Xu int ret; 95a091d823SDavid Xu 96a091d823SDavid Xu THR_LOCK_ACQUIRE(thread, &_cond_static_lock); 97bb535300SJeff Roberson 98bb535300SJeff Roberson if (*cond == NULL) 99a091d823SDavid Xu ret = cond_init(cond, NULL); 100a091d823SDavid Xu else 101a091d823SDavid Xu ret = 0; 102bb535300SJeff Roberson 103a091d823SDavid Xu THR_LOCK_RELEASE(thread, &_cond_static_lock); 104bb535300SJeff Roberson 105a091d823SDavid Xu return (ret); 106bb535300SJeff Roberson } 107bb535300SJeff Roberson 108bbb64c21SDavid Xu #define CHECK_AND_INIT_COND \ 109*d1078b0bSDavid Xu if (__predict_false((cvp = (*cond)) <= THR_COND_DESTROYED)) { \ 110*d1078b0bSDavid Xu if (cvp == THR_COND_INITIALIZER) { \ 111bbb64c21SDavid Xu int ret; \ 112bbb64c21SDavid Xu ret = init_static(_get_curthread(), cond); \ 113bbb64c21SDavid Xu if (ret) \ 114bbb64c21SDavid Xu return (ret); \ 115*d1078b0bSDavid Xu } else if (cvp == THR_COND_DESTROYED) { \ 116bbb64c21SDavid Xu return (EINVAL); \ 117bbb64c21SDavid Xu } \ 118*d1078b0bSDavid Xu cvp = *cond; \ 119bbb64c21SDavid Xu } 120bbb64c21SDavid Xu 121bb535300SJeff Roberson int 122bb535300SJeff Roberson _pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) 123bb535300SJeff Roberson { 124bb535300SJeff Roberson 125a091d823SDavid Xu *cond = NULL; 126a091d823SDavid Xu return (cond_init(cond, cond_attr)); 127bb535300SJeff Roberson } 128bb535300SJeff Roberson 129bb535300SJeff Roberson int 130bb535300SJeff Roberson _pthread_cond_destroy(pthread_cond_t *cond) 131bb535300SJeff Roberson { 132*d1078b0bSDavid Xu struct pthread_cond *cvp; 133*d1078b0bSDavid Xu int error = 0; 134bb535300SJeff Roberson 135*d1078b0bSDavid Xu if ((cvp = *cond) == THR_COND_INITIALIZER) 136*d1078b0bSDavid Xu error = 0; 137*d1078b0bSDavid Xu else if (cvp == THR_COND_DESTROYED) 138*d1078b0bSDavid Xu error = EINVAL; 139a091d823SDavid Xu else { 140*d1078b0bSDavid Xu cvp = *cond; 141bbb64c21SDavid Xu *cond = THR_COND_DESTROYED; 142a091d823SDavid Xu 143a091d823SDavid Xu /* 144a091d823SDavid Xu * Free the memory allocated for the condition 145a091d823SDavid Xu * variable structure: 146a091d823SDavid Xu */ 147*d1078b0bSDavid Xu free(cvp); 148a091d823SDavid Xu } 149*d1078b0bSDavid Xu return (error); 150a091d823SDavid Xu } 151a091d823SDavid Xu 152635f917aSDavid Xu /* 153635f917aSDavid Xu * Cancellation behaivor: 154635f917aSDavid Xu * Thread may be canceled at start, if thread is canceled, it means it 155635f917aSDavid Xu * did not get a wakeup from pthread_cond_signal(), otherwise, it is 156635f917aSDavid Xu * not canceled. 157635f917aSDavid Xu * Thread cancellation never cause wakeup from pthread_cond_signal() 158635f917aSDavid Xu * to be lost. 159635f917aSDavid Xu */ 160a091d823SDavid Xu static int 161*d1078b0bSDavid Xu cond_wait_kernel(struct pthread_cond *cvp, struct pthread_mutex *mp, 162*d1078b0bSDavid Xu const struct timespec *abstime, int cancel) 163*d1078b0bSDavid Xu { 164*d1078b0bSDavid Xu struct pthread *curthread = _get_curthread(); 165*d1078b0bSDavid Xu int recurse; 166*d1078b0bSDavid Xu int error, error2 = 0; 167*d1078b0bSDavid Xu 168*d1078b0bSDavid Xu error = _mutex_cv_detach(mp, &recurse); 169*d1078b0bSDavid Xu if (error != 0) 170*d1078b0bSDavid Xu return (error); 171*d1078b0bSDavid Xu 172*d1078b0bSDavid Xu if (cancel) { 173*d1078b0bSDavid Xu _thr_cancel_enter2(curthread, 0); 174*d1078b0bSDavid Xu error = _thr_ucond_wait((struct ucond *)&cvp->__has_kern_waiters, 175*d1078b0bSDavid Xu (struct umutex *)&mp->m_lock, abstime, 176*d1078b0bSDavid Xu CVWAIT_ABSTIME|CVWAIT_CLOCKID); 177*d1078b0bSDavid Xu _thr_cancel_leave(curthread, 0); 178*d1078b0bSDavid Xu } else { 179*d1078b0bSDavid Xu error = _thr_ucond_wait((struct ucond *)&cvp->__has_kern_waiters, 180*d1078b0bSDavid Xu (struct umutex *)&mp->m_lock, abstime, 181*d1078b0bSDavid Xu CVWAIT_ABSTIME|CVWAIT_CLOCKID); 182*d1078b0bSDavid Xu } 183*d1078b0bSDavid Xu 184*d1078b0bSDavid Xu /* 185*d1078b0bSDavid Xu * Note that PP mutex and ROBUST mutex may return 186*d1078b0bSDavid Xu * interesting error codes. 187*d1078b0bSDavid Xu */ 188*d1078b0bSDavid Xu if (error == 0) { 189*d1078b0bSDavid Xu error2 = _mutex_cv_lock(mp, recurse); 190*d1078b0bSDavid Xu } else if (error == EINTR || error == ETIMEDOUT) { 191*d1078b0bSDavid Xu error2 = _mutex_cv_lock(mp, recurse); 192*d1078b0bSDavid Xu if (error2 == 0 && cancel) 193*d1078b0bSDavid Xu _thr_testcancel(curthread); 194*d1078b0bSDavid Xu if (error == EINTR) 195*d1078b0bSDavid Xu error = 0; 196*d1078b0bSDavid Xu } else { 197*d1078b0bSDavid Xu /* We know that it didn't unlock the mutex. */ 198*d1078b0bSDavid Xu error2 = _mutex_cv_attach(mp, recurse); 199*d1078b0bSDavid Xu if (error2 == 0 && cancel) 200*d1078b0bSDavid Xu _thr_testcancel(curthread); 201*d1078b0bSDavid Xu } 202*d1078b0bSDavid Xu return (error2 != 0 ? error2 : error); 203*d1078b0bSDavid Xu } 204*d1078b0bSDavid Xu 205*d1078b0bSDavid Xu /* 206*d1078b0bSDavid Xu * Thread waits in userland queue whenever possible, when thread 207*d1078b0bSDavid Xu * is signaled or broadcasted, it is removed from the queue, and 208*d1078b0bSDavid Xu * is saved in curthread's defer_waiters[] buffer, but won't be 209*d1078b0bSDavid Xu * woken up until mutex is unlocked. 210*d1078b0bSDavid Xu */ 211*d1078b0bSDavid Xu 212*d1078b0bSDavid Xu static int 213*d1078b0bSDavid Xu cond_wait_user(struct pthread_cond *cvp, struct pthread_mutex *mp, 214*d1078b0bSDavid Xu const struct timespec *abstime, int cancel) 215*d1078b0bSDavid Xu { 216*d1078b0bSDavid Xu struct pthread *curthread = _get_curthread(); 217*d1078b0bSDavid Xu struct sleepqueue *sq; 218*d1078b0bSDavid Xu int recurse; 219*d1078b0bSDavid Xu int error; 220*d1078b0bSDavid Xu 221*d1078b0bSDavid Xu if (curthread->wchan != NULL) 222*d1078b0bSDavid Xu PANIC("thread was already on queue."); 223*d1078b0bSDavid Xu 224*d1078b0bSDavid Xu if (cancel) 225*d1078b0bSDavid Xu _thr_testcancel(curthread); 226*d1078b0bSDavid Xu 227*d1078b0bSDavid Xu _sleepq_lock(cvp); 228*d1078b0bSDavid Xu /* 229*d1078b0bSDavid Xu * set __has_user_waiters before unlocking mutex, this allows 230*d1078b0bSDavid Xu * us to check it without locking in pthread_cond_signal(). 231*d1078b0bSDavid Xu */ 232*d1078b0bSDavid Xu cvp->__has_user_waiters = 1; 233*d1078b0bSDavid Xu curthread->will_sleep = 1; 234*d1078b0bSDavid Xu (void)_mutex_cv_unlock(mp, &recurse); 235*d1078b0bSDavid Xu curthread->mutex_obj = mp; 236*d1078b0bSDavid Xu _sleepq_add(cvp, curthread); 237*d1078b0bSDavid Xu for(;;) { 238*d1078b0bSDavid Xu _thr_clear_wake(curthread); 239*d1078b0bSDavid Xu _sleepq_unlock(cvp); 240*d1078b0bSDavid Xu 241*d1078b0bSDavid Xu if (cancel) { 242*d1078b0bSDavid Xu _thr_cancel_enter2(curthread, 0); 243*d1078b0bSDavid Xu error = _thr_sleep(curthread, cvp->__clock_id, abstime); 244*d1078b0bSDavid Xu _thr_cancel_leave(curthread, 0); 245*d1078b0bSDavid Xu } else { 246*d1078b0bSDavid Xu error = _thr_sleep(curthread, cvp->__clock_id, abstime); 247*d1078b0bSDavid Xu } 248*d1078b0bSDavid Xu 249*d1078b0bSDavid Xu if (curthread->wchan == NULL) { 250*d1078b0bSDavid Xu error = 0; 251*d1078b0bSDavid Xu goto out; 252*d1078b0bSDavid Xu } 253*d1078b0bSDavid Xu 254*d1078b0bSDavid Xu _sleepq_lock(cvp); 255*d1078b0bSDavid Xu if (curthread->wchan == NULL) { 256*d1078b0bSDavid Xu error = 0; 257*d1078b0bSDavid Xu break; 258*d1078b0bSDavid Xu } else if (cancel && SHOULD_CANCEL(curthread)) { 259*d1078b0bSDavid Xu sq = _sleepq_lookup(cvp); 260*d1078b0bSDavid Xu cvp->__has_user_waiters = 261*d1078b0bSDavid Xu _sleepq_remove(sq, curthread); 262*d1078b0bSDavid Xu _sleepq_unlock(cvp); 263*d1078b0bSDavid Xu curthread->mutex_obj = NULL; 264*d1078b0bSDavid Xu _mutex_cv_lock(mp, recurse); 265*d1078b0bSDavid Xu if (!THR_IN_CRITICAL(curthread)) 266*d1078b0bSDavid Xu _pthread_exit(PTHREAD_CANCELED); 267*d1078b0bSDavid Xu else /* this should not happen */ 268*d1078b0bSDavid Xu return (0); 269*d1078b0bSDavid Xu } else if (error == ETIMEDOUT) { 270*d1078b0bSDavid Xu sq = _sleepq_lookup(cvp); 271*d1078b0bSDavid Xu cvp->__has_user_waiters = 272*d1078b0bSDavid Xu _sleepq_remove(sq, curthread); 273*d1078b0bSDavid Xu break; 274*d1078b0bSDavid Xu } 275*d1078b0bSDavid Xu } 276*d1078b0bSDavid Xu _sleepq_unlock(cvp); 277*d1078b0bSDavid Xu out: 278*d1078b0bSDavid Xu curthread->mutex_obj = NULL; 279*d1078b0bSDavid Xu _mutex_cv_lock(mp, recurse); 280*d1078b0bSDavid Xu return (error); 281*d1078b0bSDavid Xu } 282*d1078b0bSDavid Xu 283*d1078b0bSDavid Xu static int 284a091d823SDavid Xu cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, 285a091d823SDavid Xu const struct timespec *abstime, int cancel) 286a091d823SDavid Xu { 287a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 288*d1078b0bSDavid Xu struct pthread_cond *cvp; 289*d1078b0bSDavid Xu struct pthread_mutex *mp; 290*d1078b0bSDavid Xu int error; 291a091d823SDavid Xu 292bbb64c21SDavid Xu CHECK_AND_INIT_COND 293635f917aSDavid Xu 294*d1078b0bSDavid Xu mp = *mutex; 2952bd2c907SDavid Xu 296*d1078b0bSDavid Xu if ((error = _mutex_owned(curthread, mp)) != 0) 297*d1078b0bSDavid Xu return (error); 298a091d823SDavid Xu 299*d1078b0bSDavid Xu if (curthread->attr.sched_policy != SCHED_OTHER || 300*d1078b0bSDavid Xu (mp->m_lock.m_flags & (UMUTEX_PRIO_PROTECT|UMUTEX_PRIO_INHERIT| 301*d1078b0bSDavid Xu USYNC_PROCESS_SHARED)) != 0 || 302*d1078b0bSDavid Xu (cvp->__flags & USYNC_PROCESS_SHARED) != 0) 303*d1078b0bSDavid Xu return cond_wait_kernel(cvp, mp, abstime, cancel); 304*d1078b0bSDavid Xu else 305*d1078b0bSDavid Xu return cond_wait_user(cvp, mp, abstime, cancel); 306bb535300SJeff Roberson } 307bb535300SJeff Roberson 308bb535300SJeff Roberson int 309bb535300SJeff Roberson _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 310bb535300SJeff Roberson { 311bb535300SJeff Roberson 312a091d823SDavid Xu return (cond_wait_common(cond, mutex, NULL, 0)); 313a091d823SDavid Xu } 314bb535300SJeff Roberson 315a091d823SDavid Xu int 316a091d823SDavid Xu __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) 317a091d823SDavid Xu { 318bb535300SJeff Roberson 319a091d823SDavid Xu return (cond_wait_common(cond, mutex, NULL, 1)); 320bb535300SJeff Roberson } 321bb535300SJeff Roberson 322bb535300SJeff Roberson int 323bb535300SJeff Roberson _pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 324bb535300SJeff Roberson const struct timespec * abstime) 325bb535300SJeff Roberson { 326a091d823SDavid Xu 327a091d823SDavid Xu if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 328a091d823SDavid Xu abstime->tv_nsec >= 1000000000) 329dd3b229eSMike Makonnen return (EINVAL); 330dd3b229eSMike Makonnen 331a091d823SDavid Xu return (cond_wait_common(cond, mutex, abstime, 0)); 332a091d823SDavid Xu } 333a091d823SDavid Xu 334a091d823SDavid Xu int 335a091d823SDavid Xu __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, 336a091d823SDavid Xu const struct timespec *abstime) 337a091d823SDavid Xu { 338a091d823SDavid Xu 339a091d823SDavid Xu if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || 340a091d823SDavid Xu abstime->tv_nsec >= 1000000000) 341a091d823SDavid Xu return (EINVAL); 342a091d823SDavid Xu 343a091d823SDavid Xu return (cond_wait_common(cond, mutex, abstime, 1)); 344dd3b229eSMike Makonnen } 345dd3b229eSMike Makonnen 346dd3b229eSMike Makonnen static int 347*d1078b0bSDavid Xu cond_signal_common(pthread_cond_t *cond) 348dd3b229eSMike Makonnen { 349a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 350*d1078b0bSDavid Xu struct pthread *td; 351*d1078b0bSDavid Xu struct pthread_cond *cvp; 352*d1078b0bSDavid Xu struct pthread_mutex *mp; 353*d1078b0bSDavid Xu struct sleepqueue *sq; 354*d1078b0bSDavid Xu int *waddr; 355*d1078b0bSDavid Xu int pshared; 356bb535300SJeff Roberson 357bb535300SJeff Roberson /* 358bb535300SJeff Roberson * If the condition variable is statically initialized, perform dynamic 359bb535300SJeff Roberson * initialization. 360bb535300SJeff Roberson */ 361bbb64c21SDavid Xu CHECK_AND_INIT_COND 362bb535300SJeff Roberson 363*d1078b0bSDavid Xu pshared = CV_PSHARED(cvp); 364*d1078b0bSDavid Xu 365*d1078b0bSDavid Xu _thr_ucond_signal((struct ucond *)&cvp->__has_kern_waiters); 366*d1078b0bSDavid Xu 367*d1078b0bSDavid Xu if (pshared || cvp->__has_user_waiters == 0) 368*d1078b0bSDavid Xu return (0); 369*d1078b0bSDavid Xu 370*d1078b0bSDavid Xu curthread = _get_curthread(); 371*d1078b0bSDavid Xu waddr = NULL; 372*d1078b0bSDavid Xu _sleepq_lock(cvp); 373*d1078b0bSDavid Xu sq = _sleepq_lookup(cvp); 374*d1078b0bSDavid Xu if (sq == NULL) { 375*d1078b0bSDavid Xu _sleepq_unlock(cvp); 376*d1078b0bSDavid Xu return (0); 377*d1078b0bSDavid Xu } 378*d1078b0bSDavid Xu 379*d1078b0bSDavid Xu td = _sleepq_first(sq); 380*d1078b0bSDavid Xu mp = td->mutex_obj; 381*d1078b0bSDavid Xu cvp->__has_user_waiters = _sleepq_remove(sq, td); 382*d1078b0bSDavid Xu if (mp->m_owner == curthread) { 383*d1078b0bSDavid Xu if (curthread->nwaiter_defer >= MAX_DEFER_WAITERS) { 384*d1078b0bSDavid Xu _thr_wake_all(curthread->defer_waiters, 385*d1078b0bSDavid Xu curthread->nwaiter_defer); 386*d1078b0bSDavid Xu curthread->nwaiter_defer = 0; 387*d1078b0bSDavid Xu } 388*d1078b0bSDavid Xu curthread->defer_waiters[curthread->nwaiter_defer++] = 389*d1078b0bSDavid Xu &td->wake_addr->value; 390*d1078b0bSDavid Xu mp->m_flags |= PMUTEX_FLAG_DEFERED; 391*d1078b0bSDavid Xu } else { 392*d1078b0bSDavid Xu waddr = &td->wake_addr->value; 393*d1078b0bSDavid Xu } 394*d1078b0bSDavid Xu _sleepq_unlock(cvp); 395*d1078b0bSDavid Xu if (waddr != NULL) 396*d1078b0bSDavid Xu _thr_set_wake(waddr); 397*d1078b0bSDavid Xu return (0); 398*d1078b0bSDavid Xu } 399*d1078b0bSDavid Xu 400*d1078b0bSDavid Xu struct broadcast_arg { 401*d1078b0bSDavid Xu struct pthread *curthread; 402*d1078b0bSDavid Xu unsigned int *waddrs[MAX_DEFER_WAITERS]; 403*d1078b0bSDavid Xu int count; 404*d1078b0bSDavid Xu }; 405*d1078b0bSDavid Xu 406*d1078b0bSDavid Xu static void 407*d1078b0bSDavid Xu drop_cb(struct pthread *td, void *arg) 408*d1078b0bSDavid Xu { 409*d1078b0bSDavid Xu struct broadcast_arg *ba = arg; 410*d1078b0bSDavid Xu struct pthread_mutex *mp; 411*d1078b0bSDavid Xu struct pthread *curthread = ba->curthread; 412*d1078b0bSDavid Xu 413*d1078b0bSDavid Xu mp = td->mutex_obj; 414*d1078b0bSDavid Xu if (mp->m_owner == curthread) { 415*d1078b0bSDavid Xu if (curthread->nwaiter_defer >= MAX_DEFER_WAITERS) { 416*d1078b0bSDavid Xu _thr_wake_all(curthread->defer_waiters, 417*d1078b0bSDavid Xu curthread->nwaiter_defer); 418*d1078b0bSDavid Xu curthread->nwaiter_defer = 0; 419*d1078b0bSDavid Xu } 420*d1078b0bSDavid Xu curthread->defer_waiters[curthread->nwaiter_defer++] = 421*d1078b0bSDavid Xu &td->wake_addr->value; 422*d1078b0bSDavid Xu mp->m_flags |= PMUTEX_FLAG_DEFERED; 423*d1078b0bSDavid Xu } else { 424*d1078b0bSDavid Xu if (ba->count >= MAX_DEFER_WAITERS) { 425*d1078b0bSDavid Xu _thr_wake_all(ba->waddrs, ba->count); 426*d1078b0bSDavid Xu ba->count = 0; 427*d1078b0bSDavid Xu } 428*d1078b0bSDavid Xu ba->waddrs[ba->count++] = &td->wake_addr->value; 429*d1078b0bSDavid Xu } 430*d1078b0bSDavid Xu } 431*d1078b0bSDavid Xu 432*d1078b0bSDavid Xu static int 433*d1078b0bSDavid Xu cond_broadcast_common(pthread_cond_t *cond) 434*d1078b0bSDavid Xu { 435*d1078b0bSDavid Xu int pshared; 436*d1078b0bSDavid Xu struct pthread_cond *cvp; 437*d1078b0bSDavid Xu struct sleepqueue *sq; 438*d1078b0bSDavid Xu struct broadcast_arg ba; 439*d1078b0bSDavid Xu 440*d1078b0bSDavid Xu /* 441*d1078b0bSDavid Xu * If the condition variable is statically initialized, perform dynamic 442*d1078b0bSDavid Xu * initialization. 443*d1078b0bSDavid Xu */ 444*d1078b0bSDavid Xu CHECK_AND_INIT_COND 445*d1078b0bSDavid Xu 446*d1078b0bSDavid Xu pshared = CV_PSHARED(cvp); 447*d1078b0bSDavid Xu 448*d1078b0bSDavid Xu _thr_ucond_broadcast((struct ucond *)&cvp->__has_kern_waiters); 449*d1078b0bSDavid Xu 450*d1078b0bSDavid Xu if (pshared || cvp->__has_user_waiters == 0) 451*d1078b0bSDavid Xu return (0); 452*d1078b0bSDavid Xu 453*d1078b0bSDavid Xu ba.curthread = _get_curthread(); 454*d1078b0bSDavid Xu ba.count = 0; 455*d1078b0bSDavid Xu 456*d1078b0bSDavid Xu _sleepq_lock(cvp); 457*d1078b0bSDavid Xu sq = _sleepq_lookup(cvp); 458*d1078b0bSDavid Xu if (sq == NULL) { 459*d1078b0bSDavid Xu _sleepq_unlock(cvp); 460*d1078b0bSDavid Xu return (0); 461*d1078b0bSDavid Xu } 462*d1078b0bSDavid Xu _sleepq_drop(sq, drop_cb, &ba); 463*d1078b0bSDavid Xu cvp->__has_user_waiters = 0; 464*d1078b0bSDavid Xu _sleepq_unlock(cvp); 465*d1078b0bSDavid Xu if (ba.count > 0) 466*d1078b0bSDavid Xu _thr_wake_all(ba.waddrs, ba.count); 467*d1078b0bSDavid Xu return (0); 468bb535300SJeff Roberson } 469bb535300SJeff Roberson 470bb535300SJeff Roberson int 471bb535300SJeff Roberson _pthread_cond_signal(pthread_cond_t * cond) 472bb535300SJeff Roberson { 473a091d823SDavid Xu 474*d1078b0bSDavid Xu return (cond_signal_common(cond)); 475bb535300SJeff Roberson } 476bb535300SJeff Roberson 477bb535300SJeff Roberson int 478bb535300SJeff Roberson _pthread_cond_broadcast(pthread_cond_t * cond) 479bb535300SJeff Roberson { 480a091d823SDavid Xu 481*d1078b0bSDavid Xu return (cond_broadcast_common(cond)); 482a224a391SMike Makonnen } 483