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