xref: /freebsd/sys/kern/kern_condvar.c (revision 01518f5eede79cf65319d455eb50e78c9efa2b51)
1238510fcSJason Evans /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
38a36da99SPedro F. Giffuni  *
4238510fcSJason Evans  * Copyright (c) 2000 Jake Burkholder <jake@freebsd.org>.
5238510fcSJason Evans  * All rights reserved.
6238510fcSJason Evans  *
7238510fcSJason Evans  * Redistribution and use in source and binary forms, with or without
8238510fcSJason Evans  * modification, are permitted provided that the following conditions
9238510fcSJason Evans  * are met:
10238510fcSJason Evans  * 1. Redistributions of source code must retain the above copyright
11238510fcSJason Evans  *    notice, this list of conditions and the following disclaimer.
12238510fcSJason Evans  * 2. Redistributions in binary form must reproduce the above copyright
13238510fcSJason Evans  *    notice, this list of conditions and the following disclaimer in the
14238510fcSJason Evans  *    documentation and/or other materials provided with the distribution.
15238510fcSJason Evans  *
16238510fcSJason Evans  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17238510fcSJason Evans  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18238510fcSJason Evans  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19238510fcSJason Evans  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20238510fcSJason Evans  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21238510fcSJason Evans  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22238510fcSJason Evans  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23238510fcSJason Evans  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24238510fcSJason Evans  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25238510fcSJason Evans  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26238510fcSJason Evans  * SUCH DAMAGE.
27238510fcSJason Evans  */
28238510fcSJason Evans 
29677b542eSDavid E. O'Brien #include <sys/cdefs.h>
30238510fcSJason Evans #include "opt_ktrace.h"
31238510fcSJason Evans 
32238510fcSJason Evans #include <sys/param.h>
33238510fcSJason Evans #include <sys/systm.h>
3411f9ca69SMark Johnston #include <sys/limits.h>
35fb919e4dSMark Murray #include <sys/lock.h>
36fb919e4dSMark Murray #include <sys/mutex.h>
37238510fcSJason Evans #include <sys/proc.h>
38238510fcSJason Evans #include <sys/kernel.h>
39238510fcSJason Evans #include <sys/ktr.h>
40a58813fdSMark Johnston #include <sys/ktrace.h>
41238510fcSJason Evans #include <sys/condvar.h>
424e997f4bSJeff Roberson #include <sys/sched.h>
43238510fcSJason Evans #include <sys/signalvar.h>
4444f3b092SJohn Baldwin #include <sys/sleepqueue.h>
45238510fcSJason Evans #include <sys/resourcevar.h>
46238510fcSJason Evans #ifdef KTRACE
47a5ef95cdSMark Johnston #include <sys/uio.h>
48a5ef95cdSMark Johnston #include <sys/user.h>
49238510fcSJason Evans #endif
50238510fcSJason Evans 
51238510fcSJason Evans /*
5211f9ca69SMark Johnston  * A bound below which cv_waiters is valid.  Once cv_waiters reaches this bound,
5311f9ca69SMark Johnston  * cv_signal must manually check the wait queue for threads.
5411f9ca69SMark Johnston  */
5511f9ca69SMark Johnston #define	CV_WAITERS_BOUND	INT_MAX
5611f9ca69SMark Johnston 
5711f9ca69SMark Johnston #define	CV_WAITERS_INC(cvp) do {					\
5811f9ca69SMark Johnston 	if ((cvp)->cv_waiters < CV_WAITERS_BOUND)			\
5911f9ca69SMark Johnston 		(cvp)->cv_waiters++;					\
6011f9ca69SMark Johnston } while (0)
6111f9ca69SMark Johnston 
6211f9ca69SMark Johnston /*
63238510fcSJason Evans  * Common sanity checks for cv_wait* functions.
64238510fcSJason Evans  */
658f27b08eSJohn Baldwin #define	CV_ASSERT(cvp, lock, td) do {					\
660a15e5d3SAttilio Rao 	KASSERT((td) != NULL, ("%s: td NULL", __func__));		\
6771fad9fdSJulian Elischer 	KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__));	\
68a48740b6SDavid E. O'Brien 	KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__));		\
698f27b08eSJohn Baldwin 	KASSERT((lock) != NULL, ("%s: lock NULL", __func__));		\
70238510fcSJason Evans } while (0)
71238510fcSJason Evans 
72238510fcSJason Evans /*
73238510fcSJason Evans  * Initialize a condition variable.  Must be called before use.
74238510fcSJason Evans  */
75238510fcSJason Evans void
76238510fcSJason Evans cv_init(struct cv *cvp, const char *desc)
77238510fcSJason Evans {
78238510fcSJason Evans 
79238510fcSJason Evans 	cvp->cv_description = desc;
809000d57dSJohn Baldwin 	cvp->cv_waiters = 0;
81238510fcSJason Evans }
82238510fcSJason Evans 
83238510fcSJason Evans /*
84238510fcSJason Evans  * Destroy a condition variable.  The condition variable must be re-initialized
85238510fcSJason Evans  * in order to be re-used.
86238510fcSJason Evans  */
87238510fcSJason Evans void
88238510fcSJason Evans cv_destroy(struct cv *cvp)
89238510fcSJason Evans {
9044f3b092SJohn Baldwin #ifdef INVARIANTS
9144f3b092SJohn Baldwin 	struct sleepqueue *sq;
92238510fcSJason Evans 
932ff0e645SJohn Baldwin 	sleepq_lock(cvp);
9444f3b092SJohn Baldwin 	sq = sleepq_lookup(cvp);
9544f3b092SJohn Baldwin 	sleepq_release(cvp);
9644f3b092SJohn Baldwin 	KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__));
9744f3b092SJohn Baldwin #endif
98238510fcSJason Evans }
99238510fcSJason Evans 
100238510fcSJason Evans /*
101b40ce416SJulian Elischer  * Wait on a condition variable.  The current thread is placed on the condition
102238510fcSJason Evans  * variable's wait queue and suspended.  A cv_signal or cv_broadcast on the same
103b40ce416SJulian Elischer  * condition variable will resume the thread.  The mutex is released before
104238510fcSJason Evans  * sleeping and will be held on return.  It is recommended that the mutex be
105238510fcSJason Evans  * held when cv_signal or cv_broadcast are called.
106238510fcSJason Evans  */
107238510fcSJason Evans void
1088f27b08eSJohn Baldwin _cv_wait(struct cv *cvp, struct lock_object *lock)
109238510fcSJason Evans {
1108f27b08eSJohn Baldwin 	WITNESS_SAVE_DECL(lock_witness);
111a5ef95cdSMark Johnston #ifdef KTRACE
112a5ef95cdSMark Johnston 	char wmesg[WMESGLEN + 1];
113a5ef95cdSMark Johnston #endif
1148f27b08eSJohn Baldwin 	struct lock_class *class;
115a58813fdSMark Johnston 	struct thread *td __ktrace_used;
1167faf4d90SDavide Italiano 	uintptr_t lock_state;
117238510fcSJason Evans 
118503916a7SJohn Baldwin 	td = curthread;
1198f27b08eSJohn Baldwin 	CV_ASSERT(cvp, lock, td);
1208f27b08eSJohn Baldwin 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
121503916a7SJohn Baldwin 	    "Waiting on \"%s\"", cvp->cv_description);
122238510fcSJason Evans 
1236b353101SOlivier Certner 	if (SCHEDULER_STOPPED())
124238510fcSJason Evans 		return;
1254bc37205SJeffrey Hsu 
126a5ef95cdSMark Johnston #ifdef KTRACE
127a5ef95cdSMark Johnston 	if (KTRPOINT(td, KTR_CSW)) {
128a5ef95cdSMark Johnston 		strlcpy(wmesg, cv_wmesg(cvp), sizeof(wmesg));
129a5ef95cdSMark Johnston 		ktrcsw(1, 0, wmesg);
130a5ef95cdSMark Johnston 	} else {
131a5ef95cdSMark Johnston 		wmesg[0] = '\0';
132a5ef95cdSMark Johnston 	}
133a5ef95cdSMark Johnston #endif
134a5ef95cdSMark Johnston 
135a5ef95cdSMark Johnston 	class = LOCK_CLASS(lock);
136a5ef95cdSMark Johnston 	lock_state = 0;
137503916a7SJohn Baldwin 	sleepq_lock(cvp);
138503916a7SJohn Baldwin 
13911f9ca69SMark Johnston 	CV_WAITERS_INC(cvp);
1407d43ca69SJohn Baldwin 	if (lock == &Giant.lock_object)
1417d43ca69SJohn Baldwin 		mtx_assert(&Giant, MA_OWNED);
142503916a7SJohn Baldwin 	DROP_GIANT();
143503916a7SJohn Baldwin 
1448f27b08eSJohn Baldwin 	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
145414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
1469fa7ce0fSJohn Baldwin 		if (class->lc_flags & LC_SLEEPABLE)
1479fa7ce0fSJohn Baldwin 			sleepq_release(cvp);
1487d43ca69SJohn Baldwin 		WITNESS_SAVE(lock, lock_witness);
1499fa7ce0fSJohn Baldwin 		lock_state = class->lc_unlock(lock);
1509fa7ce0fSJohn Baldwin 		if (class->lc_flags & LC_SLEEPABLE)
1519fa7ce0fSJohn Baldwin 			sleepq_lock(cvp);
152414e7679SJohn Baldwin 	}
153c5aa6b58SJeff Roberson 	sleepq_wait(cvp, 0);
154503916a7SJohn Baldwin 
155503916a7SJohn Baldwin #ifdef KTRACE
156503916a7SJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
157a5ef95cdSMark Johnston 		ktrcsw(0, 0, wmesg);
158503916a7SJohn Baldwin #endif
159503916a7SJohn Baldwin 	PICKUP_GIANT();
160414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
1618f27b08eSJohn Baldwin 		class->lc_lock(lock, lock_state);
1628f27b08eSJohn Baldwin 		WITNESS_RESTORE(lock, lock_witness);
16392f44a3fSCraig Rodrigues 	}
164414e7679SJohn Baldwin }
16592f44a3fSCraig Rodrigues 
16692f44a3fSCraig Rodrigues /*
16792f44a3fSCraig Rodrigues  * Wait on a condition variable.  This function differs from cv_wait by
168e3043798SPedro F. Giffuni  * not acquiring the mutex after condition variable was signaled.
16992f44a3fSCraig Rodrigues  */
17092f44a3fSCraig Rodrigues void
1718f27b08eSJohn Baldwin _cv_wait_unlock(struct cv *cvp, struct lock_object *lock)
17292f44a3fSCraig Rodrigues {
173a5ef95cdSMark Johnston #ifdef KTRACE
174a5ef95cdSMark Johnston 	char wmesg[WMESGLEN + 1];
175a5ef95cdSMark Johnston #endif
1768f27b08eSJohn Baldwin 	struct lock_class *class;
177a58813fdSMark Johnston 	struct thread *td __ktrace_used;
17892f44a3fSCraig Rodrigues 
17992f44a3fSCraig Rodrigues 	td = curthread;
1808f27b08eSJohn Baldwin 	CV_ASSERT(cvp, lock, td);
1818f27b08eSJohn Baldwin 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
18292f44a3fSCraig Rodrigues 	    "Waiting on \"%s\"", cvp->cv_description);
183414e7679SJohn Baldwin 	KASSERT(lock != &Giant.lock_object,
184414e7679SJohn Baldwin 	    ("cv_wait_unlock cannot be used with Giant"));
1858f27b08eSJohn Baldwin 	class = LOCK_CLASS(lock);
18692f44a3fSCraig Rodrigues 
1876b353101SOlivier Certner 	if (SCHEDULER_STOPPED()) {
1888f27b08eSJohn Baldwin 		class->lc_unlock(lock);
18992f44a3fSCraig Rodrigues 		return;
19092f44a3fSCraig Rodrigues 	}
19192f44a3fSCraig Rodrigues 
192a5ef95cdSMark Johnston #ifdef KTRACE
193a5ef95cdSMark Johnston 	if (KTRPOINT(td, KTR_CSW)) {
194a5ef95cdSMark Johnston 		strlcpy(wmesg, cv_wmesg(cvp), sizeof(wmesg));
195a5ef95cdSMark Johnston 		ktrcsw(1, 0, wmesg);
196a5ef95cdSMark Johnston 	} else {
197a5ef95cdSMark Johnston 		wmesg[0] = '\0';
198a5ef95cdSMark Johnston 	}
199a5ef95cdSMark Johnston #endif
200a5ef95cdSMark Johnston 
2012ff0e645SJohn Baldwin 	sleepq_lock(cvp);
202238510fcSJason Evans 
20311f9ca69SMark Johnston 	CV_WAITERS_INC(cvp);
204c86b6ff5SJohn Baldwin 	DROP_GIANT();
205238510fcSJason Evans 
2068f27b08eSJohn Baldwin 	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
2079fa7ce0fSJohn Baldwin 	if (class->lc_flags & LC_SLEEPABLE)
2089fa7ce0fSJohn Baldwin 		sleepq_release(cvp);
2099fa7ce0fSJohn Baldwin 	class->lc_unlock(lock);
2109fa7ce0fSJohn Baldwin 	if (class->lc_flags & LC_SLEEPABLE)
2119fa7ce0fSJohn Baldwin 		sleepq_lock(cvp);
212c5aa6b58SJeff Roberson 	sleepq_wait(cvp, 0);
213238510fcSJason Evans 
214503916a7SJohn Baldwin #ifdef KTRACE
215503916a7SJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
216a5ef95cdSMark Johnston 		ktrcsw(0, 0, wmesg);
217503916a7SJohn Baldwin #endif
218238510fcSJason Evans 	PICKUP_GIANT();
219238510fcSJason Evans }
220238510fcSJason Evans 
221238510fcSJason Evans /*
222238510fcSJason Evans  * Wait on a condition variable, allowing interruption by signals.  Return 0 if
223b40ce416SJulian Elischer  * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
224238510fcSJason Evans  * a signal was caught.  If ERESTART is returned the system call should be
225238510fcSJason Evans  * restarted if possible.
226238510fcSJason Evans  */
227238510fcSJason Evans int
2288f27b08eSJohn Baldwin _cv_wait_sig(struct cv *cvp, struct lock_object *lock)
229238510fcSJason Evans {
2308f27b08eSJohn Baldwin 	WITNESS_SAVE_DECL(lock_witness);
231a5ef95cdSMark Johnston #ifdef KTRACE
232a5ef95cdSMark Johnston 	char wmesg[WMESGLEN + 1];
233a5ef95cdSMark Johnston #endif
2348f27b08eSJohn Baldwin 	struct lock_class *class;
235a58813fdSMark Johnston 	struct thread *td __ktrace_used;
2367faf4d90SDavide Italiano 	uintptr_t lock_state;
2377faf4d90SDavide Italiano 	int rval;
238238510fcSJason Evans 
239b40ce416SJulian Elischer 	td = curthread;
2408f27b08eSJohn Baldwin 	CV_ASSERT(cvp, lock, td);
2418f27b08eSJohn Baldwin 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
24226306795SJohn Baldwin 	    "Waiting on \"%s\"", cvp->cv_description);
243238510fcSJason Evans 
2446b353101SOlivier Certner 	if (SCHEDULER_STOPPED())
245274f8f48SJohn Baldwin 		return (0);
2464bc37205SJeffrey Hsu 
247a5ef95cdSMark Johnston #ifdef KTRACE
248a5ef95cdSMark Johnston 	if (KTRPOINT(td, KTR_CSW)) {
249a5ef95cdSMark Johnston 		strlcpy(wmesg, cv_wmesg(cvp), sizeof(wmesg));
250a5ef95cdSMark Johnston 		ktrcsw(1, 0, wmesg);
251a5ef95cdSMark Johnston 	} else {
252a5ef95cdSMark Johnston 		wmesg[0] = '\0';
253a5ef95cdSMark Johnston 	}
254a5ef95cdSMark Johnston #endif
255a5ef95cdSMark Johnston 
256a5ef95cdSMark Johnston 	class = LOCK_CLASS(lock);
257a5ef95cdSMark Johnston 	lock_state = 0;
2582ff0e645SJohn Baldwin 	sleepq_lock(cvp);
2594bc37205SJeffrey Hsu 
26011f9ca69SMark Johnston 	CV_WAITERS_INC(cvp);
2617d43ca69SJohn Baldwin 	if (lock == &Giant.lock_object)
2627d43ca69SJohn Baldwin 		mtx_assert(&Giant, MA_OWNED);
263c86b6ff5SJohn Baldwin 	DROP_GIANT();
264238510fcSJason Evans 
2658f27b08eSJohn Baldwin 	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
2666cbb70e2SKip Macy 	    SLEEPQ_INTERRUPTIBLE, 0);
267414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
2689fa7ce0fSJohn Baldwin 		if (class->lc_flags & LC_SLEEPABLE)
2699fa7ce0fSJohn Baldwin 			sleepq_release(cvp);
2707d43ca69SJohn Baldwin 		WITNESS_SAVE(lock, lock_witness);
2719fa7ce0fSJohn Baldwin 		lock_state = class->lc_unlock(lock);
2729fa7ce0fSJohn Baldwin 		if (class->lc_flags & LC_SLEEPABLE)
2739fa7ce0fSJohn Baldwin 			sleepq_lock(cvp);
274414e7679SJohn Baldwin 	}
275c5aa6b58SJeff Roberson 	rval = sleepq_wait_sig(cvp, 0);
276238510fcSJason Evans 
277238510fcSJason Evans #ifdef KTRACE
2789ba7fe1bSJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
279a5ef95cdSMark Johnston 		ktrcsw(0, 0, wmesg);
280238510fcSJason Evans #endif
2819ba7fe1bSJohn Baldwin 	PICKUP_GIANT();
282414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
2838f27b08eSJohn Baldwin 		class->lc_lock(lock, lock_state);
2848f27b08eSJohn Baldwin 		WITNESS_RESTORE(lock, lock_witness);
285414e7679SJohn Baldwin 	}
286238510fcSJason Evans 
287238510fcSJason Evans 	return (rval);
288238510fcSJason Evans }
289238510fcSJason Evans 
290238510fcSJason Evans /*
29146153735SDavide Italiano  * Wait on a condition variable for (at most) the value specified in sbt
29246153735SDavide Italiano  * argument. Returns 0 if the process was resumed by cv_signal or cv_broadcast,
29346153735SDavide Italiano  * EWOULDBLOCK if the timeout expires.
294238510fcSJason Evans  */
295238510fcSJason Evans int
29646153735SDavide Italiano _cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt,
29746153735SDavide Italiano     sbintime_t pr, int flags)
298238510fcSJason Evans {
2998f27b08eSJohn Baldwin 	WITNESS_SAVE_DECL(lock_witness);
300a5ef95cdSMark Johnston #ifdef KTRACE
301a5ef95cdSMark Johnston 	char wmesg[WMESGLEN + 1];
302a5ef95cdSMark Johnston #endif
3038f27b08eSJohn Baldwin 	struct lock_class *class;
304a58813fdSMark Johnston 	struct thread *td __ktrace_used;
3058f27b08eSJohn Baldwin 	int lock_state, rval;
306238510fcSJason Evans 
307b40ce416SJulian Elischer 	td = curthread;
3088f27b08eSJohn Baldwin 	CV_ASSERT(cvp, lock, td);
3098f27b08eSJohn Baldwin 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
31026306795SJohn Baldwin 	    "Waiting on \"%s\"", cvp->cv_description);
311238510fcSJason Evans 
3126b353101SOlivier Certner 	if (SCHEDULER_STOPPED())
313b4f1d267SJohn Baldwin 		return (0);
3144bc37205SJeffrey Hsu 
315a5ef95cdSMark Johnston #ifdef KTRACE
316a5ef95cdSMark Johnston 	if (KTRPOINT(td, KTR_CSW)) {
317a5ef95cdSMark Johnston 		strlcpy(wmesg, cv_wmesg(cvp), sizeof(wmesg));
318a5ef95cdSMark Johnston 		ktrcsw(1, 0, wmesg);
319a5ef95cdSMark Johnston 	} else {
320a5ef95cdSMark Johnston 		wmesg[0] = '\0';
321a5ef95cdSMark Johnston 	}
322a5ef95cdSMark Johnston #endif
323a5ef95cdSMark Johnston 
324a5ef95cdSMark Johnston 	class = LOCK_CLASS(lock);
325a5ef95cdSMark Johnston 	lock_state = 0;
3262ff0e645SJohn Baldwin 	sleepq_lock(cvp);
327238510fcSJason Evans 
32811f9ca69SMark Johnston 	CV_WAITERS_INC(cvp);
3297d43ca69SJohn Baldwin 	if (lock == &Giant.lock_object)
3307d43ca69SJohn Baldwin 		mtx_assert(&Giant, MA_OWNED);
331c86b6ff5SJohn Baldwin 	DROP_GIANT();
332238510fcSJason Evans 
3338f27b08eSJohn Baldwin 	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
33446153735SDavide Italiano 	sleepq_set_timeout_sbt(cvp, sbt, pr, flags);
335414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
336a115fb62SHans Petter Selasky 		if (class->lc_flags & LC_SLEEPABLE)
337a115fb62SHans Petter Selasky 			sleepq_release(cvp);
3387d43ca69SJohn Baldwin 		WITNESS_SAVE(lock, lock_witness);
3399fa7ce0fSJohn Baldwin 		lock_state = class->lc_unlock(lock);
340a115fb62SHans Petter Selasky 		if (class->lc_flags & LC_SLEEPABLE)
3411a26c3c0SHans Petter Selasky 			sleepq_lock(cvp);
342a115fb62SHans Petter Selasky 	}
343c5aa6b58SJeff Roberson 	rval = sleepq_timedwait(cvp, 0);
344238510fcSJason Evans 
345238510fcSJason Evans #ifdef KTRACE
3469ba7fe1bSJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
347a5ef95cdSMark Johnston 		ktrcsw(0, 0, wmesg);
348238510fcSJason Evans #endif
349238510fcSJason Evans 	PICKUP_GIANT();
350414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
3518f27b08eSJohn Baldwin 		class->lc_lock(lock, lock_state);
3528f27b08eSJohn Baldwin 		WITNESS_RESTORE(lock, lock_witness);
353414e7679SJohn Baldwin 	}
354238510fcSJason Evans 
355238510fcSJason Evans 	return (rval);
356238510fcSJason Evans }
357238510fcSJason Evans 
358238510fcSJason Evans /*
35946153735SDavide Italiano  * Wait on a condition variable for (at most) the value specified in sbt
36046153735SDavide Italiano  * argument, allowing interruption by signals.
36146153735SDavide Italiano  * Returns 0 if the thread was resumed by cv_signal or cv_broadcast,
36246153735SDavide Italiano  * EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if a signal
36346153735SDavide Italiano  * was caught.
364238510fcSJason Evans  */
365238510fcSJason Evans int
36646153735SDavide Italiano _cv_timedwait_sig_sbt(struct cv *cvp, struct lock_object *lock,
36746153735SDavide Italiano     sbintime_t sbt, sbintime_t pr, int flags)
368238510fcSJason Evans {
3698f27b08eSJohn Baldwin 	WITNESS_SAVE_DECL(lock_witness);
370a5ef95cdSMark Johnston #ifdef KTRACE
371a5ef95cdSMark Johnston 	char wmesg[WMESGLEN + 1];
372a5ef95cdSMark Johnston #endif
3738f27b08eSJohn Baldwin 	struct lock_class *class;
374a58813fdSMark Johnston 	struct thread *td __ktrace_used;
3758f27b08eSJohn Baldwin 	int lock_state, rval;
376238510fcSJason Evans 
377b40ce416SJulian Elischer 	td = curthread;
3788f27b08eSJohn Baldwin 	CV_ASSERT(cvp, lock, td);
3798f27b08eSJohn Baldwin 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
38026306795SJohn Baldwin 	    "Waiting on \"%s\"", cvp->cv_description);
381238510fcSJason Evans 
3826b353101SOlivier Certner 	if (SCHEDULER_STOPPED())
383b4f1d267SJohn Baldwin 		return (0);
3844bc37205SJeffrey Hsu 
385a5ef95cdSMark Johnston #ifdef KTRACE
386a5ef95cdSMark Johnston 	if (KTRPOINT(td, KTR_CSW)) {
387a5ef95cdSMark Johnston 		strlcpy(wmesg, cv_wmesg(cvp), sizeof(wmesg));
388a5ef95cdSMark Johnston 		ktrcsw(1, 0, wmesg);
389a5ef95cdSMark Johnston 	} else {
390a5ef95cdSMark Johnston 		wmesg[0] = '\0';
391a5ef95cdSMark Johnston 	}
392a5ef95cdSMark Johnston #endif
393a5ef95cdSMark Johnston 
394a5ef95cdSMark Johnston 	class = LOCK_CLASS(lock);
395a5ef95cdSMark Johnston 	lock_state = 0;
3962ff0e645SJohn Baldwin 	sleepq_lock(cvp);
397238510fcSJason Evans 
39811f9ca69SMark Johnston 	CV_WAITERS_INC(cvp);
3997d43ca69SJohn Baldwin 	if (lock == &Giant.lock_object)
4007d43ca69SJohn Baldwin 		mtx_assert(&Giant, MA_OWNED);
401c86b6ff5SJohn Baldwin 	DROP_GIANT();
402238510fcSJason Evans 
4038f27b08eSJohn Baldwin 	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
4046cbb70e2SKip Macy 	    SLEEPQ_INTERRUPTIBLE, 0);
40546153735SDavide Italiano 	sleepq_set_timeout_sbt(cvp, sbt, pr, flags);
406414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
407a115fb62SHans Petter Selasky 		if (class->lc_flags & LC_SLEEPABLE)
408a115fb62SHans Petter Selasky 			sleepq_release(cvp);
4097d43ca69SJohn Baldwin 		WITNESS_SAVE(lock, lock_witness);
4109fa7ce0fSJohn Baldwin 		lock_state = class->lc_unlock(lock);
411a115fb62SHans Petter Selasky 		if (class->lc_flags & LC_SLEEPABLE)
4121a26c3c0SHans Petter Selasky 			sleepq_lock(cvp);
413a115fb62SHans Petter Selasky 	}
414c5aa6b58SJeff Roberson 	rval = sleepq_timedwait_sig(cvp, 0);
415238510fcSJason Evans 
416238510fcSJason Evans #ifdef KTRACE
4179ba7fe1bSJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
418a5ef95cdSMark Johnston 		ktrcsw(0, 0, wmesg);
419238510fcSJason Evans #endif
4209ba7fe1bSJohn Baldwin 	PICKUP_GIANT();
421414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
4228f27b08eSJohn Baldwin 		class->lc_lock(lock, lock_state);
4238f27b08eSJohn Baldwin 		WITNESS_RESTORE(lock, lock_witness);
424414e7679SJohn Baldwin 	}
425238510fcSJason Evans 
426238510fcSJason Evans 	return (rval);
427238510fcSJason Evans }
428238510fcSJason Evans 
429238510fcSJason Evans /*
430*01518f5eSMark Johnston  * Signal a condition variable, wakes up one waiting thread.  Note that this may
431*01518f5eSMark Johnston  * also result in additional threads being made runnable.  Should be called with
432*01518f5eSMark Johnston  * the same mutex as was passed to cv_wait held.
433238510fcSJason Evans  */
434238510fcSJason Evans void
435238510fcSJason Evans cv_signal(struct cv *cvp)
436238510fcSJason Evans {
4375b7d9ae2SMateusz Guzik 	if (cvp->cv_waiters == 0)
4385b7d9ae2SMateusz Guzik 		return;
4392ff0e645SJohn Baldwin 	sleepq_lock(cvp);
44063ca9ea4SAlexander Motin 	if (cvp->cv_waiters == 0) {
44163ca9ea4SAlexander Motin 		sleepq_release(cvp);
44263ca9ea4SAlexander Motin 		return;
44363ca9ea4SAlexander Motin 	}
44463ca9ea4SAlexander Motin 	if (cvp->cv_waiters == CV_WAITERS_BOUND && sleepq_lookup(cvp) == NULL) {
44511f9ca69SMark Johnston 		cvp->cv_waiters = 0;
44663ca9ea4SAlexander Motin 		sleepq_release(cvp);
44711f9ca69SMark Johnston 	} else {
44811f9ca69SMark Johnston 		if (cvp->cv_waiters < CV_WAITERS_BOUND)
449c636f94bSJohn Baldwin 			cvp->cv_waiters--;
450*01518f5eSMark Johnston 		sleepq_signal(cvp, SLEEPQ_CONDVAR | SLEEPQ_DROP, 0, 0);
4519000d57dSJohn Baldwin 	}
45263ca9ea4SAlexander Motin }
453238510fcSJason Evans 
454238510fcSJason Evans /*
455b40ce416SJulian Elischer  * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
456238510fcSJason Evans  * Should be called with the same mutex as was passed to cv_wait held.
457238510fcSJason Evans  */
458238510fcSJason Evans void
459512824f8SSeigo Tanimura cv_broadcastpri(struct cv *cvp, int pri)
460238510fcSJason Evans {
4615b7d9ae2SMateusz Guzik 	if (cvp->cv_waiters == 0)
4625b7d9ae2SMateusz Guzik 		return;
463c5aa6b58SJeff Roberson 	/*
464c5aa6b58SJeff Roberson 	 * XXX sleepq_broadcast pri argument changed from -1 meaning
465c5aa6b58SJeff Roberson 	 * no pri to 0 meaning no pri.
466c5aa6b58SJeff Roberson 	 */
467c5aa6b58SJeff Roberson 	if (pri == -1)
468c5aa6b58SJeff Roberson 		pri = 0;
4692ff0e645SJohn Baldwin 	sleepq_lock(cvp);
470c636f94bSJohn Baldwin 	if (cvp->cv_waiters > 0) {
471c636f94bSJohn Baldwin 		cvp->cv_waiters = 0;
472*01518f5eSMark Johnston 		sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0);
473c636f94bSJohn Baldwin 	}
4742ff0e645SJohn Baldwin 	sleepq_release(cvp);
4759000d57dSJohn Baldwin }
476