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