X-Git-Url: http://nsz.repo.hu/git/?p=musl;a=blobdiff_plain;f=src%2Fthread%2Fpthread_cond_broadcast.c;h=7e5ea91c507401525d4616fe0154b8fb01fe39b8;hp=6002c53507be55152328caacd3394614daa0dffd;hb=c11d1e696723f41d7873332e51fb6858b417fa5f;hpb=4b153ac42428447a148e6da543ebe6df017078db diff --git a/src/thread/pthread_cond_broadcast.c b/src/thread/pthread_cond_broadcast.c index 6002c535..7e5ea91c 100644 --- a/src/thread/pthread_cond_broadcast.c +++ b/src/thread/pthread_cond_broadcast.c @@ -1,9 +1,48 @@ #include "pthread_impl.h" +static void unlock(pthread_cond_t *c) +{ + a_dec(&c->_c_bcast); + if (c->_c_leavers) __wake(&c->_c_bcast, -1, 0); +} + int pthread_cond_broadcast(pthread_cond_t *c) { - int w = c->_c_waiters; - if (a_swap(&c->_c_block, 0) || w) + pthread_mutex_t *m; + int w; + + if (!c->_c_waiters) return 0; + a_inc(&c->_c_bcast); + if (!c->_c_waiters) { + unlock(c); + return 0; + } + + a_store(&c->_c_block, 0); + + m = c->_c_mutex; + + /* If mutex ptr is not available, simply wake all waiters. */ + if (m == (void *)-1) { + unlock(c); __wake(&c->_c_block, -1, 0); + return 0; + } + + /* Move waiter count to the mutex */ + for (;;) { + w = c->_c_waiters; + a_fetch_add(&m->_m_waiters, w); + if (a_cas(&c->_c_waiters, w, 0) == w) break; + a_fetch_add(&m->_m_waiters, -w); + } + + /* Perform the futex requeue, waking one waiter unless we know + * that the calling thread holds the mutex. */ + __syscall(SYS_futex, &c->_c_block, FUTEX_REQUEUE, + !m->_m_type || (m->_m_lock&INT_MAX)!=pthread_self()->tid, + INT_MAX, &m->_m_lock); + + unlock(c); return 0; }