xref: /dragonfly/sys/kern/kern_condvar.c (revision 3426d2c2)
1 #include <sys/condvar.h>
2 #include <sys/spinlock2.h>
3 #include <sys/systm.h>
4 #include <sys/lock.h>
5 
6 void
cv_init(struct cv * c,const char * desc)7 cv_init(struct cv *c, const char *desc)
8 {
9 	c->cv_desc = desc;
10 	c->cv_waiters = 0;
11 	spin_init(&c->cv_lock, "cvinit");
12 }
13 
14 void
cv_destroy(struct cv * c)15 cv_destroy(struct cv *c)
16 {
17 	spin_uninit(&c->cv_lock);
18 }
19 
20 int
_cv_timedwait(struct cv * c,struct lock * lk,int timo,int wakesig)21 _cv_timedwait(struct cv *c, struct lock *lk, int timo, int wakesig)
22 {
23 	int flags = wakesig ? PCATCH : 0;
24 	int error;
25 
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 	 */
32 	tsleep_interlock(c, flags);
33 
34 	spin_lock(&c->cv_lock);
35 	c->cv_waiters++;
36 	spin_unlock(&c->cv_lock);
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);
42 
43 	return (error);
44 }
45 
46 /*
47  * _cv_timedwait() implementation using mtx.
48  */
49 int
_cv_mtx_timedwait(struct cv * c,struct mtx * mtx,int timo,int wakesig)50 _cv_mtx_timedwait(struct cv *c, struct mtx *mtx, int timo, int wakesig)
51 {
52 	int flags = wakesig ? PCATCH : 0;
53 	int error;
54 
55 	/*
56 	 * Can interlock without critical section/spinlock as long
57 	 * as we don't block before calling *sleep().  PINTERLOCKED
58 	 * must be passed to the *sleep() to use the manual interlock
59 	 * (else a new one is created which opens a timing race).
60 	 */
61 	tsleep_interlock(c, flags);
62 
63 	spin_lock(&c->cv_lock);
64 	c->cv_waiters++;
65 	spin_unlock(&c->cv_lock);
66 
67 	if (mtx)
68 		error = mtxsleep(c, mtx, flags | PINTERLOCKED, c->cv_desc, timo);
69 	else
70 		error = tsleep(c, flags | PINTERLOCKED, c->cv_desc, timo);
71 
72 	return (error);
73 }
74 
75 void
_cv_signal(struct cv * c,int broadcast)76 _cv_signal(struct cv *c, int broadcast)
77 {
78 	spin_lock(&c->cv_lock);
79 	if (c->cv_waiters == 0) {
80 		spin_unlock(&c->cv_lock);
81 	} else if (broadcast) {
82 		c->cv_waiters = 0;
83 		spin_unlock(&c->cv_lock);	/* must unlock first */
84 		wakeup(c);
85 	} else {
86 		c->cv_waiters--;
87 		spin_unlock(&c->cv_lock);	/* must unlock first */
88 		wakeup_one(c);
89 	}
90 }
91 
92 int
cv_has_waiters(const struct cv * c)93 cv_has_waiters(const struct cv *c)
94 {
95 	return (c->cv_waiters);
96 }
97