#include "pthread_impl.h" #include static int __cnd_broadcast(__cnd_t *c) { int ret = 0; __mtx_t * mtx = c->mtx; /* If the mtx isn't set, this __cnd has never been used for a wait, nothing to do. */ if (mtx) { /* Perform the futex requeue, waking one waiter unless we know * that the calling thread holds the mutex. */ int wakeup = !mtx->_mt_typ || (mtx->_mt_lck&INT_MAX)!=__pthread_self()->tid; ret = __syscall(SYS_futex, &c->tok, FUTEX_REQUEUE|THRD_PRIVATE, 0, INT_MAX, &mtx->_mt_lck); if (ret < 0) goto OUT; int mv = ret; ret = __syscall(SYS_futex, &c->seq, FUTEX_REQUEUE|THRD_PRIVATE, 0, INT_MAX, &mtx->_mt_lck); if (ret < 0) goto OUT; mv += ret; /* Do the bookkeeping for the mutex and wake up one thread eventually. */ if (mv > wakeup) a_fetch_add(&mtx->_mt_wts, mv-wakeup); if (mv > 0 && wakeup) ret = __syscall(SYS_futex, &mtx->_mt_lck, FUTEX_WAKE|THRD_PRIVATE, 1); } OUT: return ret < 0 ? thrd_error : thrd_success; } int cnd_broadcast(cnd_t * cond) { int ret = thrd_success; int wakeup = 0; /* Avoid fight for critical section if there is nothing to do. */ if (!cond || !cond->_cx_cnd) return ret; /* Critical section protected by lock */ __lock(&cond->_cx_lock); __cnd_t * c = cond->_cx_cnd; /* If there are waiters, all will be waiting on c. Since we hold the lock no other waiters can sneak in. Lock them permanently out of using this one, here. As a consequence we don't have inc the reference count: there is no change in the total number of references. */ if (c) { ++c->seq; wakeup = c->wts; if (wakeup) { cond->_cx_cnd = 0; c->wts = 0; } else { c = 0; } } __unlock(&cond->_cx_lock); /* If c is 0, there haven't been any waiters, yet, nothing to do. */ if (c) { a_fetch_add(&c->tok, wakeup); ret = __cnd_broadcast(c); __cnd_unref(c); } return ret; }