1238510fcSJason Evans /*- 2238510fcSJason Evans * Copyright (c) 2000 Jake Burkholder <jake@freebsd.org>. 3238510fcSJason Evans * All rights reserved. 4238510fcSJason Evans * 5238510fcSJason Evans * Redistribution and use in source and binary forms, with or without 6238510fcSJason Evans * modification, are permitted provided that the following conditions 7238510fcSJason Evans * are met: 8238510fcSJason Evans * 1. Redistributions of source code must retain the above copyright 9238510fcSJason Evans * notice, this list of conditions and the following disclaimer. 10238510fcSJason Evans * 2. Redistributions in binary form must reproduce the above copyright 11238510fcSJason Evans * notice, this list of conditions and the following disclaimer in the 12238510fcSJason Evans * documentation and/or other materials provided with the distribution. 13238510fcSJason Evans * 14238510fcSJason Evans * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15238510fcSJason Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16238510fcSJason Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17238510fcSJason Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18238510fcSJason Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19238510fcSJason Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20238510fcSJason Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21238510fcSJason Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22238510fcSJason Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23238510fcSJason Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24238510fcSJason Evans * SUCH DAMAGE. 25238510fcSJason Evans */ 26238510fcSJason Evans 27677b542eSDavid E. O'Brien #include <sys/cdefs.h> 28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 29677b542eSDavid E. O'Brien 30238510fcSJason Evans #include "opt_ktrace.h" 31238510fcSJason Evans 32238510fcSJason Evans #include <sys/param.h> 33238510fcSJason Evans #include <sys/systm.h> 34*11f9ca69SMark 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> 40238510fcSJason Evans #include <sys/condvar.h> 414e997f4bSJeff Roberson #include <sys/sched.h> 42238510fcSJason Evans #include <sys/signalvar.h> 4344f3b092SJohn Baldwin #include <sys/sleepqueue.h> 44238510fcSJason Evans #include <sys/resourcevar.h> 45238510fcSJason Evans #ifdef KTRACE 46238510fcSJason Evans #include <sys/uio.h> 47238510fcSJason Evans #include <sys/ktrace.h> 48238510fcSJason Evans #endif 49238510fcSJason Evans 50238510fcSJason Evans /* 51*11f9ca69SMark Johnston * A bound below which cv_waiters is valid. Once cv_waiters reaches this bound, 52*11f9ca69SMark Johnston * cv_signal must manually check the wait queue for threads. 53*11f9ca69SMark Johnston */ 54*11f9ca69SMark Johnston #define CV_WAITERS_BOUND INT_MAX 55*11f9ca69SMark Johnston 56*11f9ca69SMark Johnston #define CV_WAITERS_INC(cvp) do { \ 57*11f9ca69SMark Johnston if ((cvp)->cv_waiters < CV_WAITERS_BOUND) \ 58*11f9ca69SMark Johnston (cvp)->cv_waiters++; \ 59*11f9ca69SMark Johnston } while (0) 60*11f9ca69SMark Johnston 61*11f9ca69SMark Johnston /* 62238510fcSJason Evans * Common sanity checks for cv_wait* functions. 63238510fcSJason Evans */ 648f27b08eSJohn Baldwin #define CV_ASSERT(cvp, lock, td) do { \ 650a15e5d3SAttilio Rao KASSERT((td) != NULL, ("%s: td NULL", __func__)); \ 6671fad9fdSJulian Elischer KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__)); \ 67a48740b6SDavid E. O'Brien KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__)); \ 688f27b08eSJohn Baldwin KASSERT((lock) != NULL, ("%s: lock NULL", __func__)); \ 69238510fcSJason Evans } while (0) 70238510fcSJason Evans 71238510fcSJason Evans /* 72238510fcSJason Evans * Initialize a condition variable. Must be called before use. 73238510fcSJason Evans */ 74238510fcSJason Evans void 75238510fcSJason Evans cv_init(struct cv *cvp, const char *desc) 76238510fcSJason Evans { 77238510fcSJason Evans 78238510fcSJason Evans cvp->cv_description = desc; 799000d57dSJohn Baldwin cvp->cv_waiters = 0; 80238510fcSJason Evans } 81238510fcSJason Evans 82238510fcSJason Evans /* 83238510fcSJason Evans * Destroy a condition variable. The condition variable must be re-initialized 84238510fcSJason Evans * in order to be re-used. 85238510fcSJason Evans */ 86238510fcSJason Evans void 87238510fcSJason Evans cv_destroy(struct cv *cvp) 88238510fcSJason Evans { 8944f3b092SJohn Baldwin #ifdef INVARIANTS 9044f3b092SJohn Baldwin struct sleepqueue *sq; 91238510fcSJason Evans 922ff0e645SJohn Baldwin sleepq_lock(cvp); 9344f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 9444f3b092SJohn Baldwin sleepq_release(cvp); 9544f3b092SJohn Baldwin KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__)); 9644f3b092SJohn Baldwin #endif 97238510fcSJason Evans } 98238510fcSJason Evans 99238510fcSJason Evans /* 100b40ce416SJulian Elischer * Wait on a condition variable. The current thread is placed on the condition 101238510fcSJason Evans * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 102b40ce416SJulian Elischer * condition variable will resume the thread. The mutex is released before 103238510fcSJason Evans * sleeping and will be held on return. It is recommended that the mutex be 104238510fcSJason Evans * held when cv_signal or cv_broadcast are called. 105238510fcSJason Evans */ 106238510fcSJason Evans void 1078f27b08eSJohn Baldwin _cv_wait(struct cv *cvp, struct lock_object *lock) 108238510fcSJason Evans { 1098f27b08eSJohn Baldwin WITNESS_SAVE_DECL(lock_witness); 1108f27b08eSJohn Baldwin struct lock_class *class; 111503916a7SJohn Baldwin struct thread *td; 1127faf4d90SDavide Italiano uintptr_t lock_state; 113238510fcSJason Evans 114503916a7SJohn Baldwin td = curthread; 115414e7679SJohn Baldwin lock_state = 0; 116503916a7SJohn Baldwin #ifdef KTRACE 117503916a7SJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 11888bf5036SJohn Baldwin ktrcsw(1, 0, cv_wmesg(cvp)); 119503916a7SJohn Baldwin #endif 1208f27b08eSJohn Baldwin CV_ASSERT(cvp, lock, td); 1218f27b08eSJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 122503916a7SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 1238f27b08eSJohn Baldwin class = LOCK_CLASS(lock); 124238510fcSJason Evans 12544f3b092SJohn Baldwin if (cold || panicstr) { 126238510fcSJason Evans /* 127fe799533SAndrew Gallatin * During autoconfiguration, just give interrupts 128fe799533SAndrew Gallatin * a chance, then just return. Don't run any other 129fe799533SAndrew Gallatin * thread or panic below, in case this is the idle 130fe799533SAndrew Gallatin * process and already asleep. 131238510fcSJason Evans */ 132238510fcSJason Evans return; 133238510fcSJason Evans } 1344bc37205SJeffrey Hsu 135503916a7SJohn Baldwin sleepq_lock(cvp); 136503916a7SJohn Baldwin 137*11f9ca69SMark Johnston CV_WAITERS_INC(cvp); 1387d43ca69SJohn Baldwin if (lock == &Giant.lock_object) 1397d43ca69SJohn Baldwin mtx_assert(&Giant, MA_OWNED); 140503916a7SJohn Baldwin DROP_GIANT(); 141503916a7SJohn Baldwin 1428f27b08eSJohn Baldwin sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); 143414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 1449fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 1459fa7ce0fSJohn Baldwin sleepq_release(cvp); 1467d43ca69SJohn Baldwin WITNESS_SAVE(lock, lock_witness); 1479fa7ce0fSJohn Baldwin lock_state = class->lc_unlock(lock); 1489fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 1499fa7ce0fSJohn Baldwin sleepq_lock(cvp); 150414e7679SJohn Baldwin } 151c5aa6b58SJeff Roberson sleepq_wait(cvp, 0); 152503916a7SJohn Baldwin 153503916a7SJohn Baldwin #ifdef KTRACE 154503916a7SJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 15588bf5036SJohn Baldwin ktrcsw(0, 0, cv_wmesg(cvp)); 156503916a7SJohn Baldwin #endif 157503916a7SJohn Baldwin PICKUP_GIANT(); 158414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 1598f27b08eSJohn Baldwin class->lc_lock(lock, lock_state); 1608f27b08eSJohn Baldwin WITNESS_RESTORE(lock, lock_witness); 16192f44a3fSCraig Rodrigues } 162414e7679SJohn Baldwin } 16392f44a3fSCraig Rodrigues 16492f44a3fSCraig Rodrigues /* 16592f44a3fSCraig Rodrigues * Wait on a condition variable. This function differs from cv_wait by 16692f44a3fSCraig Rodrigues * not aquiring the mutex after condition variable was signaled. 16792f44a3fSCraig Rodrigues */ 16892f44a3fSCraig Rodrigues void 1698f27b08eSJohn Baldwin _cv_wait_unlock(struct cv *cvp, struct lock_object *lock) 17092f44a3fSCraig Rodrigues { 1718f27b08eSJohn Baldwin struct lock_class *class; 17292f44a3fSCraig Rodrigues struct thread *td; 17392f44a3fSCraig Rodrigues 17492f44a3fSCraig Rodrigues td = curthread; 17592f44a3fSCraig Rodrigues #ifdef KTRACE 17692f44a3fSCraig Rodrigues if (KTRPOINT(td, KTR_CSW)) 17788bf5036SJohn Baldwin ktrcsw(1, 0, cv_wmesg(cvp)); 17892f44a3fSCraig Rodrigues #endif 1798f27b08eSJohn Baldwin CV_ASSERT(cvp, lock, td); 1808f27b08eSJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 18192f44a3fSCraig Rodrigues "Waiting on \"%s\"", cvp->cv_description); 182414e7679SJohn Baldwin KASSERT(lock != &Giant.lock_object, 183414e7679SJohn Baldwin ("cv_wait_unlock cannot be used with Giant")); 1848f27b08eSJohn Baldwin class = LOCK_CLASS(lock); 18592f44a3fSCraig Rodrigues 18692f44a3fSCraig Rodrigues if (cold || panicstr) { 18792f44a3fSCraig Rodrigues /* 18892f44a3fSCraig Rodrigues * During autoconfiguration, just give interrupts 18992f44a3fSCraig Rodrigues * a chance, then just return. Don't run any other 19092f44a3fSCraig Rodrigues * thread or panic below, in case this is the idle 19192f44a3fSCraig Rodrigues * process and already asleep. 19292f44a3fSCraig Rodrigues */ 1938f27b08eSJohn Baldwin class->lc_unlock(lock); 19492f44a3fSCraig Rodrigues return; 19592f44a3fSCraig Rodrigues } 19692f44a3fSCraig Rodrigues 1972ff0e645SJohn Baldwin sleepq_lock(cvp); 198238510fcSJason Evans 199*11f9ca69SMark Johnston CV_WAITERS_INC(cvp); 200c86b6ff5SJohn Baldwin DROP_GIANT(); 201238510fcSJason Evans 2028f27b08eSJohn Baldwin sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); 2039fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 2049fa7ce0fSJohn Baldwin sleepq_release(cvp); 2059fa7ce0fSJohn Baldwin class->lc_unlock(lock); 2069fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 2079fa7ce0fSJohn Baldwin sleepq_lock(cvp); 208c5aa6b58SJeff Roberson sleepq_wait(cvp, 0); 209238510fcSJason Evans 210503916a7SJohn Baldwin #ifdef KTRACE 211503916a7SJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 21288bf5036SJohn Baldwin ktrcsw(0, 0, cv_wmesg(cvp)); 213503916a7SJohn Baldwin #endif 214238510fcSJason Evans PICKUP_GIANT(); 215238510fcSJason Evans } 216238510fcSJason Evans 217238510fcSJason Evans /* 218238510fcSJason Evans * Wait on a condition variable, allowing interruption by signals. Return 0 if 219b40ce416SJulian Elischer * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 220238510fcSJason Evans * a signal was caught. If ERESTART is returned the system call should be 221238510fcSJason Evans * restarted if possible. 222238510fcSJason Evans */ 223238510fcSJason Evans int 2248f27b08eSJohn Baldwin _cv_wait_sig(struct cv *cvp, struct lock_object *lock) 225238510fcSJason Evans { 2268f27b08eSJohn Baldwin WITNESS_SAVE_DECL(lock_witness); 2278f27b08eSJohn Baldwin struct lock_class *class; 228b40ce416SJulian Elischer struct thread *td; 2297faf4d90SDavide Italiano uintptr_t lock_state; 2307faf4d90SDavide Italiano int rval; 231238510fcSJason Evans 232b40ce416SJulian Elischer td = curthread; 233414e7679SJohn Baldwin lock_state = 0; 234238510fcSJason Evans #ifdef KTRACE 2359ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 23688bf5036SJohn Baldwin ktrcsw(1, 0, cv_wmesg(cvp)); 237238510fcSJason Evans #endif 2388f27b08eSJohn Baldwin CV_ASSERT(cvp, lock, td); 2398f27b08eSJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 24026306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 2418f27b08eSJohn Baldwin class = LOCK_CLASS(lock); 242238510fcSJason Evans 243238510fcSJason Evans if (cold || panicstr) { 244238510fcSJason Evans /* 245238510fcSJason Evans * After a panic, or during autoconfiguration, just give 246238510fcSJason Evans * interrupts a chance, then just return; don't run any other 247238510fcSJason Evans * procs or panic below, in case this is the idle process and 248238510fcSJason Evans * already asleep. 249238510fcSJason Evans */ 250274f8f48SJohn Baldwin return (0); 251238510fcSJason Evans } 2524bc37205SJeffrey Hsu 2532ff0e645SJohn Baldwin sleepq_lock(cvp); 2544bc37205SJeffrey Hsu 255*11f9ca69SMark Johnston CV_WAITERS_INC(cvp); 2567d43ca69SJohn Baldwin if (lock == &Giant.lock_object) 2577d43ca69SJohn Baldwin mtx_assert(&Giant, MA_OWNED); 258c86b6ff5SJohn Baldwin DROP_GIANT(); 259238510fcSJason Evans 2608f27b08eSJohn Baldwin sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | 2616cbb70e2SKip Macy SLEEPQ_INTERRUPTIBLE, 0); 262414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 2639fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 2649fa7ce0fSJohn Baldwin sleepq_release(cvp); 2657d43ca69SJohn Baldwin WITNESS_SAVE(lock, lock_witness); 2669fa7ce0fSJohn Baldwin lock_state = class->lc_unlock(lock); 2679fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 2689fa7ce0fSJohn Baldwin sleepq_lock(cvp); 269414e7679SJohn Baldwin } 270c5aa6b58SJeff Roberson rval = sleepq_wait_sig(cvp, 0); 271238510fcSJason Evans 272238510fcSJason Evans #ifdef KTRACE 2739ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 27488bf5036SJohn Baldwin ktrcsw(0, 0, cv_wmesg(cvp)); 275238510fcSJason Evans #endif 2769ba7fe1bSJohn Baldwin PICKUP_GIANT(); 277414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 2788f27b08eSJohn Baldwin class->lc_lock(lock, lock_state); 2798f27b08eSJohn Baldwin WITNESS_RESTORE(lock, lock_witness); 280414e7679SJohn Baldwin } 281238510fcSJason Evans 282238510fcSJason Evans return (rval); 283238510fcSJason Evans } 284238510fcSJason Evans 285238510fcSJason Evans /* 28646153735SDavide Italiano * Wait on a condition variable for (at most) the value specified in sbt 28746153735SDavide Italiano * argument. Returns 0 if the process was resumed by cv_signal or cv_broadcast, 28846153735SDavide Italiano * EWOULDBLOCK if the timeout expires. 289238510fcSJason Evans */ 290238510fcSJason Evans int 29146153735SDavide Italiano _cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt, 29246153735SDavide Italiano sbintime_t pr, int flags) 293238510fcSJason Evans { 2948f27b08eSJohn Baldwin WITNESS_SAVE_DECL(lock_witness); 2958f27b08eSJohn Baldwin struct lock_class *class; 296b40ce416SJulian Elischer struct thread *td; 2978f27b08eSJohn Baldwin int lock_state, rval; 298238510fcSJason Evans 299b40ce416SJulian Elischer td = curthread; 300414e7679SJohn Baldwin lock_state = 0; 301238510fcSJason Evans #ifdef KTRACE 3029ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 30388bf5036SJohn Baldwin ktrcsw(1, 0, cv_wmesg(cvp)); 304238510fcSJason Evans #endif 3058f27b08eSJohn Baldwin CV_ASSERT(cvp, lock, td); 3068f27b08eSJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 30726306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 3088f27b08eSJohn Baldwin class = LOCK_CLASS(lock); 309238510fcSJason Evans 310238510fcSJason Evans if (cold || panicstr) { 311238510fcSJason Evans /* 312238510fcSJason Evans * After a panic, or during autoconfiguration, just give 313238510fcSJason Evans * interrupts a chance, then just return; don't run any other 314b40ce416SJulian Elischer * thread or panic below, in case this is the idle process and 315238510fcSJason Evans * already asleep. 316238510fcSJason Evans */ 317238510fcSJason Evans return 0; 318238510fcSJason Evans } 3194bc37205SJeffrey Hsu 3202ff0e645SJohn Baldwin sleepq_lock(cvp); 321238510fcSJason Evans 322*11f9ca69SMark Johnston CV_WAITERS_INC(cvp); 3237d43ca69SJohn Baldwin if (lock == &Giant.lock_object) 3247d43ca69SJohn Baldwin mtx_assert(&Giant, MA_OWNED); 325c86b6ff5SJohn Baldwin DROP_GIANT(); 326238510fcSJason Evans 3278f27b08eSJohn Baldwin sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); 32846153735SDavide Italiano sleepq_set_timeout_sbt(cvp, sbt, pr, flags); 329414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 330a115fb62SHans Petter Selasky if (class->lc_flags & LC_SLEEPABLE) 331a115fb62SHans Petter Selasky sleepq_release(cvp); 3327d43ca69SJohn Baldwin WITNESS_SAVE(lock, lock_witness); 3339fa7ce0fSJohn Baldwin lock_state = class->lc_unlock(lock); 334a115fb62SHans Petter Selasky if (class->lc_flags & LC_SLEEPABLE) 3351a26c3c0SHans Petter Selasky sleepq_lock(cvp); 336a115fb62SHans Petter Selasky } 337c5aa6b58SJeff Roberson rval = sleepq_timedwait(cvp, 0); 338238510fcSJason Evans 339238510fcSJason Evans #ifdef KTRACE 3409ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 34188bf5036SJohn Baldwin ktrcsw(0, 0, cv_wmesg(cvp)); 342238510fcSJason Evans #endif 343238510fcSJason Evans PICKUP_GIANT(); 344414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 3458f27b08eSJohn Baldwin class->lc_lock(lock, lock_state); 3468f27b08eSJohn Baldwin WITNESS_RESTORE(lock, lock_witness); 347414e7679SJohn Baldwin } 348238510fcSJason Evans 349238510fcSJason Evans return (rval); 350238510fcSJason Evans } 351238510fcSJason Evans 352238510fcSJason Evans /* 35346153735SDavide Italiano * Wait on a condition variable for (at most) the value specified in sbt 35446153735SDavide Italiano * argument, allowing interruption by signals. 35546153735SDavide Italiano * Returns 0 if the thread was resumed by cv_signal or cv_broadcast, 35646153735SDavide Italiano * EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if a signal 35746153735SDavide Italiano * was caught. 358238510fcSJason Evans */ 359238510fcSJason Evans int 36046153735SDavide Italiano _cv_timedwait_sig_sbt(struct cv *cvp, struct lock_object *lock, 36146153735SDavide Italiano sbintime_t sbt, sbintime_t pr, int flags) 362238510fcSJason Evans { 3638f27b08eSJohn Baldwin WITNESS_SAVE_DECL(lock_witness); 3648f27b08eSJohn Baldwin struct lock_class *class; 365b40ce416SJulian Elischer struct thread *td; 3668f27b08eSJohn Baldwin int lock_state, rval; 367238510fcSJason Evans 368b40ce416SJulian Elischer td = curthread; 369414e7679SJohn Baldwin lock_state = 0; 370238510fcSJason Evans #ifdef KTRACE 3719ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 37288bf5036SJohn Baldwin ktrcsw(1, 0, cv_wmesg(cvp)); 373238510fcSJason Evans #endif 3748f27b08eSJohn Baldwin CV_ASSERT(cvp, lock, td); 3758f27b08eSJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 37626306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 3778f27b08eSJohn Baldwin class = LOCK_CLASS(lock); 378238510fcSJason Evans 379238510fcSJason Evans if (cold || panicstr) { 380238510fcSJason Evans /* 381238510fcSJason Evans * After a panic, or during autoconfiguration, just give 382238510fcSJason Evans * interrupts a chance, then just return; don't run any other 383b40ce416SJulian Elischer * thread or panic below, in case this is the idle process and 384238510fcSJason Evans * already asleep. 385238510fcSJason Evans */ 386238510fcSJason Evans return 0; 387238510fcSJason Evans } 3884bc37205SJeffrey Hsu 3892ff0e645SJohn Baldwin sleepq_lock(cvp); 390238510fcSJason Evans 391*11f9ca69SMark Johnston CV_WAITERS_INC(cvp); 3927d43ca69SJohn Baldwin if (lock == &Giant.lock_object) 3937d43ca69SJohn Baldwin mtx_assert(&Giant, MA_OWNED); 394c86b6ff5SJohn Baldwin DROP_GIANT(); 395238510fcSJason Evans 3968f27b08eSJohn Baldwin sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | 3976cbb70e2SKip Macy SLEEPQ_INTERRUPTIBLE, 0); 39846153735SDavide Italiano sleepq_set_timeout_sbt(cvp, sbt, pr, flags); 399414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 400a115fb62SHans Petter Selasky if (class->lc_flags & LC_SLEEPABLE) 401a115fb62SHans Petter Selasky sleepq_release(cvp); 4027d43ca69SJohn Baldwin WITNESS_SAVE(lock, lock_witness); 4039fa7ce0fSJohn Baldwin lock_state = class->lc_unlock(lock); 404a115fb62SHans Petter Selasky if (class->lc_flags & LC_SLEEPABLE) 4051a26c3c0SHans Petter Selasky sleepq_lock(cvp); 406a115fb62SHans Petter Selasky } 407c5aa6b58SJeff Roberson rval = sleepq_timedwait_sig(cvp, 0); 408238510fcSJason Evans 409238510fcSJason Evans #ifdef KTRACE 4109ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 41188bf5036SJohn Baldwin ktrcsw(0, 0, cv_wmesg(cvp)); 412238510fcSJason Evans #endif 4139ba7fe1bSJohn Baldwin PICKUP_GIANT(); 414414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 4158f27b08eSJohn Baldwin class->lc_lock(lock, lock_state); 4168f27b08eSJohn Baldwin WITNESS_RESTORE(lock, lock_witness); 417414e7679SJohn Baldwin } 418238510fcSJason Evans 419238510fcSJason Evans return (rval); 420238510fcSJason Evans } 421238510fcSJason Evans 422238510fcSJason Evans /* 423b40ce416SJulian Elischer * Signal a condition variable, wakes up one waiting thread. Will also wakeup 424238510fcSJason Evans * the swapper if the process is not in memory, so that it can bring the 425b40ce416SJulian Elischer * sleeping process in. Note that this may also result in additional threads 426238510fcSJason Evans * being made runnable. Should be called with the same mutex as was passed to 427238510fcSJason Evans * cv_wait held. 428238510fcSJason Evans */ 429238510fcSJason Evans void 430238510fcSJason Evans cv_signal(struct cv *cvp) 431238510fcSJason Evans { 432da7bbd2cSJohn Baldwin int wakeup_swapper; 433238510fcSJason Evans 434da7bbd2cSJohn Baldwin wakeup_swapper = 0; 4352ff0e645SJohn Baldwin sleepq_lock(cvp); 436c636f94bSJohn Baldwin if (cvp->cv_waiters > 0) { 437*11f9ca69SMark Johnston if (cvp->cv_waiters == CV_WAITERS_BOUND && 438*11f9ca69SMark Johnston sleepq_lookup(cvp) == NULL) { 439*11f9ca69SMark Johnston cvp->cv_waiters = 0; 440*11f9ca69SMark Johnston } else { 441*11f9ca69SMark Johnston if (cvp->cv_waiters < CV_WAITERS_BOUND) 442c636f94bSJohn Baldwin cvp->cv_waiters--; 443*11f9ca69SMark Johnston wakeup_swapper = sleepq_signal(cvp, SLEEPQ_CONDVAR, 0, 444*11f9ca69SMark Johnston 0); 445*11f9ca69SMark Johnston } 446c636f94bSJohn Baldwin } 4472ff0e645SJohn Baldwin sleepq_release(cvp); 448da7bbd2cSJohn Baldwin if (wakeup_swapper) 449da7bbd2cSJohn Baldwin kick_proc0(); 4509000d57dSJohn Baldwin } 451238510fcSJason Evans 452238510fcSJason Evans /* 453b40ce416SJulian Elischer * Broadcast a signal to a condition variable. Wakes up all waiting threads. 454238510fcSJason Evans * Should be called with the same mutex as was passed to cv_wait held. 455238510fcSJason Evans */ 456238510fcSJason Evans void 457512824f8SSeigo Tanimura cv_broadcastpri(struct cv *cvp, int pri) 458238510fcSJason Evans { 459da7bbd2cSJohn Baldwin int wakeup_swapper; 460da7bbd2cSJohn Baldwin 461c5aa6b58SJeff Roberson /* 462c5aa6b58SJeff Roberson * XXX sleepq_broadcast pri argument changed from -1 meaning 463c5aa6b58SJeff Roberson * no pri to 0 meaning no pri. 464c5aa6b58SJeff Roberson */ 465da7bbd2cSJohn Baldwin wakeup_swapper = 0; 466c5aa6b58SJeff Roberson if (pri == -1) 467c5aa6b58SJeff Roberson pri = 0; 4682ff0e645SJohn Baldwin sleepq_lock(cvp); 469c636f94bSJohn Baldwin if (cvp->cv_waiters > 0) { 470c636f94bSJohn Baldwin cvp->cv_waiters = 0; 471da7bbd2cSJohn Baldwin wakeup_swapper = sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0); 472c636f94bSJohn Baldwin } 4732ff0e645SJohn Baldwin sleepq_release(cvp); 474da7bbd2cSJohn Baldwin if (wakeup_swapper) 475da7bbd2cSJohn Baldwin kick_proc0(); 4769000d57dSJohn Baldwin } 477