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 */ 52b40ce416SJulian Elischer #define CV_ASSERT(cvp, mp, 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__)); \ 56a48740b6SDavid E. O'Brien KASSERT((mp) != NULL, ("%s: mp NULL", __func__)); \ 57238510fcSJason Evans mtx_assert((mp), MA_OWNED | MA_NOTRECURSED); \ 58238510fcSJason Evans } while (0) 59238510fcSJason Evans 60238510fcSJason Evans /* 61238510fcSJason Evans * Initialize a condition variable. Must be called before use. 62238510fcSJason Evans */ 63238510fcSJason Evans void 64238510fcSJason Evans cv_init(struct cv *cvp, const char *desc) 65238510fcSJason Evans { 66238510fcSJason Evans 67238510fcSJason Evans cvp->cv_description = desc; 689000d57dSJohn Baldwin cvp->cv_waiters = 0; 69238510fcSJason Evans } 70238510fcSJason Evans 71238510fcSJason Evans /* 72238510fcSJason Evans * Destroy a condition variable. The condition variable must be re-initialized 73238510fcSJason Evans * in order to be re-used. 74238510fcSJason Evans */ 75238510fcSJason Evans void 76238510fcSJason Evans cv_destroy(struct cv *cvp) 77238510fcSJason Evans { 7844f3b092SJohn Baldwin #ifdef INVARIANTS 7944f3b092SJohn Baldwin struct sleepqueue *sq; 80238510fcSJason Evans 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 95238510fcSJason Evans cv_wait(struct cv *cvp, struct mtx *mp) 96238510fcSJason Evans { 9744f3b092SJohn Baldwin struct sleepqueue *sq; 98b40ce416SJulian Elischer struct thread *td; 99238510fcSJason Evans WITNESS_SAVE_DECL(mp); 100238510fcSJason Evans 101b40ce416SJulian Elischer td = curthread; 102238510fcSJason Evans #ifdef KTRACE 1039ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 1049ba7fe1bSJohn Baldwin ktrcsw(1, 0); 105238510fcSJason Evans #endif 106b40ce416SJulian Elischer CV_ASSERT(cvp, mp, td); 10726306795SJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 10826306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 10919284646SJohn Baldwin WITNESS_SAVE(&mp->mtx_object, mp); 110238510fcSJason Evans 11144f3b092SJohn Baldwin if (cold || panicstr) { 112238510fcSJason Evans /* 113fe799533SAndrew Gallatin * During autoconfiguration, just give interrupts 114fe799533SAndrew Gallatin * a chance, then just return. Don't run any other 115fe799533SAndrew Gallatin * thread or panic below, in case this is the idle 116fe799533SAndrew Gallatin * process and already asleep. 117238510fcSJason Evans */ 118238510fcSJason Evans return; 119238510fcSJason Evans } 1204bc37205SJeffrey Hsu 12144f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 122238510fcSJason Evans 1239000d57dSJohn Baldwin cvp->cv_waiters++; 124c86b6ff5SJohn Baldwin DROP_GIANT(); 125c86b6ff5SJohn Baldwin mtx_unlock(mp); 126238510fcSJason Evans 12744f3b092SJohn Baldwin sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 12844f3b092SJohn Baldwin sleepq_wait(cvp); 129238510fcSJason Evans 130238510fcSJason Evans #ifdef KTRACE 1319ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 1329ba7fe1bSJohn Baldwin ktrcsw(0, 0); 133238510fcSJason Evans #endif 134238510fcSJason Evans PICKUP_GIANT(); 1359ed346baSBosko Milekic mtx_lock(mp); 13619284646SJohn Baldwin WITNESS_RESTORE(&mp->mtx_object, mp); 137238510fcSJason Evans } 138238510fcSJason Evans 139238510fcSJason Evans /* 140238510fcSJason Evans * Wait on a condition variable, allowing interruption by signals. Return 0 if 141b40ce416SJulian Elischer * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 142238510fcSJason Evans * a signal was caught. If ERESTART is returned the system call should be 143238510fcSJason Evans * restarted if possible. 144238510fcSJason Evans */ 145238510fcSJason Evans int 146238510fcSJason Evans cv_wait_sig(struct cv *cvp, struct mtx *mp) 147238510fcSJason Evans { 14844f3b092SJohn Baldwin struct sleepqueue *sq; 149b40ce416SJulian Elischer struct thread *td; 15066f769feSPeter Wemm struct proc *p; 15144f3b092SJohn Baldwin int rval, sig; 152238510fcSJason Evans WITNESS_SAVE_DECL(mp); 153238510fcSJason Evans 154b40ce416SJulian Elischer td = curthread; 1559ef3a985SJohn Baldwin p = td->td_proc; 156238510fcSJason Evans rval = 0; 157238510fcSJason Evans #ifdef KTRACE 1589ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 1599ba7fe1bSJohn Baldwin ktrcsw(1, 0); 160238510fcSJason Evans #endif 161b40ce416SJulian Elischer CV_ASSERT(cvp, mp, td); 16226306795SJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 16326306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 16419284646SJohn Baldwin WITNESS_SAVE(&mp->mtx_object, mp); 165238510fcSJason Evans 166238510fcSJason Evans if (cold || panicstr) { 167238510fcSJason Evans /* 168238510fcSJason Evans * After a panic, or during autoconfiguration, just give 169238510fcSJason Evans * interrupts a chance, then just return; don't run any other 170238510fcSJason Evans * procs or panic below, in case this is the idle process and 171238510fcSJason Evans * already asleep. 172238510fcSJason Evans */ 173238510fcSJason Evans return 0; 174238510fcSJason Evans } 1754bc37205SJeffrey Hsu 17644f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 1774bc37205SJeffrey Hsu 17844f3b092SJohn Baldwin /* XXX: Missing the threading checks from msleep! */ 179238510fcSJason Evans 1809000d57dSJohn Baldwin cvp->cv_waiters++; 181c86b6ff5SJohn Baldwin DROP_GIANT(); 182c86b6ff5SJohn Baldwin mtx_unlock(mp); 183238510fcSJason Evans 18444f3b092SJohn Baldwin sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 18544f3b092SJohn Baldwin sig = sleepq_catch_signals(cvp); 18644f3b092SJohn Baldwin /* 18744f3b092SJohn Baldwin * XXX: Missing magic return value handling for no signal 18844f3b092SJohn Baldwin * caught but thread woken up during check. 18944f3b092SJohn Baldwin */ 19044f3b092SJohn Baldwin rval = sleepq_wait_sig(cvp); 19144f3b092SJohn Baldwin if (rval == 0) 19244f3b092SJohn Baldwin rval = sleepq_calc_signal_retval(sig); 193238510fcSJason Evans 19444f3b092SJohn Baldwin /* XXX: Part of missing threading checks? */ 1959ef3a985SJohn Baldwin PROC_LOCK(p); 196e602ba25SJulian Elischer if (p->p_flag & P_WEXIT) 197e602ba25SJulian Elischer rval = EINTR; 19853862173SJohn Baldwin PROC_UNLOCK(p); 199238510fcSJason Evans 200238510fcSJason Evans #ifdef KTRACE 2019ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 2029ba7fe1bSJohn Baldwin ktrcsw(0, 0); 203238510fcSJason Evans #endif 2049ba7fe1bSJohn Baldwin PICKUP_GIANT(); 2059ed346baSBosko Milekic mtx_lock(mp); 20619284646SJohn Baldwin WITNESS_RESTORE(&mp->mtx_object, mp); 207238510fcSJason Evans 208238510fcSJason Evans return (rval); 209238510fcSJason Evans } 210238510fcSJason Evans 211238510fcSJason Evans /* 212238510fcSJason Evans * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 213238510fcSJason Evans * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 214238510fcSJason Evans * expires. 215238510fcSJason Evans */ 216238510fcSJason Evans int 217238510fcSJason Evans cv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 218238510fcSJason Evans { 21944f3b092SJohn Baldwin struct sleepqueue *sq; 220b40ce416SJulian Elischer struct thread *td; 221238510fcSJason Evans int rval; 222238510fcSJason Evans WITNESS_SAVE_DECL(mp); 223238510fcSJason Evans 224b40ce416SJulian Elischer td = curthread; 225238510fcSJason Evans rval = 0; 226238510fcSJason Evans #ifdef KTRACE 2279ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 2289ba7fe1bSJohn Baldwin ktrcsw(1, 0); 229238510fcSJason Evans #endif 230b40ce416SJulian Elischer CV_ASSERT(cvp, mp, td); 23126306795SJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 23226306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 23319284646SJohn Baldwin WITNESS_SAVE(&mp->mtx_object, mp); 234238510fcSJason Evans 235238510fcSJason Evans if (cold || panicstr) { 236238510fcSJason Evans /* 237238510fcSJason Evans * After a panic, or during autoconfiguration, just give 238238510fcSJason Evans * interrupts a chance, then just return; don't run any other 239b40ce416SJulian Elischer * thread or panic below, in case this is the idle process and 240238510fcSJason Evans * already asleep. 241238510fcSJason Evans */ 242238510fcSJason Evans return 0; 243238510fcSJason Evans } 2444bc37205SJeffrey Hsu 24544f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 246238510fcSJason Evans 2479000d57dSJohn Baldwin cvp->cv_waiters++; 248c86b6ff5SJohn Baldwin DROP_GIANT(); 249c86b6ff5SJohn Baldwin mtx_unlock(mp); 250238510fcSJason Evans 25144f3b092SJohn Baldwin sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 2521ed3e44fSJohn Baldwin sleepq_set_timeout(cvp, timo); 25344f3b092SJohn Baldwin rval = sleepq_timedwait(cvp, 0); 254238510fcSJason Evans 255238510fcSJason Evans #ifdef KTRACE 2569ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 2579ba7fe1bSJohn Baldwin ktrcsw(0, 0); 258238510fcSJason Evans #endif 259238510fcSJason Evans PICKUP_GIANT(); 2609ed346baSBosko Milekic mtx_lock(mp); 26119284646SJohn Baldwin WITNESS_RESTORE(&mp->mtx_object, mp); 262238510fcSJason Evans 263238510fcSJason Evans return (rval); 264238510fcSJason Evans } 265238510fcSJason Evans 266238510fcSJason Evans /* 267238510fcSJason Evans * Wait on a condition variable for at most timo/hz seconds, allowing 268b40ce416SJulian Elischer * interruption by signals. Returns 0 if the thread was resumed by cv_signal 269238510fcSJason Evans * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 270238510fcSJason Evans * a signal was caught. 271238510fcSJason Evans */ 272238510fcSJason Evans int 273238510fcSJason Evans cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 274238510fcSJason Evans { 27544f3b092SJohn Baldwin struct sleepqueue *sq; 276b40ce416SJulian Elischer struct thread *td; 2779ef3a985SJohn Baldwin struct proc *p; 278238510fcSJason Evans int rval; 279238510fcSJason Evans int sig; 280238510fcSJason Evans WITNESS_SAVE_DECL(mp); 281238510fcSJason Evans 282b40ce416SJulian Elischer td = curthread; 2839ef3a985SJohn Baldwin p = td->td_proc; 284238510fcSJason Evans rval = 0; 285238510fcSJason Evans #ifdef KTRACE 2869ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 2879ba7fe1bSJohn Baldwin ktrcsw(1, 0); 288238510fcSJason Evans #endif 289b40ce416SJulian Elischer CV_ASSERT(cvp, mp, td); 29026306795SJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 29126306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 29219284646SJohn Baldwin WITNESS_SAVE(&mp->mtx_object, mp); 293238510fcSJason Evans 294238510fcSJason Evans if (cold || panicstr) { 295238510fcSJason Evans /* 296238510fcSJason Evans * After a panic, or during autoconfiguration, just give 297238510fcSJason Evans * interrupts a chance, then just return; don't run any other 298b40ce416SJulian Elischer * thread or panic below, in case this is the idle process and 299238510fcSJason Evans * already asleep. 300238510fcSJason Evans */ 301238510fcSJason Evans return 0; 302238510fcSJason Evans } 3034bc37205SJeffrey Hsu 30444f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 305238510fcSJason Evans 3069000d57dSJohn Baldwin cvp->cv_waiters++; 307c86b6ff5SJohn Baldwin DROP_GIANT(); 308c86b6ff5SJohn Baldwin mtx_unlock(mp); 309238510fcSJason Evans 31044f3b092SJohn Baldwin sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 3111ed3e44fSJohn Baldwin sleepq_set_timeout(cvp, timo); 31244f3b092SJohn Baldwin sig = sleepq_catch_signals(cvp); 31391a4536fSJohn Baldwin /* 31444f3b092SJohn Baldwin * XXX: Missing magic return value handling for no signal 31544f3b092SJohn Baldwin * caught but thread woken up during check. 31691a4536fSJohn Baldwin */ 31744f3b092SJohn Baldwin rval = sleepq_timedwait_sig(cvp, sig != 0); 31844f3b092SJohn Baldwin if (rval == 0) 31944f3b092SJohn Baldwin rval = sleepq_calc_signal_retval(sig); 320238510fcSJason Evans 32144f3b092SJohn Baldwin /* XXX: Part of missing threading checks? */ 3229ef3a985SJohn Baldwin PROC_LOCK(p); 323e602ba25SJulian Elischer if (p->p_flag & P_WEXIT) 324e602ba25SJulian Elischer rval = EINTR; 32553862173SJohn Baldwin PROC_UNLOCK(p); 326e602ba25SJulian Elischer 327238510fcSJason Evans #ifdef KTRACE 3289ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 3299ba7fe1bSJohn Baldwin ktrcsw(0, 0); 330238510fcSJason Evans #endif 3319ba7fe1bSJohn Baldwin PICKUP_GIANT(); 3329ed346baSBosko Milekic mtx_lock(mp); 33319284646SJohn Baldwin WITNESS_RESTORE(&mp->mtx_object, mp); 334238510fcSJason Evans 335238510fcSJason Evans return (rval); 336238510fcSJason Evans } 337238510fcSJason Evans 338238510fcSJason Evans /* 339b40ce416SJulian Elischer * Signal a condition variable, wakes up one waiting thread. Will also wakeup 340238510fcSJason Evans * the swapper if the process is not in memory, so that it can bring the 341b40ce416SJulian Elischer * sleeping process in. Note that this may also result in additional threads 342238510fcSJason Evans * being made runnable. Should be called with the same mutex as was passed to 343238510fcSJason Evans * cv_wait held. 344238510fcSJason Evans */ 345238510fcSJason Evans void 346238510fcSJason Evans cv_signal(struct cv *cvp) 347238510fcSJason Evans { 348238510fcSJason Evans 3499000d57dSJohn Baldwin if (cvp->cv_waiters > 0) { 3509000d57dSJohn Baldwin cvp->cv_waiters--; 35144f3b092SJohn Baldwin sleepq_signal(cvp, SLEEPQ_CONDVAR, -1); 352238510fcSJason Evans } 3539000d57dSJohn Baldwin } 354238510fcSJason Evans 355238510fcSJason Evans /* 356b40ce416SJulian Elischer * Broadcast a signal to a condition variable. Wakes up all waiting threads. 357238510fcSJason Evans * Should be called with the same mutex as was passed to cv_wait held. 358238510fcSJason Evans */ 359238510fcSJason Evans void 360512824f8SSeigo Tanimura cv_broadcastpri(struct cv *cvp, int pri) 361238510fcSJason Evans { 362238510fcSJason Evans 3639000d57dSJohn Baldwin if (cvp->cv_waiters > 0) { 3649000d57dSJohn Baldwin cvp->cv_waiters = 0; 36544f3b092SJohn Baldwin sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri); 366512824f8SSeigo Tanimura } 3679000d57dSJohn Baldwin } 368