xref: /freebsd/sys/kern/kern_condvar.c (revision 8a36da99deb0e19363ec04e4d3facd869c1028f5)
1238510fcSJason Evans /*-
2*8a36da99SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*8a36da99SPedro 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>
30677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
31677b542eSDavid E. O'Brien 
32238510fcSJason Evans #include "opt_ktrace.h"
33238510fcSJason Evans 
34238510fcSJason Evans #include <sys/param.h>
35238510fcSJason Evans #include <sys/systm.h>
3611f9ca69SMark Johnston #include <sys/limits.h>
37fb919e4dSMark Murray #include <sys/lock.h>
38fb919e4dSMark Murray #include <sys/mutex.h>
39238510fcSJason Evans #include <sys/proc.h>
40238510fcSJason Evans #include <sys/kernel.h>
41238510fcSJason Evans #include <sys/ktr.h>
42238510fcSJason Evans #include <sys/condvar.h>
434e997f4bSJeff Roberson #include <sys/sched.h>
44238510fcSJason Evans #include <sys/signalvar.h>
4544f3b092SJohn Baldwin #include <sys/sleepqueue.h>
46238510fcSJason Evans #include <sys/resourcevar.h>
47238510fcSJason Evans #ifdef KTRACE
48238510fcSJason Evans #include <sys/uio.h>
49238510fcSJason Evans #include <sys/ktrace.h>
50238510fcSJason Evans #endif
51238510fcSJason Evans 
52238510fcSJason Evans /*
5311f9ca69SMark Johnston  * A bound below which cv_waiters is valid.  Once cv_waiters reaches this bound,
5411f9ca69SMark Johnston  * cv_signal must manually check the wait queue for threads.
5511f9ca69SMark Johnston  */
5611f9ca69SMark Johnston #define	CV_WAITERS_BOUND	INT_MAX
5711f9ca69SMark Johnston 
5811f9ca69SMark Johnston #define	CV_WAITERS_INC(cvp) do {					\
5911f9ca69SMark Johnston 	if ((cvp)->cv_waiters < CV_WAITERS_BOUND)			\
6011f9ca69SMark Johnston 		(cvp)->cv_waiters++;					\
6111f9ca69SMark Johnston } while (0)
6211f9ca69SMark Johnston 
6311f9ca69SMark Johnston /*
64238510fcSJason Evans  * Common sanity checks for cv_wait* functions.
65238510fcSJason Evans  */
668f27b08eSJohn Baldwin #define	CV_ASSERT(cvp, lock, td) do {					\
670a15e5d3SAttilio Rao 	KASSERT((td) != NULL, ("%s: td NULL", __func__));		\
6871fad9fdSJulian Elischer 	KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__));	\
69a48740b6SDavid E. O'Brien 	KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__));		\
708f27b08eSJohn Baldwin 	KASSERT((lock) != NULL, ("%s: lock NULL", __func__));		\
71238510fcSJason Evans } while (0)
72238510fcSJason Evans 
73238510fcSJason Evans /*
74238510fcSJason Evans  * Initialize a condition variable.  Must be called before use.
75238510fcSJason Evans  */
76238510fcSJason Evans void
77238510fcSJason Evans cv_init(struct cv *cvp, const char *desc)
78238510fcSJason Evans {
79238510fcSJason Evans 
80238510fcSJason Evans 	cvp->cv_description = desc;
819000d57dSJohn Baldwin 	cvp->cv_waiters = 0;
82238510fcSJason Evans }
83238510fcSJason Evans 
84238510fcSJason Evans /*
85238510fcSJason Evans  * Destroy a condition variable.  The condition variable must be re-initialized
86238510fcSJason Evans  * in order to be re-used.
87238510fcSJason Evans  */
88238510fcSJason Evans void
89238510fcSJason Evans cv_destroy(struct cv *cvp)
90238510fcSJason Evans {
9144f3b092SJohn Baldwin #ifdef INVARIANTS
9244f3b092SJohn Baldwin 	struct sleepqueue *sq;
93238510fcSJason Evans 
942ff0e645SJohn Baldwin 	sleepq_lock(cvp);
9544f3b092SJohn Baldwin 	sq = sleepq_lookup(cvp);
9644f3b092SJohn Baldwin 	sleepq_release(cvp);
9744f3b092SJohn Baldwin 	KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__));
9844f3b092SJohn Baldwin #endif
99238510fcSJason Evans }
100238510fcSJason Evans 
101238510fcSJason Evans /*
102b40ce416SJulian Elischer  * Wait on a condition variable.  The current thread is placed on the condition
103238510fcSJason Evans  * variable's wait queue and suspended.  A cv_signal or cv_broadcast on the same
104b40ce416SJulian Elischer  * condition variable will resume the thread.  The mutex is released before
105238510fcSJason Evans  * sleeping and will be held on return.  It is recommended that the mutex be
106238510fcSJason Evans  * held when cv_signal or cv_broadcast are called.
107238510fcSJason Evans  */
108238510fcSJason Evans void
1098f27b08eSJohn Baldwin _cv_wait(struct cv *cvp, struct lock_object *lock)
110238510fcSJason Evans {
1118f27b08eSJohn Baldwin 	WITNESS_SAVE_DECL(lock_witness);
1128f27b08eSJohn Baldwin 	struct lock_class *class;
113503916a7SJohn Baldwin 	struct thread *td;
1147faf4d90SDavide Italiano 	uintptr_t lock_state;
115238510fcSJason Evans 
116503916a7SJohn Baldwin 	td = curthread;
117414e7679SJohn Baldwin 	lock_state = 0;
118503916a7SJohn Baldwin #ifdef KTRACE
119503916a7SJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
12088bf5036SJohn Baldwin 		ktrcsw(1, 0, cv_wmesg(cvp));
121503916a7SJohn Baldwin #endif
1228f27b08eSJohn Baldwin 	CV_ASSERT(cvp, lock, td);
1238f27b08eSJohn Baldwin 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
124503916a7SJohn Baldwin 	    "Waiting on \"%s\"", cvp->cv_description);
1258f27b08eSJohn Baldwin 	class = LOCK_CLASS(lock);
126238510fcSJason Evans 
12791fa4707SMateusz Guzik 	if (SCHEDULER_STOPPED_TD(td))
128238510fcSJason Evans 		return;
1294bc37205SJeffrey Hsu 
130503916a7SJohn Baldwin 	sleepq_lock(cvp);
131503916a7SJohn Baldwin 
13211f9ca69SMark Johnston 	CV_WAITERS_INC(cvp);
1337d43ca69SJohn Baldwin 	if (lock == &Giant.lock_object)
1347d43ca69SJohn Baldwin 		mtx_assert(&Giant, MA_OWNED);
135503916a7SJohn Baldwin 	DROP_GIANT();
136503916a7SJohn Baldwin 
1378f27b08eSJohn Baldwin 	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
138414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
1399fa7ce0fSJohn Baldwin 		if (class->lc_flags & LC_SLEEPABLE)
1409fa7ce0fSJohn Baldwin 			sleepq_release(cvp);
1417d43ca69SJohn Baldwin 		WITNESS_SAVE(lock, lock_witness);
1429fa7ce0fSJohn Baldwin 		lock_state = class->lc_unlock(lock);
1439fa7ce0fSJohn Baldwin 		if (class->lc_flags & LC_SLEEPABLE)
1449fa7ce0fSJohn Baldwin 			sleepq_lock(cvp);
145414e7679SJohn Baldwin 	}
146c5aa6b58SJeff Roberson 	sleepq_wait(cvp, 0);
147503916a7SJohn Baldwin 
148503916a7SJohn Baldwin #ifdef KTRACE
149503916a7SJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
15088bf5036SJohn Baldwin 		ktrcsw(0, 0, cv_wmesg(cvp));
151503916a7SJohn Baldwin #endif
152503916a7SJohn Baldwin 	PICKUP_GIANT();
153414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
1548f27b08eSJohn Baldwin 		class->lc_lock(lock, lock_state);
1558f27b08eSJohn Baldwin 		WITNESS_RESTORE(lock, lock_witness);
15692f44a3fSCraig Rodrigues 	}
157414e7679SJohn Baldwin }
15892f44a3fSCraig Rodrigues 
15992f44a3fSCraig Rodrigues /*
16092f44a3fSCraig Rodrigues  * Wait on a condition variable.  This function differs from cv_wait by
161e3043798SPedro F. Giffuni  * not acquiring the mutex after condition variable was signaled.
16292f44a3fSCraig Rodrigues  */
16392f44a3fSCraig Rodrigues void
1648f27b08eSJohn Baldwin _cv_wait_unlock(struct cv *cvp, struct lock_object *lock)
16592f44a3fSCraig Rodrigues {
1668f27b08eSJohn Baldwin 	struct lock_class *class;
16792f44a3fSCraig Rodrigues 	struct thread *td;
16892f44a3fSCraig Rodrigues 
16992f44a3fSCraig Rodrigues 	td = curthread;
17092f44a3fSCraig Rodrigues #ifdef KTRACE
17192f44a3fSCraig Rodrigues 	if (KTRPOINT(td, KTR_CSW))
17288bf5036SJohn Baldwin 		ktrcsw(1, 0, cv_wmesg(cvp));
17392f44a3fSCraig Rodrigues #endif
1748f27b08eSJohn Baldwin 	CV_ASSERT(cvp, lock, td);
1758f27b08eSJohn Baldwin 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
17692f44a3fSCraig Rodrigues 	    "Waiting on \"%s\"", cvp->cv_description);
177414e7679SJohn Baldwin 	KASSERT(lock != &Giant.lock_object,
178414e7679SJohn Baldwin 	    ("cv_wait_unlock cannot be used with Giant"));
1798f27b08eSJohn Baldwin 	class = LOCK_CLASS(lock);
18092f44a3fSCraig Rodrigues 
18191fa4707SMateusz Guzik 	if (SCHEDULER_STOPPED_TD(td)) {
1828f27b08eSJohn Baldwin 		class->lc_unlock(lock);
18392f44a3fSCraig Rodrigues 		return;
18492f44a3fSCraig Rodrigues 	}
18592f44a3fSCraig Rodrigues 
1862ff0e645SJohn Baldwin 	sleepq_lock(cvp);
187238510fcSJason Evans 
18811f9ca69SMark Johnston 	CV_WAITERS_INC(cvp);
189c86b6ff5SJohn Baldwin 	DROP_GIANT();
190238510fcSJason Evans 
1918f27b08eSJohn Baldwin 	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
1929fa7ce0fSJohn Baldwin 	if (class->lc_flags & LC_SLEEPABLE)
1939fa7ce0fSJohn Baldwin 		sleepq_release(cvp);
1949fa7ce0fSJohn Baldwin 	class->lc_unlock(lock);
1959fa7ce0fSJohn Baldwin 	if (class->lc_flags & LC_SLEEPABLE)
1969fa7ce0fSJohn Baldwin 		sleepq_lock(cvp);
197c5aa6b58SJeff Roberson 	sleepq_wait(cvp, 0);
198238510fcSJason Evans 
199503916a7SJohn Baldwin #ifdef KTRACE
200503916a7SJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
20188bf5036SJohn Baldwin 		ktrcsw(0, 0, cv_wmesg(cvp));
202503916a7SJohn Baldwin #endif
203238510fcSJason Evans 	PICKUP_GIANT();
204238510fcSJason Evans }
205238510fcSJason Evans 
206238510fcSJason Evans /*
207238510fcSJason Evans  * Wait on a condition variable, allowing interruption by signals.  Return 0 if
208b40ce416SJulian Elischer  * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
209238510fcSJason Evans  * a signal was caught.  If ERESTART is returned the system call should be
210238510fcSJason Evans  * restarted if possible.
211238510fcSJason Evans  */
212238510fcSJason Evans int
2138f27b08eSJohn Baldwin _cv_wait_sig(struct cv *cvp, struct lock_object *lock)
214238510fcSJason Evans {
2158f27b08eSJohn Baldwin 	WITNESS_SAVE_DECL(lock_witness);
2168f27b08eSJohn Baldwin 	struct lock_class *class;
217b40ce416SJulian Elischer 	struct thread *td;
2187faf4d90SDavide Italiano 	uintptr_t lock_state;
2197faf4d90SDavide Italiano 	int rval;
220238510fcSJason Evans 
221b40ce416SJulian Elischer 	td = curthread;
222414e7679SJohn Baldwin 	lock_state = 0;
223238510fcSJason Evans #ifdef KTRACE
2249ba7fe1bSJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
22588bf5036SJohn Baldwin 		ktrcsw(1, 0, cv_wmesg(cvp));
226238510fcSJason Evans #endif
2278f27b08eSJohn Baldwin 	CV_ASSERT(cvp, lock, td);
2288f27b08eSJohn Baldwin 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
22926306795SJohn Baldwin 	    "Waiting on \"%s\"", cvp->cv_description);
2308f27b08eSJohn Baldwin 	class = LOCK_CLASS(lock);
231238510fcSJason Evans 
23291fa4707SMateusz Guzik 	if (SCHEDULER_STOPPED_TD(td))
233274f8f48SJohn Baldwin 		return (0);
2344bc37205SJeffrey Hsu 
2352ff0e645SJohn Baldwin 	sleepq_lock(cvp);
2364bc37205SJeffrey Hsu 
23711f9ca69SMark Johnston 	CV_WAITERS_INC(cvp);
2387d43ca69SJohn Baldwin 	if (lock == &Giant.lock_object)
2397d43ca69SJohn Baldwin 		mtx_assert(&Giant, MA_OWNED);
240c86b6ff5SJohn Baldwin 	DROP_GIANT();
241238510fcSJason Evans 
2428f27b08eSJohn Baldwin 	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
2436cbb70e2SKip Macy 	    SLEEPQ_INTERRUPTIBLE, 0);
244414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
2459fa7ce0fSJohn Baldwin 		if (class->lc_flags & LC_SLEEPABLE)
2469fa7ce0fSJohn Baldwin 			sleepq_release(cvp);
2477d43ca69SJohn Baldwin 		WITNESS_SAVE(lock, lock_witness);
2489fa7ce0fSJohn Baldwin 		lock_state = class->lc_unlock(lock);
2499fa7ce0fSJohn Baldwin 		if (class->lc_flags & LC_SLEEPABLE)
2509fa7ce0fSJohn Baldwin 			sleepq_lock(cvp);
251414e7679SJohn Baldwin 	}
252c5aa6b58SJeff Roberson 	rval = sleepq_wait_sig(cvp, 0);
253238510fcSJason Evans 
254238510fcSJason Evans #ifdef KTRACE
2559ba7fe1bSJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
25688bf5036SJohn Baldwin 		ktrcsw(0, 0, cv_wmesg(cvp));
257238510fcSJason Evans #endif
2589ba7fe1bSJohn Baldwin 	PICKUP_GIANT();
259414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
2608f27b08eSJohn Baldwin 		class->lc_lock(lock, lock_state);
2618f27b08eSJohn Baldwin 		WITNESS_RESTORE(lock, lock_witness);
262414e7679SJohn Baldwin 	}
263238510fcSJason Evans 
264238510fcSJason Evans 	return (rval);
265238510fcSJason Evans }
266238510fcSJason Evans 
267238510fcSJason Evans /*
26846153735SDavide Italiano  * Wait on a condition variable for (at most) the value specified in sbt
26946153735SDavide Italiano  * argument. Returns 0 if the process was resumed by cv_signal or cv_broadcast,
27046153735SDavide Italiano  * EWOULDBLOCK if the timeout expires.
271238510fcSJason Evans  */
272238510fcSJason Evans int
27346153735SDavide Italiano _cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt,
27446153735SDavide Italiano     sbintime_t pr, int flags)
275238510fcSJason Evans {
2768f27b08eSJohn Baldwin 	WITNESS_SAVE_DECL(lock_witness);
2778f27b08eSJohn Baldwin 	struct lock_class *class;
278b40ce416SJulian Elischer 	struct thread *td;
2798f27b08eSJohn Baldwin 	int lock_state, rval;
280238510fcSJason Evans 
281b40ce416SJulian Elischer 	td = curthread;
282414e7679SJohn Baldwin 	lock_state = 0;
283238510fcSJason Evans #ifdef KTRACE
2849ba7fe1bSJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
28588bf5036SJohn Baldwin 		ktrcsw(1, 0, cv_wmesg(cvp));
286238510fcSJason Evans #endif
2878f27b08eSJohn Baldwin 	CV_ASSERT(cvp, lock, td);
2888f27b08eSJohn Baldwin 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
28926306795SJohn Baldwin 	    "Waiting on \"%s\"", cvp->cv_description);
2908f27b08eSJohn Baldwin 	class = LOCK_CLASS(lock);
291238510fcSJason Evans 
29291fa4707SMateusz Guzik 	if (SCHEDULER_STOPPED_TD(td))
293b4f1d267SJohn Baldwin 		return (0);
2944bc37205SJeffrey Hsu 
2952ff0e645SJohn Baldwin 	sleepq_lock(cvp);
296238510fcSJason Evans 
29711f9ca69SMark Johnston 	CV_WAITERS_INC(cvp);
2987d43ca69SJohn Baldwin 	if (lock == &Giant.lock_object)
2997d43ca69SJohn Baldwin 		mtx_assert(&Giant, MA_OWNED);
300c86b6ff5SJohn Baldwin 	DROP_GIANT();
301238510fcSJason Evans 
3028f27b08eSJohn Baldwin 	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
30346153735SDavide Italiano 	sleepq_set_timeout_sbt(cvp, sbt, pr, flags);
304414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
305a115fb62SHans Petter Selasky 		if (class->lc_flags & LC_SLEEPABLE)
306a115fb62SHans Petter Selasky 			sleepq_release(cvp);
3077d43ca69SJohn Baldwin 		WITNESS_SAVE(lock, lock_witness);
3089fa7ce0fSJohn Baldwin 		lock_state = class->lc_unlock(lock);
309a115fb62SHans Petter Selasky 		if (class->lc_flags & LC_SLEEPABLE)
3101a26c3c0SHans Petter Selasky 			sleepq_lock(cvp);
311a115fb62SHans Petter Selasky 	}
312c5aa6b58SJeff Roberson 	rval = sleepq_timedwait(cvp, 0);
313238510fcSJason Evans 
314238510fcSJason Evans #ifdef KTRACE
3159ba7fe1bSJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
31688bf5036SJohn Baldwin 		ktrcsw(0, 0, cv_wmesg(cvp));
317238510fcSJason Evans #endif
318238510fcSJason Evans 	PICKUP_GIANT();
319414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
3208f27b08eSJohn Baldwin 		class->lc_lock(lock, lock_state);
3218f27b08eSJohn Baldwin 		WITNESS_RESTORE(lock, lock_witness);
322414e7679SJohn Baldwin 	}
323238510fcSJason Evans 
324238510fcSJason Evans 	return (rval);
325238510fcSJason Evans }
326238510fcSJason Evans 
327238510fcSJason Evans /*
32846153735SDavide Italiano  * Wait on a condition variable for (at most) the value specified in sbt
32946153735SDavide Italiano  * argument, allowing interruption by signals.
33046153735SDavide Italiano  * Returns 0 if the thread was resumed by cv_signal or cv_broadcast,
33146153735SDavide Italiano  * EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if a signal
33246153735SDavide Italiano  * was caught.
333238510fcSJason Evans  */
334238510fcSJason Evans int
33546153735SDavide Italiano _cv_timedwait_sig_sbt(struct cv *cvp, struct lock_object *lock,
33646153735SDavide Italiano     sbintime_t sbt, sbintime_t pr, int flags)
337238510fcSJason Evans {
3388f27b08eSJohn Baldwin 	WITNESS_SAVE_DECL(lock_witness);
3398f27b08eSJohn Baldwin 	struct lock_class *class;
340b40ce416SJulian Elischer 	struct thread *td;
3418f27b08eSJohn Baldwin 	int lock_state, rval;
342238510fcSJason Evans 
343b40ce416SJulian Elischer 	td = curthread;
344414e7679SJohn Baldwin 	lock_state = 0;
345238510fcSJason Evans #ifdef KTRACE
3469ba7fe1bSJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
34788bf5036SJohn Baldwin 		ktrcsw(1, 0, cv_wmesg(cvp));
348238510fcSJason Evans #endif
3498f27b08eSJohn Baldwin 	CV_ASSERT(cvp, lock, td);
3508f27b08eSJohn Baldwin 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
35126306795SJohn Baldwin 	    "Waiting on \"%s\"", cvp->cv_description);
3528f27b08eSJohn Baldwin 	class = LOCK_CLASS(lock);
353238510fcSJason Evans 
35491fa4707SMateusz Guzik 	if (SCHEDULER_STOPPED_TD(td))
355b4f1d267SJohn Baldwin 		return (0);
3564bc37205SJeffrey Hsu 
3572ff0e645SJohn Baldwin 	sleepq_lock(cvp);
358238510fcSJason Evans 
35911f9ca69SMark Johnston 	CV_WAITERS_INC(cvp);
3607d43ca69SJohn Baldwin 	if (lock == &Giant.lock_object)
3617d43ca69SJohn Baldwin 		mtx_assert(&Giant, MA_OWNED);
362c86b6ff5SJohn Baldwin 	DROP_GIANT();
363238510fcSJason Evans 
3648f27b08eSJohn Baldwin 	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
3656cbb70e2SKip Macy 	    SLEEPQ_INTERRUPTIBLE, 0);
36646153735SDavide Italiano 	sleepq_set_timeout_sbt(cvp, sbt, pr, flags);
367414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
368a115fb62SHans Petter Selasky 		if (class->lc_flags & LC_SLEEPABLE)
369a115fb62SHans Petter Selasky 			sleepq_release(cvp);
3707d43ca69SJohn Baldwin 		WITNESS_SAVE(lock, lock_witness);
3719fa7ce0fSJohn Baldwin 		lock_state = class->lc_unlock(lock);
372a115fb62SHans Petter Selasky 		if (class->lc_flags & LC_SLEEPABLE)
3731a26c3c0SHans Petter Selasky 			sleepq_lock(cvp);
374a115fb62SHans Petter Selasky 	}
375c5aa6b58SJeff Roberson 	rval = sleepq_timedwait_sig(cvp, 0);
376238510fcSJason Evans 
377238510fcSJason Evans #ifdef KTRACE
3789ba7fe1bSJohn Baldwin 	if (KTRPOINT(td, KTR_CSW))
37988bf5036SJohn Baldwin 		ktrcsw(0, 0, cv_wmesg(cvp));
380238510fcSJason Evans #endif
3819ba7fe1bSJohn Baldwin 	PICKUP_GIANT();
382414e7679SJohn Baldwin 	if (lock != &Giant.lock_object) {
3838f27b08eSJohn Baldwin 		class->lc_lock(lock, lock_state);
3848f27b08eSJohn Baldwin 		WITNESS_RESTORE(lock, lock_witness);
385414e7679SJohn Baldwin 	}
386238510fcSJason Evans 
387238510fcSJason Evans 	return (rval);
388238510fcSJason Evans }
389238510fcSJason Evans 
390238510fcSJason Evans /*
391b40ce416SJulian Elischer  * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
392238510fcSJason Evans  * the swapper if the process is not in memory, so that it can bring the
393b40ce416SJulian Elischer  * sleeping process in.  Note that this may also result in additional threads
394238510fcSJason Evans  * being made runnable.  Should be called with the same mutex as was passed to
395238510fcSJason Evans  * cv_wait held.
396238510fcSJason Evans  */
397238510fcSJason Evans void
398238510fcSJason Evans cv_signal(struct cv *cvp)
399238510fcSJason Evans {
400da7bbd2cSJohn Baldwin 	int wakeup_swapper;
401238510fcSJason Evans 
4025b7d9ae2SMateusz Guzik 	if (cvp->cv_waiters == 0)
4035b7d9ae2SMateusz Guzik 		return;
404da7bbd2cSJohn Baldwin 	wakeup_swapper = 0;
4052ff0e645SJohn Baldwin 	sleepq_lock(cvp);
406c636f94bSJohn Baldwin 	if (cvp->cv_waiters > 0) {
40711f9ca69SMark Johnston 		if (cvp->cv_waiters == CV_WAITERS_BOUND &&
40811f9ca69SMark Johnston 		    sleepq_lookup(cvp) == NULL) {
40911f9ca69SMark Johnston 			cvp->cv_waiters = 0;
41011f9ca69SMark Johnston 		} else {
41111f9ca69SMark Johnston 			if (cvp->cv_waiters < CV_WAITERS_BOUND)
412c636f94bSJohn Baldwin 				cvp->cv_waiters--;
41311f9ca69SMark Johnston 			wakeup_swapper = sleepq_signal(cvp, SLEEPQ_CONDVAR, 0,
41411f9ca69SMark Johnston 			    0);
41511f9ca69SMark Johnston 		}
416c636f94bSJohn Baldwin 	}
4172ff0e645SJohn Baldwin 	sleepq_release(cvp);
418da7bbd2cSJohn Baldwin 	if (wakeup_swapper)
419da7bbd2cSJohn Baldwin 		kick_proc0();
4209000d57dSJohn Baldwin }
421238510fcSJason Evans 
422238510fcSJason Evans /*
423b40ce416SJulian Elischer  * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
424238510fcSJason Evans  * Should be called with the same mutex as was passed to cv_wait held.
425238510fcSJason Evans  */
426238510fcSJason Evans void
427512824f8SSeigo Tanimura cv_broadcastpri(struct cv *cvp, int pri)
428238510fcSJason Evans {
429da7bbd2cSJohn Baldwin 	int wakeup_swapper;
430da7bbd2cSJohn Baldwin 
4315b7d9ae2SMateusz Guzik 	if (cvp->cv_waiters == 0)
4325b7d9ae2SMateusz Guzik 		return;
433c5aa6b58SJeff Roberson 	/*
434c5aa6b58SJeff Roberson 	 * XXX sleepq_broadcast pri argument changed from -1 meaning
435c5aa6b58SJeff Roberson 	 * no pri to 0 meaning no pri.
436c5aa6b58SJeff Roberson 	 */
437da7bbd2cSJohn Baldwin 	wakeup_swapper = 0;
438c5aa6b58SJeff Roberson 	if (pri == -1)
439c5aa6b58SJeff Roberson 		pri = 0;
4402ff0e645SJohn Baldwin 	sleepq_lock(cvp);
441c636f94bSJohn Baldwin 	if (cvp->cv_waiters > 0) {
442c636f94bSJohn Baldwin 		cvp->cv_waiters = 0;
443da7bbd2cSJohn Baldwin 		wakeup_swapper = sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0);
444c636f94bSJohn Baldwin 	}
4452ff0e645SJohn Baldwin 	sleepq_release(cvp);
446da7bbd2cSJohn Baldwin 	if (wakeup_swapper)
447da7bbd2cSJohn Baldwin 		kick_proc0();
4489000d57dSJohn Baldwin }
449