1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
| | #include "pthread_impl.h"
#include <threads.h>
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;
}
|