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> 34fb919e4dSMark Murray #include <sys/lock.h> 35fb919e4dSMark Murray #include <sys/mutex.h> 36238510fcSJason Evans #include <sys/proc.h> 37238510fcSJason Evans #include <sys/kernel.h> 38238510fcSJason Evans #include <sys/ktr.h> 39238510fcSJason Evans #include <sys/condvar.h> 404e997f4bSJeff Roberson #include <sys/sched.h> 41238510fcSJason Evans #include <sys/signalvar.h> 4244f3b092SJohn Baldwin #include <sys/sleepqueue.h> 43238510fcSJason Evans #include <sys/resourcevar.h> 44238510fcSJason Evans #ifdef KTRACE 45238510fcSJason Evans #include <sys/uio.h> 46238510fcSJason Evans #include <sys/ktrace.h> 47238510fcSJason Evans #endif 48238510fcSJason Evans 49238510fcSJason Evans /* 50238510fcSJason Evans * Common sanity checks for cv_wait* functions. 51238510fcSJason Evans */ 528f27b08eSJohn Baldwin #define CV_ASSERT(cvp, lock, td) do { \ 53a48740b6SDavid E. O'Brien KASSERT((td) != NULL, ("%s: curthread NULL", __func__)); \ 5471fad9fdSJulian Elischer KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__)); \ 55a48740b6SDavid E. O'Brien KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__)); \ 568f27b08eSJohn Baldwin KASSERT((lock) != NULL, ("%s: lock NULL", __func__)); \ 57238510fcSJason Evans } while (0) 58238510fcSJason Evans 59238510fcSJason Evans /* 60238510fcSJason Evans * Initialize a condition variable. Must be called before use. 61238510fcSJason Evans */ 62238510fcSJason Evans void 63238510fcSJason Evans cv_init(struct cv *cvp, const char *desc) 64238510fcSJason Evans { 65238510fcSJason Evans 66238510fcSJason Evans cvp->cv_description = desc; 679000d57dSJohn Baldwin cvp->cv_waiters = 0; 68238510fcSJason Evans } 69238510fcSJason Evans 70238510fcSJason Evans /* 71238510fcSJason Evans * Destroy a condition variable. The condition variable must be re-initialized 72238510fcSJason Evans * in order to be re-used. 73238510fcSJason Evans */ 74238510fcSJason Evans void 75238510fcSJason Evans cv_destroy(struct cv *cvp) 76238510fcSJason Evans { 7744f3b092SJohn Baldwin #ifdef INVARIANTS 7844f3b092SJohn Baldwin struct sleepqueue *sq; 79238510fcSJason Evans 802ff0e645SJohn Baldwin sleepq_lock(cvp); 8144f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 8244f3b092SJohn Baldwin sleepq_release(cvp); 8344f3b092SJohn Baldwin KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__)); 8444f3b092SJohn Baldwin #endif 85238510fcSJason Evans } 86238510fcSJason Evans 87238510fcSJason Evans /* 88b40ce416SJulian Elischer * Wait on a condition variable. The current thread is placed on the condition 89238510fcSJason Evans * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 90b40ce416SJulian Elischer * condition variable will resume the thread. The mutex is released before 91238510fcSJason Evans * sleeping and will be held on return. It is recommended that the mutex be 92238510fcSJason Evans * held when cv_signal or cv_broadcast are called. 93238510fcSJason Evans */ 94238510fcSJason Evans void 958f27b08eSJohn Baldwin _cv_wait(struct cv *cvp, struct lock_object *lock) 96238510fcSJason Evans { 978f27b08eSJohn Baldwin WITNESS_SAVE_DECL(lock_witness); 988f27b08eSJohn Baldwin struct lock_class *class; 99503916a7SJohn Baldwin struct thread *td; 1008f27b08eSJohn Baldwin int lock_state; 101238510fcSJason Evans 102503916a7SJohn Baldwin td = curthread; 103414e7679SJohn Baldwin lock_state = 0; 104503916a7SJohn Baldwin #ifdef KTRACE 105503916a7SJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 106503916a7SJohn Baldwin ktrcsw(1, 0); 107503916a7SJohn Baldwin #endif 1088f27b08eSJohn Baldwin CV_ASSERT(cvp, lock, td); 1098f27b08eSJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 110503916a7SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 1118f27b08eSJohn Baldwin class = LOCK_CLASS(lock); 112238510fcSJason Evans 11344f3b092SJohn Baldwin if (cold || panicstr) { 114238510fcSJason Evans /* 115fe799533SAndrew Gallatin * During autoconfiguration, just give interrupts 116fe799533SAndrew Gallatin * a chance, then just return. Don't run any other 117fe799533SAndrew Gallatin * thread or panic below, in case this is the idle 118fe799533SAndrew Gallatin * process and already asleep. 119238510fcSJason Evans */ 120238510fcSJason Evans return; 121238510fcSJason Evans } 1224bc37205SJeffrey Hsu 123503916a7SJohn Baldwin sleepq_lock(cvp); 124503916a7SJohn Baldwin 125503916a7SJohn Baldwin cvp->cv_waiters++; 1267d43ca69SJohn Baldwin if (lock == &Giant.lock_object) 1277d43ca69SJohn Baldwin mtx_assert(&Giant, MA_OWNED); 128503916a7SJohn Baldwin DROP_GIANT(); 129503916a7SJohn Baldwin 1308f27b08eSJohn Baldwin sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); 131414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 1329fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 1339fa7ce0fSJohn Baldwin sleepq_release(cvp); 1347d43ca69SJohn Baldwin WITNESS_SAVE(lock, lock_witness); 1359fa7ce0fSJohn Baldwin lock_state = class->lc_unlock(lock); 1369fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 1379fa7ce0fSJohn Baldwin sleepq_lock(cvp); 138414e7679SJohn Baldwin } 139c5aa6b58SJeff Roberson sleepq_wait(cvp, 0); 140503916a7SJohn Baldwin 141503916a7SJohn Baldwin #ifdef KTRACE 142503916a7SJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 143503916a7SJohn Baldwin ktrcsw(0, 0); 144503916a7SJohn Baldwin #endif 145503916a7SJohn Baldwin PICKUP_GIANT(); 146414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 1478f27b08eSJohn Baldwin class->lc_lock(lock, lock_state); 1488f27b08eSJohn Baldwin WITNESS_RESTORE(lock, lock_witness); 14992f44a3fSCraig Rodrigues } 150414e7679SJohn Baldwin } 15192f44a3fSCraig Rodrigues 15292f44a3fSCraig Rodrigues /* 15392f44a3fSCraig Rodrigues * Wait on a condition variable. This function differs from cv_wait by 15492f44a3fSCraig Rodrigues * not aquiring the mutex after condition variable was signaled. 15592f44a3fSCraig Rodrigues */ 15692f44a3fSCraig Rodrigues void 1578f27b08eSJohn Baldwin _cv_wait_unlock(struct cv *cvp, struct lock_object *lock) 15892f44a3fSCraig Rodrigues { 1598f27b08eSJohn Baldwin struct lock_class *class; 16092f44a3fSCraig Rodrigues struct thread *td; 16192f44a3fSCraig Rodrigues 16292f44a3fSCraig Rodrigues td = curthread; 16392f44a3fSCraig Rodrigues #ifdef KTRACE 16492f44a3fSCraig Rodrigues if (KTRPOINT(td, KTR_CSW)) 16592f44a3fSCraig Rodrigues ktrcsw(1, 0); 16692f44a3fSCraig Rodrigues #endif 1678f27b08eSJohn Baldwin CV_ASSERT(cvp, lock, td); 1688f27b08eSJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 16992f44a3fSCraig Rodrigues "Waiting on \"%s\"", cvp->cv_description); 170414e7679SJohn Baldwin KASSERT(lock != &Giant.lock_object, 171414e7679SJohn Baldwin ("cv_wait_unlock cannot be used with Giant")); 1728f27b08eSJohn Baldwin class = LOCK_CLASS(lock); 17392f44a3fSCraig Rodrigues 17492f44a3fSCraig Rodrigues if (cold || panicstr) { 17592f44a3fSCraig Rodrigues /* 17692f44a3fSCraig Rodrigues * During autoconfiguration, just give interrupts 17792f44a3fSCraig Rodrigues * a chance, then just return. Don't run any other 17892f44a3fSCraig Rodrigues * thread or panic below, in case this is the idle 17992f44a3fSCraig Rodrigues * process and already asleep. 18092f44a3fSCraig Rodrigues */ 1818f27b08eSJohn Baldwin class->lc_unlock(lock); 18292f44a3fSCraig Rodrigues return; 18392f44a3fSCraig Rodrigues } 18492f44a3fSCraig Rodrigues 1852ff0e645SJohn Baldwin sleepq_lock(cvp); 186238510fcSJason Evans 1879000d57dSJohn Baldwin cvp->cv_waiters++; 188c86b6ff5SJohn Baldwin DROP_GIANT(); 189238510fcSJason Evans 1908f27b08eSJohn Baldwin sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); 1919fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 1929fa7ce0fSJohn Baldwin sleepq_release(cvp); 1939fa7ce0fSJohn Baldwin class->lc_unlock(lock); 1949fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 1959fa7ce0fSJohn Baldwin sleepq_lock(cvp); 196c5aa6b58SJeff Roberson sleepq_wait(cvp, 0); 197238510fcSJason Evans 198503916a7SJohn Baldwin #ifdef KTRACE 199503916a7SJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 200503916a7SJohn Baldwin ktrcsw(0, 0); 201503916a7SJohn Baldwin #endif 202238510fcSJason Evans PICKUP_GIANT(); 203238510fcSJason Evans } 204238510fcSJason Evans 205238510fcSJason Evans /* 206238510fcSJason Evans * Wait on a condition variable, allowing interruption by signals. Return 0 if 207b40ce416SJulian Elischer * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 208238510fcSJason Evans * a signal was caught. If ERESTART is returned the system call should be 209238510fcSJason Evans * restarted if possible. 210238510fcSJason Evans */ 211238510fcSJason Evans int 2128f27b08eSJohn Baldwin _cv_wait_sig(struct cv *cvp, struct lock_object *lock) 213238510fcSJason Evans { 2148f27b08eSJohn Baldwin WITNESS_SAVE_DECL(lock_witness); 2158f27b08eSJohn Baldwin struct lock_class *class; 216b40ce416SJulian Elischer struct thread *td; 21766f769feSPeter Wemm struct proc *p; 2188f27b08eSJohn Baldwin int lock_state, rval; 219238510fcSJason Evans 220b40ce416SJulian Elischer td = curthread; 2219ef3a985SJohn Baldwin p = td->td_proc; 222414e7679SJohn Baldwin lock_state = 0; 223238510fcSJason Evans #ifdef KTRACE 2249ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 2259ba7fe1bSJohn Baldwin ktrcsw(1, 0); 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 232238510fcSJason Evans if (cold || panicstr) { 233238510fcSJason Evans /* 234238510fcSJason Evans * After a panic, or during autoconfiguration, just give 235238510fcSJason Evans * interrupts a chance, then just return; don't run any other 236238510fcSJason Evans * procs or panic below, in case this is the idle process and 237238510fcSJason Evans * already asleep. 238238510fcSJason Evans */ 239274f8f48SJohn Baldwin return (0); 240238510fcSJason Evans } 2414bc37205SJeffrey Hsu 2422ff0e645SJohn Baldwin sleepq_lock(cvp); 2434bc37205SJeffrey Hsu 2449000d57dSJohn Baldwin cvp->cv_waiters++; 2457d43ca69SJohn Baldwin if (lock == &Giant.lock_object) 2467d43ca69SJohn Baldwin mtx_assert(&Giant, MA_OWNED); 247c86b6ff5SJohn Baldwin DROP_GIANT(); 248238510fcSJason Evans 2498f27b08eSJohn Baldwin sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | 2506cbb70e2SKip Macy SLEEPQ_INTERRUPTIBLE, 0); 251414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 2529fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 2539fa7ce0fSJohn Baldwin sleepq_release(cvp); 2547d43ca69SJohn Baldwin WITNESS_SAVE(lock, lock_witness); 2559fa7ce0fSJohn Baldwin lock_state = class->lc_unlock(lock); 2569fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 2579fa7ce0fSJohn Baldwin sleepq_lock(cvp); 258414e7679SJohn Baldwin } 259c5aa6b58SJeff Roberson rval = sleepq_wait_sig(cvp, 0); 260238510fcSJason Evans 261238510fcSJason Evans #ifdef KTRACE 2629ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 2639ba7fe1bSJohn Baldwin ktrcsw(0, 0); 264238510fcSJason Evans #endif 2659ba7fe1bSJohn Baldwin PICKUP_GIANT(); 266414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 2678f27b08eSJohn Baldwin class->lc_lock(lock, lock_state); 2688f27b08eSJohn Baldwin WITNESS_RESTORE(lock, lock_witness); 269414e7679SJohn Baldwin } 270238510fcSJason Evans 271238510fcSJason Evans return (rval); 272238510fcSJason Evans } 273238510fcSJason Evans 274238510fcSJason Evans /* 275238510fcSJason Evans * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 276238510fcSJason Evans * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 277238510fcSJason Evans * expires. 278238510fcSJason Evans */ 279238510fcSJason Evans int 2808f27b08eSJohn Baldwin _cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo) 281238510fcSJason Evans { 2828f27b08eSJohn Baldwin WITNESS_SAVE_DECL(lock_witness); 2838f27b08eSJohn Baldwin struct lock_class *class; 284b40ce416SJulian Elischer struct thread *td; 2858f27b08eSJohn Baldwin int lock_state, rval; 286238510fcSJason Evans 287b40ce416SJulian Elischer td = curthread; 288238510fcSJason Evans rval = 0; 289414e7679SJohn Baldwin lock_state = 0; 290238510fcSJason Evans #ifdef KTRACE 2919ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 2929ba7fe1bSJohn Baldwin ktrcsw(1, 0); 293238510fcSJason Evans #endif 2948f27b08eSJohn Baldwin CV_ASSERT(cvp, lock, td); 2958f27b08eSJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 29626306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 2978f27b08eSJohn Baldwin class = LOCK_CLASS(lock); 298238510fcSJason Evans 299238510fcSJason Evans if (cold || panicstr) { 300238510fcSJason Evans /* 301238510fcSJason Evans * After a panic, or during autoconfiguration, just give 302238510fcSJason Evans * interrupts a chance, then just return; don't run any other 303b40ce416SJulian Elischer * thread or panic below, in case this is the idle process and 304238510fcSJason Evans * already asleep. 305238510fcSJason Evans */ 306238510fcSJason Evans return 0; 307238510fcSJason Evans } 3084bc37205SJeffrey Hsu 3092ff0e645SJohn Baldwin sleepq_lock(cvp); 310238510fcSJason Evans 3119000d57dSJohn Baldwin cvp->cv_waiters++; 3127d43ca69SJohn Baldwin if (lock == &Giant.lock_object) 3137d43ca69SJohn Baldwin mtx_assert(&Giant, MA_OWNED); 314c86b6ff5SJohn Baldwin DROP_GIANT(); 315238510fcSJason Evans 3168f27b08eSJohn Baldwin sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); 3171ed3e44fSJohn Baldwin sleepq_set_timeout(cvp, timo); 318414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 3199fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 3209fa7ce0fSJohn Baldwin sleepq_release(cvp); 3217d43ca69SJohn Baldwin WITNESS_SAVE(lock, lock_witness); 3229fa7ce0fSJohn Baldwin lock_state = class->lc_unlock(lock); 3239fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 3249fa7ce0fSJohn Baldwin sleepq_lock(cvp); 325414e7679SJohn Baldwin } 326c5aa6b58SJeff Roberson rval = sleepq_timedwait(cvp, 0); 327238510fcSJason Evans 328238510fcSJason Evans #ifdef KTRACE 3299ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 3309ba7fe1bSJohn Baldwin ktrcsw(0, 0); 331238510fcSJason Evans #endif 332238510fcSJason Evans PICKUP_GIANT(); 333414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 3348f27b08eSJohn Baldwin class->lc_lock(lock, lock_state); 3358f27b08eSJohn Baldwin WITNESS_RESTORE(lock, lock_witness); 336414e7679SJohn Baldwin } 337238510fcSJason Evans 338238510fcSJason Evans return (rval); 339238510fcSJason Evans } 340238510fcSJason Evans 341238510fcSJason Evans /* 342238510fcSJason Evans * Wait on a condition variable for at most timo/hz seconds, allowing 343b40ce416SJulian Elischer * interruption by signals. Returns 0 if the thread was resumed by cv_signal 344238510fcSJason Evans * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 345238510fcSJason Evans * a signal was caught. 346238510fcSJason Evans */ 347238510fcSJason Evans int 3488f27b08eSJohn Baldwin _cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo) 349238510fcSJason Evans { 3508f27b08eSJohn Baldwin WITNESS_SAVE_DECL(lock_witness); 3518f27b08eSJohn Baldwin struct lock_class *class; 352b40ce416SJulian Elischer struct thread *td; 3539ef3a985SJohn Baldwin struct proc *p; 3548f27b08eSJohn Baldwin int lock_state, rval; 355238510fcSJason Evans 356b40ce416SJulian Elischer td = curthread; 3579ef3a985SJohn Baldwin p = td->td_proc; 358238510fcSJason Evans rval = 0; 359414e7679SJohn Baldwin lock_state = 0; 360238510fcSJason Evans #ifdef KTRACE 3619ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 3629ba7fe1bSJohn Baldwin ktrcsw(1, 0); 363238510fcSJason Evans #endif 3648f27b08eSJohn Baldwin CV_ASSERT(cvp, lock, td); 3658f27b08eSJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 36626306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 3678f27b08eSJohn Baldwin class = LOCK_CLASS(lock); 368238510fcSJason Evans 369238510fcSJason Evans if (cold || panicstr) { 370238510fcSJason Evans /* 371238510fcSJason Evans * After a panic, or during autoconfiguration, just give 372238510fcSJason Evans * interrupts a chance, then just return; don't run any other 373b40ce416SJulian Elischer * thread or panic below, in case this is the idle process and 374238510fcSJason Evans * already asleep. 375238510fcSJason Evans */ 376238510fcSJason Evans return 0; 377238510fcSJason Evans } 3784bc37205SJeffrey Hsu 3792ff0e645SJohn Baldwin sleepq_lock(cvp); 380238510fcSJason Evans 3819000d57dSJohn Baldwin cvp->cv_waiters++; 3827d43ca69SJohn Baldwin if (lock == &Giant.lock_object) 3837d43ca69SJohn Baldwin mtx_assert(&Giant, MA_OWNED); 384c86b6ff5SJohn Baldwin DROP_GIANT(); 385238510fcSJason Evans 3868f27b08eSJohn Baldwin sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | 3876cbb70e2SKip Macy SLEEPQ_INTERRUPTIBLE, 0); 3881ed3e44fSJohn Baldwin sleepq_set_timeout(cvp, timo); 389414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 3909fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 3919fa7ce0fSJohn Baldwin sleepq_release(cvp); 3927d43ca69SJohn Baldwin WITNESS_SAVE(lock, lock_witness); 3939fa7ce0fSJohn Baldwin lock_state = class->lc_unlock(lock); 3949fa7ce0fSJohn Baldwin if (class->lc_flags & LC_SLEEPABLE) 3959fa7ce0fSJohn Baldwin sleepq_lock(cvp); 396414e7679SJohn Baldwin } 397c5aa6b58SJeff Roberson rval = sleepq_timedwait_sig(cvp, 0); 398238510fcSJason Evans 399238510fcSJason Evans #ifdef KTRACE 4009ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 4019ba7fe1bSJohn Baldwin ktrcsw(0, 0); 402238510fcSJason Evans #endif 4039ba7fe1bSJohn Baldwin PICKUP_GIANT(); 404414e7679SJohn Baldwin if (lock != &Giant.lock_object) { 4058f27b08eSJohn Baldwin class->lc_lock(lock, lock_state); 4068f27b08eSJohn Baldwin WITNESS_RESTORE(lock, lock_witness); 407414e7679SJohn Baldwin } 408238510fcSJason Evans 409238510fcSJason Evans return (rval); 410238510fcSJason Evans } 411238510fcSJason Evans 412238510fcSJason Evans /* 413b40ce416SJulian Elischer * Signal a condition variable, wakes up one waiting thread. Will also wakeup 414238510fcSJason Evans * the swapper if the process is not in memory, so that it can bring the 415b40ce416SJulian Elischer * sleeping process in. Note that this may also result in additional threads 416238510fcSJason Evans * being made runnable. Should be called with the same mutex as was passed to 417238510fcSJason Evans * cv_wait held. 418238510fcSJason Evans */ 419238510fcSJason Evans void 420238510fcSJason Evans cv_signal(struct cv *cvp) 421238510fcSJason Evans { 422da7bbd2cSJohn Baldwin int wakeup_swapper; 423238510fcSJason Evans 424da7bbd2cSJohn Baldwin wakeup_swapper = 0; 4252ff0e645SJohn Baldwin sleepq_lock(cvp); 4269000d57dSJohn Baldwin if (cvp->cv_waiters > 0) { 4279000d57dSJohn Baldwin cvp->cv_waiters--; 428da7bbd2cSJohn Baldwin wakeup_swapper = sleepq_signal(cvp, SLEEPQ_CONDVAR, 0, 0); 429d72e80f0SJeff Roberson } 4302ff0e645SJohn Baldwin sleepq_release(cvp); 431da7bbd2cSJohn Baldwin if (wakeup_swapper) 432da7bbd2cSJohn Baldwin kick_proc0(); 4339000d57dSJohn Baldwin } 434238510fcSJason Evans 435238510fcSJason Evans /* 436b40ce416SJulian Elischer * Broadcast a signal to a condition variable. Wakes up all waiting threads. 437238510fcSJason Evans * Should be called with the same mutex as was passed to cv_wait held. 438238510fcSJason Evans */ 439238510fcSJason Evans void 440512824f8SSeigo Tanimura cv_broadcastpri(struct cv *cvp, int pri) 441238510fcSJason Evans { 442da7bbd2cSJohn Baldwin int wakeup_swapper; 443da7bbd2cSJohn Baldwin 444c5aa6b58SJeff Roberson /* 445c5aa6b58SJeff Roberson * XXX sleepq_broadcast pri argument changed from -1 meaning 446c5aa6b58SJeff Roberson * no pri to 0 meaning no pri. 447c5aa6b58SJeff Roberson */ 448da7bbd2cSJohn Baldwin wakeup_swapper = 0; 449c5aa6b58SJeff Roberson if (pri == -1) 450c5aa6b58SJeff Roberson pri = 0; 4512ff0e645SJohn Baldwin sleepq_lock(cvp); 4529000d57dSJohn Baldwin if (cvp->cv_waiters > 0) { 4539000d57dSJohn Baldwin cvp->cv_waiters = 0; 454da7bbd2cSJohn Baldwin wakeup_swapper = sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0); 455c5aa6b58SJeff Roberson } 4562ff0e645SJohn Baldwin sleepq_release(cvp); 457da7bbd2cSJohn Baldwin if (wakeup_swapper) 458da7bbd2cSJohn Baldwin kick_proc0(); 4599000d57dSJohn Baldwin } 460