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; 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 8044f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 8144f3b092SJohn Baldwin sleepq_release(cvp); 8244f3b092SJohn Baldwin KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__)); 8344f3b092SJohn Baldwin #endif 84238510fcSJason Evans } 85238510fcSJason Evans 86238510fcSJason Evans /* 87b40ce416SJulian Elischer * Wait on a condition variable. The current thread is placed on the condition 88238510fcSJason Evans * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 89b40ce416SJulian Elischer * condition variable will resume the thread. The mutex is released before 90238510fcSJason Evans * sleeping and will be held on return. It is recommended that the mutex be 91238510fcSJason Evans * held when cv_signal or cv_broadcast are called. 92238510fcSJason Evans */ 93238510fcSJason Evans void 94238510fcSJason Evans cv_wait(struct cv *cvp, struct mtx *mp) 95238510fcSJason Evans { 9644f3b092SJohn Baldwin struct sleepqueue *sq; 97b40ce416SJulian Elischer struct thread *td; 98238510fcSJason Evans WITNESS_SAVE_DECL(mp); 99238510fcSJason Evans 100b40ce416SJulian Elischer td = curthread; 101238510fcSJason Evans #ifdef KTRACE 1029ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 1039ba7fe1bSJohn Baldwin ktrcsw(1, 0); 104238510fcSJason Evans #endif 105b40ce416SJulian Elischer CV_ASSERT(cvp, mp, td); 10626306795SJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 10726306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 10819284646SJohn Baldwin WITNESS_SAVE(&mp->mtx_object, mp); 109238510fcSJason Evans 11044f3b092SJohn Baldwin if (cold || panicstr) { 111238510fcSJason Evans /* 112fe799533SAndrew Gallatin * During autoconfiguration, just give interrupts 113fe799533SAndrew Gallatin * a chance, then just return. Don't run any other 114fe799533SAndrew Gallatin * thread or panic below, in case this is the idle 115fe799533SAndrew Gallatin * process and already asleep. 116238510fcSJason Evans */ 117238510fcSJason Evans return; 118238510fcSJason Evans } 1194bc37205SJeffrey Hsu 12044f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 121238510fcSJason Evans 122c86b6ff5SJohn Baldwin DROP_GIANT(); 123c86b6ff5SJohn Baldwin mtx_unlock(mp); 124238510fcSJason Evans 12544f3b092SJohn Baldwin sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 12644f3b092SJohn Baldwin sleepq_wait(cvp); 127238510fcSJason Evans 128238510fcSJason Evans #ifdef KTRACE 1299ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 1309ba7fe1bSJohn Baldwin ktrcsw(0, 0); 131238510fcSJason Evans #endif 132238510fcSJason Evans PICKUP_GIANT(); 1339ed346baSBosko Milekic mtx_lock(mp); 13419284646SJohn Baldwin WITNESS_RESTORE(&mp->mtx_object, mp); 135238510fcSJason Evans } 136238510fcSJason Evans 137238510fcSJason Evans /* 138238510fcSJason Evans * Wait on a condition variable, allowing interruption by signals. Return 0 if 139b40ce416SJulian Elischer * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 140238510fcSJason Evans * a signal was caught. If ERESTART is returned the system call should be 141238510fcSJason Evans * restarted if possible. 142238510fcSJason Evans */ 143238510fcSJason Evans int 144238510fcSJason Evans cv_wait_sig(struct cv *cvp, struct mtx *mp) 145238510fcSJason Evans { 14644f3b092SJohn Baldwin struct sleepqueue *sq; 147b40ce416SJulian Elischer struct thread *td; 14866f769feSPeter Wemm struct proc *p; 14944f3b092SJohn Baldwin int rval, sig; 150238510fcSJason Evans WITNESS_SAVE_DECL(mp); 151238510fcSJason Evans 152b40ce416SJulian Elischer td = curthread; 1539ef3a985SJohn Baldwin p = td->td_proc; 154238510fcSJason Evans rval = 0; 155238510fcSJason Evans #ifdef KTRACE 1569ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 1579ba7fe1bSJohn Baldwin ktrcsw(1, 0); 158238510fcSJason Evans #endif 159b40ce416SJulian Elischer CV_ASSERT(cvp, mp, td); 16026306795SJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 16126306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 16219284646SJohn Baldwin WITNESS_SAVE(&mp->mtx_object, mp); 163238510fcSJason Evans 164238510fcSJason Evans if (cold || panicstr) { 165238510fcSJason Evans /* 166238510fcSJason Evans * After a panic, or during autoconfiguration, just give 167238510fcSJason Evans * interrupts a chance, then just return; don't run any other 168238510fcSJason Evans * procs or panic below, in case this is the idle process and 169238510fcSJason Evans * already asleep. 170238510fcSJason Evans */ 171238510fcSJason Evans return 0; 172238510fcSJason Evans } 1734bc37205SJeffrey Hsu 17444f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 1754bc37205SJeffrey Hsu 17644f3b092SJohn Baldwin /* XXX: Missing the threading checks from msleep! */ 177238510fcSJason Evans 178c86b6ff5SJohn Baldwin DROP_GIANT(); 179c86b6ff5SJohn Baldwin mtx_unlock(mp); 180238510fcSJason Evans 18144f3b092SJohn Baldwin sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 18244f3b092SJohn Baldwin sig = sleepq_catch_signals(cvp); 18344f3b092SJohn Baldwin /* 18444f3b092SJohn Baldwin * XXX: Missing magic return value handling for no signal 18544f3b092SJohn Baldwin * caught but thread woken up during check. 18644f3b092SJohn Baldwin */ 18744f3b092SJohn Baldwin rval = sleepq_wait_sig(cvp); 18844f3b092SJohn Baldwin if (rval == 0) 18944f3b092SJohn Baldwin rval = sleepq_calc_signal_retval(sig); 190238510fcSJason Evans 19144f3b092SJohn Baldwin /* XXX: Part of missing threading checks? */ 1929ef3a985SJohn Baldwin PROC_LOCK(p); 193e602ba25SJulian Elischer if (p->p_flag & P_WEXIT) 194e602ba25SJulian Elischer rval = EINTR; 19553862173SJohn Baldwin PROC_UNLOCK(p); 196238510fcSJason Evans 197238510fcSJason Evans #ifdef KTRACE 1989ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 1999ba7fe1bSJohn Baldwin ktrcsw(0, 0); 200238510fcSJason Evans #endif 2019ba7fe1bSJohn Baldwin PICKUP_GIANT(); 2029ed346baSBosko Milekic mtx_lock(mp); 20319284646SJohn Baldwin WITNESS_RESTORE(&mp->mtx_object, mp); 204238510fcSJason Evans 205238510fcSJason Evans return (rval); 206238510fcSJason Evans } 207238510fcSJason Evans 208238510fcSJason Evans /* 209238510fcSJason Evans * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 210238510fcSJason Evans * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 211238510fcSJason Evans * expires. 212238510fcSJason Evans */ 213238510fcSJason Evans int 214238510fcSJason Evans cv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 215238510fcSJason Evans { 21644f3b092SJohn Baldwin struct sleepqueue *sq; 217b40ce416SJulian Elischer struct thread *td; 218238510fcSJason Evans int rval; 219238510fcSJason Evans WITNESS_SAVE_DECL(mp); 220238510fcSJason Evans 221b40ce416SJulian Elischer td = curthread; 222238510fcSJason Evans rval = 0; 223238510fcSJason Evans #ifdef KTRACE 2249ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 2259ba7fe1bSJohn Baldwin ktrcsw(1, 0); 226238510fcSJason Evans #endif 227b40ce416SJulian Elischer CV_ASSERT(cvp, mp, td); 22826306795SJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 22926306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 23019284646SJohn Baldwin WITNESS_SAVE(&mp->mtx_object, mp); 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 236b40ce416SJulian Elischer * thread or panic below, in case this is the idle process and 237238510fcSJason Evans * already asleep. 238238510fcSJason Evans */ 239238510fcSJason Evans return 0; 240238510fcSJason Evans } 2414bc37205SJeffrey Hsu 24244f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 243238510fcSJason Evans 244c86b6ff5SJohn Baldwin DROP_GIANT(); 245c86b6ff5SJohn Baldwin mtx_unlock(mp); 246238510fcSJason Evans 24744f3b092SJohn Baldwin sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 24844f3b092SJohn Baldwin sleepq_set_timeout(sq, cvp, timo); 24944f3b092SJohn Baldwin rval = sleepq_timedwait(cvp, 0); 250238510fcSJason Evans 251238510fcSJason Evans #ifdef KTRACE 2529ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 2539ba7fe1bSJohn Baldwin ktrcsw(0, 0); 254238510fcSJason Evans #endif 255238510fcSJason Evans PICKUP_GIANT(); 2569ed346baSBosko Milekic mtx_lock(mp); 25719284646SJohn Baldwin WITNESS_RESTORE(&mp->mtx_object, mp); 258238510fcSJason Evans 259238510fcSJason Evans return (rval); 260238510fcSJason Evans } 261238510fcSJason Evans 262238510fcSJason Evans /* 263238510fcSJason Evans * Wait on a condition variable for at most timo/hz seconds, allowing 264b40ce416SJulian Elischer * interruption by signals. Returns 0 if the thread was resumed by cv_signal 265238510fcSJason Evans * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 266238510fcSJason Evans * a signal was caught. 267238510fcSJason Evans */ 268238510fcSJason Evans int 269238510fcSJason Evans cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 270238510fcSJason Evans { 27144f3b092SJohn Baldwin struct sleepqueue *sq; 272b40ce416SJulian Elischer struct thread *td; 2739ef3a985SJohn Baldwin struct proc *p; 274238510fcSJason Evans int rval; 275238510fcSJason Evans int sig; 276238510fcSJason Evans WITNESS_SAVE_DECL(mp); 277238510fcSJason Evans 278b40ce416SJulian Elischer td = curthread; 2799ef3a985SJohn Baldwin p = td->td_proc; 280238510fcSJason Evans rval = 0; 281238510fcSJason Evans #ifdef KTRACE 2829ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 2839ba7fe1bSJohn Baldwin ktrcsw(1, 0); 284238510fcSJason Evans #endif 285b40ce416SJulian Elischer CV_ASSERT(cvp, mp, td); 28626306795SJohn Baldwin WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 28726306795SJohn Baldwin "Waiting on \"%s\"", cvp->cv_description); 28819284646SJohn Baldwin WITNESS_SAVE(&mp->mtx_object, mp); 289238510fcSJason Evans 290238510fcSJason Evans if (cold || panicstr) { 291238510fcSJason Evans /* 292238510fcSJason Evans * After a panic, or during autoconfiguration, just give 293238510fcSJason Evans * interrupts a chance, then just return; don't run any other 294b40ce416SJulian Elischer * thread or panic below, in case this is the idle process and 295238510fcSJason Evans * already asleep. 296238510fcSJason Evans */ 297238510fcSJason Evans return 0; 298238510fcSJason Evans } 2994bc37205SJeffrey Hsu 30044f3b092SJohn Baldwin sq = sleepq_lookup(cvp); 301238510fcSJason Evans 302c86b6ff5SJohn Baldwin DROP_GIANT(); 303c86b6ff5SJohn Baldwin mtx_unlock(mp); 304238510fcSJason Evans 30544f3b092SJohn Baldwin sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 30644f3b092SJohn Baldwin sleepq_set_timeout(sq, cvp, timo); 30744f3b092SJohn Baldwin sig = sleepq_catch_signals(cvp); 30891a4536fSJohn Baldwin /* 30944f3b092SJohn Baldwin * XXX: Missing magic return value handling for no signal 31044f3b092SJohn Baldwin * caught but thread woken up during check. 31191a4536fSJohn Baldwin */ 31244f3b092SJohn Baldwin rval = sleepq_timedwait_sig(cvp, sig != 0); 31344f3b092SJohn Baldwin if (rval == 0) 31444f3b092SJohn Baldwin rval = sleepq_calc_signal_retval(sig); 315238510fcSJason Evans 31644f3b092SJohn Baldwin /* XXX: Part of missing threading checks? */ 3179ef3a985SJohn Baldwin PROC_LOCK(p); 318e602ba25SJulian Elischer if (p->p_flag & P_WEXIT) 319e602ba25SJulian Elischer rval = EINTR; 32053862173SJohn Baldwin PROC_UNLOCK(p); 321e602ba25SJulian Elischer 322238510fcSJason Evans #ifdef KTRACE 3239ba7fe1bSJohn Baldwin if (KTRPOINT(td, KTR_CSW)) 3249ba7fe1bSJohn Baldwin ktrcsw(0, 0); 325238510fcSJason Evans #endif 3269ba7fe1bSJohn Baldwin PICKUP_GIANT(); 3279ed346baSBosko Milekic mtx_lock(mp); 32819284646SJohn Baldwin WITNESS_RESTORE(&mp->mtx_object, mp); 329238510fcSJason Evans 330238510fcSJason Evans return (rval); 331238510fcSJason Evans } 332238510fcSJason Evans 333238510fcSJason Evans /* 334b40ce416SJulian Elischer * Signal a condition variable, wakes up one waiting thread. Will also wakeup 335238510fcSJason Evans * the swapper if the process is not in memory, so that it can bring the 336b40ce416SJulian Elischer * sleeping process in. Note that this may also result in additional threads 337238510fcSJason Evans * being made runnable. Should be called with the same mutex as was passed to 338238510fcSJason Evans * cv_wait held. 339238510fcSJason Evans */ 340238510fcSJason Evans void 341238510fcSJason Evans cv_signal(struct cv *cvp) 342238510fcSJason Evans { 343238510fcSJason Evans 34444f3b092SJohn Baldwin sleepq_signal(cvp, SLEEPQ_CONDVAR, -1); 345238510fcSJason Evans } 346238510fcSJason Evans 347238510fcSJason Evans /* 348b40ce416SJulian Elischer * Broadcast a signal to a condition variable. Wakes up all waiting threads. 349238510fcSJason Evans * Should be called with the same mutex as was passed to cv_wait held. 350238510fcSJason Evans */ 351238510fcSJason Evans void 352512824f8SSeigo Tanimura cv_broadcastpri(struct cv *cvp, int pri) 353238510fcSJason Evans { 354238510fcSJason Evans 35544f3b092SJohn Baldwin sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri); 356512824f8SSeigo Tanimura } 357