kernel - Fix condvar races
[dragonfly.git] / sys / kern / kern_condvar.c
CommitLineData
6830d0fc
SS
1#include <sys/condvar.h>
2#include <sys/spinlock2.h>
3#include <sys/systm.h>
4#include <sys/lock.h>
5
6void
7cv_init(struct cv *c, const char *desc)
8{
9 c->cv_desc = desc;
10 c->cv_waiters = 0;
11 spin_init(&c->cv_lock);
12}
13
14void
15cv_destroy(struct cv *c)
16{
17 spin_uninit(&c->cv_lock);
18}
19
20int
a5fcdfa4 21_cv_timedwait(struct cv *c, struct lock *lk, int timo, int wakesig)
6830d0fc
SS
22{
23 int flags = wakesig ? PCATCH : 0;
24 int error;
25
a5fcdfa4
MD
26 /*
27 * Can interlock without critical section/spinlock as long
28 * as we don't block before calling *sleep(). PINTERLOCKED
29 * must be passed to the *sleep() to use the manual interlock
30 * (else a new one is created which opens a timing race).
31 */
6830d0fc 32 tsleep_interlock(c, flags);
a5fcdfa4
MD
33
34 spin_lock(&c->cv_lock);
6830d0fc 35 c->cv_waiters++;
287a8577 36 spin_unlock(&c->cv_lock);
a5fcdfa4
MD
37
38 if (lk)
39 error = lksleep(c, lk, flags | PINTERLOCKED, c->cv_desc, timo);
40 else
41 error = tsleep(c, flags | PINTERLOCKED, c->cv_desc, timo);
6830d0fc
SS
42
43 return (error);
44}
45
46void
47_cv_signal(struct cv *c, int broadcast)
48{
287a8577 49 spin_lock(&c->cv_lock);
a5fcdfa4
MD
50 if (c->cv_waiters == 0) {
51 spin_unlock(&c->cv_lock);
52 } else if (broadcast) {
6830d0fc 53 c->cv_waiters = 0;
a5fcdfa4 54 spin_unlock(&c->cv_lock); /* must unlock first */
6830d0fc
SS
55 wakeup(c);
56 } else {
57 c->cv_waiters--;
a5fcdfa4 58 spin_unlock(&c->cv_lock); /* must unlock first */
6830d0fc
SS
59 wakeup_one(c);
60 }
6830d0fc 61}
70f34aab
AH
62
63int
c67284ab 64cv_has_waiters(const struct cv *c)
70f34aab
AH
65{
66 return (c->cv_waiters);
67}