kern_condvar.c revision 153321
171088Sjasone/*- 271088Sjasone * Copyright (c) 2000 Jake Burkholder <jake@freebsd.org>. 371088Sjasone * All rights reserved. 471088Sjasone * 571088Sjasone * Redistribution and use in source and binary forms, with or without 671088Sjasone * modification, are permitted provided that the following conditions 771088Sjasone * are met: 871088Sjasone * 1. Redistributions of source code must retain the above copyright 971088Sjasone * notice, this list of conditions and the following disclaimer. 1071088Sjasone * 2. Redistributions in binary form must reproduce the above copyright 1171088Sjasone * notice, this list of conditions and the following disclaimer in the 1271088Sjasone * documentation and/or other materials provided with the distribution. 1371088Sjasone * 1471088Sjasone * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1571088Sjasone * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1671088Sjasone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1771088Sjasone * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1871088Sjasone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1971088Sjasone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2071088Sjasone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2171088Sjasone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2271088Sjasone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2371088Sjasone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2471088Sjasone * SUCH DAMAGE. 2571088Sjasone */ 2671088Sjasone 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_condvar.c 153321 2005-12-12 00:02:22Z rodrigc $"); 29116182Sobrien 3071088Sjasone#include "opt_ktrace.h" 3171088Sjasone 3271088Sjasone#include <sys/param.h> 3371088Sjasone#include <sys/systm.h> 3476166Smarkm#include <sys/lock.h> 3576166Smarkm#include <sys/mutex.h> 3671088Sjasone#include <sys/proc.h> 3771088Sjasone#include <sys/kernel.h> 3871088Sjasone#include <sys/ktr.h> 3971088Sjasone#include <sys/condvar.h> 40109862Sjeff#include <sys/sched.h> 4171088Sjasone#include <sys/signalvar.h> 42126326Sjhb#include <sys/sleepqueue.h> 4371088Sjasone#include <sys/resourcevar.h> 4471088Sjasone#ifdef KTRACE 4571088Sjasone#include <sys/uio.h> 4671088Sjasone#include <sys/ktrace.h> 4771088Sjasone#endif 4871088Sjasone 4971088Sjasone/* 5071088Sjasone * Common sanity checks for cv_wait* functions. 5171088Sjasone */ 5283366Sjulian#define CV_ASSERT(cvp, mp, td) do { \ 5387594Sobrien KASSERT((td) != NULL, ("%s: curthread NULL", __func__)); \ 54103216Sjulian KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__)); \ 5587594Sobrien KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__)); \ 5687594Sobrien KASSERT((mp) != NULL, ("%s: mp NULL", __func__)); \ 5771088Sjasone mtx_assert((mp), MA_OWNED | MA_NOTRECURSED); \ 5871088Sjasone} while (0) 5971088Sjasone 6071088Sjasone/* 6171088Sjasone * Initialize a condition variable. Must be called before use. 6271088Sjasone */ 6371088Sjasonevoid 6471088Sjasonecv_init(struct cv *cvp, const char *desc) 6571088Sjasone{ 6671088Sjasone 6771088Sjasone cvp->cv_description = desc; 68127954Sjhb cvp->cv_waiters = 0; 6971088Sjasone} 7071088Sjasone 7171088Sjasone/* 7271088Sjasone * Destroy a condition variable. The condition variable must be re-initialized 7371088Sjasone * in order to be re-used. 7471088Sjasone */ 7571088Sjasonevoid 7671088Sjasonecv_destroy(struct cv *cvp) 7771088Sjasone{ 78126326Sjhb#ifdef INVARIANTS 79136445Sjhb struct sleepqueue *sq; 8071088Sjasone 81136445Sjhb sleepq_lock(cvp); 82126326Sjhb sq = sleepq_lookup(cvp); 83126326Sjhb sleepq_release(cvp); 84126326Sjhb KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__)); 85126326Sjhb#endif 8671088Sjasone} 8771088Sjasone 8871088Sjasone/* 8983366Sjulian * Wait on a condition variable. The current thread is placed on the condition 9071088Sjasone * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 9183366Sjulian * condition variable will resume the thread. The mutex is released before 9271088Sjasone * sleeping and will be held on return. It is recommended that the mutex be 9371088Sjasone * held when cv_signal or cv_broadcast are called. 9471088Sjasone */ 9571088Sjasonevoid 9671088Sjasonecv_wait(struct cv *cvp, struct mtx *mp) 9771088Sjasone{ 9871088Sjasone WITNESS_SAVE_DECL(mp); 9971088Sjasone 100153321Srodrigc WITNESS_SAVE(&mp->mtx_object, mp); 101153321Srodrigc 102153321Srodrigc if (cold || panicstr) { 103153321Srodrigc /* 104153321Srodrigc * During autoconfiguration, just give interrupts 105153321Srodrigc * a chance, then just return. Don't run any other 106153321Srodrigc * thread or panic below, in case this is the idle 107153321Srodrigc * process and already asleep. 108153321Srodrigc */ 109153321Srodrigc return; 110153321Srodrigc } 111153321Srodrigc 112153321Srodrigc cv_wait_unlock(cvp, mp); 113153321Srodrigc mtx_lock(mp); 114153321Srodrigc WITNESS_RESTORE(&mp->mtx_object, mp); 115153321Srodrigc} 116153321Srodrigc 117153321Srodrigc/* 118153321Srodrigc * Wait on a condition variable. This function differs from cv_wait by 119153321Srodrigc * not aquiring the mutex after condition variable was signaled. 120153321Srodrigc */ 121153321Srodrigcvoid 122153321Srodrigccv_wait_unlock(struct cv *cvp, struct mtx *mp) 123153321Srodrigc{ 124153321Srodrigc struct thread *td; 125153321Srodrigc 12683366Sjulian td = curthread; 12771088Sjasone#ifdef KTRACE 12897995Sjhb if (KTRPOINT(td, KTR_CSW)) 12997995Sjhb ktrcsw(1, 0); 13071088Sjasone#endif 13183366Sjulian CV_ASSERT(cvp, mp, td); 132111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 133111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 13471088Sjasone 135126326Sjhb if (cold || panicstr) { 13671088Sjasone /* 137100209Sgallatin * During autoconfiguration, just give interrupts 138100209Sgallatin * a chance, then just return. Don't run any other 139100209Sgallatin * thread or panic below, in case this is the idle 140100209Sgallatin * process and already asleep. 14171088Sjasone */ 142153321Srodrigc mtx_unlock(mp); 14371088Sjasone return; 14471088Sjasone } 14595322Shsu 146136445Sjhb sleepq_lock(cvp); 14795322Shsu 148127954Sjhb cvp->cv_waiters++; 14988900Sjhb DROP_GIANT(); 15088900Sjhb mtx_unlock(mp); 15171088Sjasone 152136445Sjhb sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 153126326Sjhb sleepq_wait(cvp); 15471088Sjasone 15571088Sjasone PICKUP_GIANT(); 15671088Sjasone} 15771088Sjasone 15871088Sjasone/* 15971088Sjasone * Wait on a condition variable, allowing interruption by signals. Return 0 if 16083366Sjulian * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 16171088Sjasone * a signal was caught. If ERESTART is returned the system call should be 16271088Sjasone * restarted if possible. 16371088Sjasone */ 16471088Sjasoneint 16571088Sjasonecv_wait_sig(struct cv *cvp, struct mtx *mp) 16671088Sjasone{ 16783366Sjulian struct thread *td; 16883658Speter struct proc *p; 169126326Sjhb int rval, sig; 17071088Sjasone WITNESS_SAVE_DECL(mp); 17171088Sjasone 17283366Sjulian td = curthread; 17383650Sjhb p = td->td_proc; 17471088Sjasone#ifdef KTRACE 17597995Sjhb if (KTRPOINT(td, KTR_CSW)) 17697995Sjhb ktrcsw(1, 0); 17771088Sjasone#endif 17883366Sjulian CV_ASSERT(cvp, mp, td); 179111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 180111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 18174912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 18271088Sjasone 18371088Sjasone if (cold || panicstr) { 18471088Sjasone /* 18571088Sjasone * After a panic, or during autoconfiguration, just give 18671088Sjasone * interrupts a chance, then just return; don't run any other 18771088Sjasone * procs or panic below, in case this is the idle process and 18871088Sjasone * already asleep. 18971088Sjasone */ 190133440Sjhb return (0); 19171088Sjasone } 19295322Shsu 193136445Sjhb sleepq_lock(cvp); 19495322Shsu 195133440Sjhb /* 196133440Sjhb * Don't bother sleeping if we are exiting and not the exiting 197133440Sjhb * thread or if our thread is marked as interrupted. 198133440Sjhb */ 199133440Sjhb mtx_lock_spin(&sched_lock); 200134013Sjhb rval = thread_sleep_check(td); 201134013Sjhb mtx_unlock_spin(&sched_lock); 202134013Sjhb if (rval != 0) { 203134013Sjhb sleepq_release(cvp); 204134013Sjhb return (rval); 205133440Sjhb } 20671088Sjasone 207127954Sjhb cvp->cv_waiters++; 20888900Sjhb DROP_GIANT(); 20988900Sjhb mtx_unlock(mp); 21071088Sjasone 211136445Sjhb sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR | 212134013Sjhb SLEEPQ_INTERRUPTIBLE); 213126326Sjhb sig = sleepq_catch_signals(cvp); 214134013Sjhb rval = sleepq_wait_sig(cvp); 215126326Sjhb if (rval == 0) 216126326Sjhb rval = sleepq_calc_signal_retval(sig); 21771088Sjasone 21871088Sjasone#ifdef KTRACE 21997995Sjhb if (KTRPOINT(td, KTR_CSW)) 22097995Sjhb ktrcsw(0, 0); 22171088Sjasone#endif 22297995Sjhb PICKUP_GIANT(); 22372200Sbmilekic mtx_lock(mp); 22474912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 22571088Sjasone 22671088Sjasone return (rval); 22771088Sjasone} 22871088Sjasone 22971088Sjasone/* 23071088Sjasone * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 23171088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 23271088Sjasone * expires. 23371088Sjasone */ 23471088Sjasoneint 23571088Sjasonecv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 23671088Sjasone{ 23783366Sjulian struct thread *td; 23871088Sjasone int rval; 23971088Sjasone WITNESS_SAVE_DECL(mp); 24071088Sjasone 24183366Sjulian td = curthread; 24271088Sjasone rval = 0; 24371088Sjasone#ifdef KTRACE 24497995Sjhb if (KTRPOINT(td, KTR_CSW)) 24597995Sjhb ktrcsw(1, 0); 24671088Sjasone#endif 24783366Sjulian CV_ASSERT(cvp, mp, td); 248111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 249111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 25074912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 25171088Sjasone 25271088Sjasone if (cold || panicstr) { 25371088Sjasone /* 25471088Sjasone * After a panic, or during autoconfiguration, just give 25571088Sjasone * interrupts a chance, then just return; don't run any other 25683366Sjulian * thread or panic below, in case this is the idle process and 25771088Sjasone * already asleep. 25871088Sjasone */ 25971088Sjasone return 0; 26071088Sjasone } 26195322Shsu 262136445Sjhb sleepq_lock(cvp); 26395322Shsu 264127954Sjhb cvp->cv_waiters++; 26588900Sjhb DROP_GIANT(); 26688900Sjhb mtx_unlock(mp); 26771088Sjasone 268136445Sjhb sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 269126885Sjhb sleepq_set_timeout(cvp, timo); 270131249Sjhb rval = sleepq_timedwait(cvp); 27171088Sjasone 27271088Sjasone#ifdef KTRACE 27397995Sjhb if (KTRPOINT(td, KTR_CSW)) 27497995Sjhb ktrcsw(0, 0); 27571088Sjasone#endif 27671088Sjasone PICKUP_GIANT(); 27772200Sbmilekic mtx_lock(mp); 27874912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 27971088Sjasone 28071088Sjasone return (rval); 28171088Sjasone} 28271088Sjasone 28371088Sjasone/* 28471088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing 28583366Sjulian * interruption by signals. Returns 0 if the thread was resumed by cv_signal 28671088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 28771088Sjasone * a signal was caught. 28871088Sjasone */ 28971088Sjasoneint 29071088Sjasonecv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 29171088Sjasone{ 29283366Sjulian struct thread *td; 29383650Sjhb struct proc *p; 29471088Sjasone int rval; 29571088Sjasone int sig; 29671088Sjasone WITNESS_SAVE_DECL(mp); 29771088Sjasone 29883366Sjulian td = curthread; 29983650Sjhb p = td->td_proc; 30071088Sjasone rval = 0; 30171088Sjasone#ifdef KTRACE 30297995Sjhb if (KTRPOINT(td, KTR_CSW)) 30397995Sjhb ktrcsw(1, 0); 30471088Sjasone#endif 30583366Sjulian CV_ASSERT(cvp, mp, td); 306111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 307111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 30874912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 30971088Sjasone 31071088Sjasone if (cold || panicstr) { 31171088Sjasone /* 31271088Sjasone * After a panic, or during autoconfiguration, just give 31371088Sjasone * interrupts a chance, then just return; don't run any other 31483366Sjulian * thread or panic below, in case this is the idle process and 31571088Sjasone * already asleep. 31671088Sjasone */ 31771088Sjasone return 0; 31871088Sjasone } 31995322Shsu 320136445Sjhb sleepq_lock(cvp); 32195322Shsu 322133440Sjhb /* 323133440Sjhb * Don't bother sleeping if we are exiting and not the exiting 324133440Sjhb * thread or if our thread is marked as interrupted. 325133440Sjhb */ 326133440Sjhb mtx_lock_spin(&sched_lock); 327134013Sjhb rval = thread_sleep_check(td); 328134013Sjhb mtx_unlock_spin(&sched_lock); 329134013Sjhb if (rval != 0) { 330134013Sjhb sleepq_release(cvp); 331134013Sjhb return (rval); 332133440Sjhb } 333133440Sjhb 334127954Sjhb cvp->cv_waiters++; 33588900Sjhb DROP_GIANT(); 33688900Sjhb mtx_unlock(mp); 33771088Sjasone 338136445Sjhb sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR | 339134013Sjhb SLEEPQ_INTERRUPTIBLE); 340126885Sjhb sleepq_set_timeout(cvp, timo); 341126326Sjhb sig = sleepq_catch_signals(cvp); 342134013Sjhb rval = sleepq_timedwait_sig(cvp, sig != 0); 343126326Sjhb if (rval == 0) 344126326Sjhb rval = sleepq_calc_signal_retval(sig); 34571088Sjasone 34671088Sjasone#ifdef KTRACE 34797995Sjhb if (KTRPOINT(td, KTR_CSW)) 34897995Sjhb ktrcsw(0, 0); 34971088Sjasone#endif 35097995Sjhb PICKUP_GIANT(); 35172200Sbmilekic mtx_lock(mp); 35274912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 35371088Sjasone 35471088Sjasone return (rval); 35571088Sjasone} 35671088Sjasone 35771088Sjasone/* 35883366Sjulian * Signal a condition variable, wakes up one waiting thread. Will also wakeup 35971088Sjasone * the swapper if the process is not in memory, so that it can bring the 36083366Sjulian * sleeping process in. Note that this may also result in additional threads 36171088Sjasone * being made runnable. Should be called with the same mutex as was passed to 36271088Sjasone * cv_wait held. 36371088Sjasone */ 36471088Sjasonevoid 36571088Sjasonecv_signal(struct cv *cvp) 36671088Sjasone{ 36771088Sjasone 368136445Sjhb sleepq_lock(cvp); 369127954Sjhb if (cvp->cv_waiters > 0) { 370127954Sjhb cvp->cv_waiters--; 371127954Sjhb sleepq_signal(cvp, SLEEPQ_CONDVAR, -1); 372136445Sjhb } else 373136445Sjhb sleepq_release(cvp); 37471088Sjasone} 37571088Sjasone 37671088Sjasone/* 37783366Sjulian * Broadcast a signal to a condition variable. Wakes up all waiting threads. 37871088Sjasone * Should be called with the same mutex as was passed to cv_wait held. 37971088Sjasone */ 38071088Sjasonevoid 381122352Stanimuracv_broadcastpri(struct cv *cvp, int pri) 38271088Sjasone{ 38371088Sjasone 384136445Sjhb sleepq_lock(cvp); 385127954Sjhb if (cvp->cv_waiters > 0) { 386127954Sjhb cvp->cv_waiters = 0; 387127954Sjhb sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri); 388136445Sjhb } else 389136445Sjhb sleepq_release(cvp); 39071088Sjasone} 391