kern_condvar.c revision 126885
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 126885 2004-03-12 19:06:18Z jhb $"); 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; 6871088Sjasone} 6971088Sjasone 7071088Sjasone/* 7171088Sjasone * Destroy a condition variable. The condition variable must be re-initialized 7271088Sjasone * in order to be re-used. 7371088Sjasone */ 7471088Sjasonevoid 7571088Sjasonecv_destroy(struct cv *cvp) 7671088Sjasone{ 77126326Sjhb#ifdef INVARIANTS 78126326Sjhb struct sleepqueue *sq; 7971088Sjasone 80126326Sjhb sq = sleepq_lookup(cvp); 81126326Sjhb sleepq_release(cvp); 82126326Sjhb KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__)); 83126326Sjhb#endif 8471088Sjasone} 8571088Sjasone 8671088Sjasone/* 8783366Sjulian * Wait on a condition variable. The current thread is placed on the condition 8871088Sjasone * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 8983366Sjulian * condition variable will resume the thread. The mutex is released before 9071088Sjasone * sleeping and will be held on return. It is recommended that the mutex be 9171088Sjasone * held when cv_signal or cv_broadcast are called. 9271088Sjasone */ 9371088Sjasonevoid 9471088Sjasonecv_wait(struct cv *cvp, struct mtx *mp) 9571088Sjasone{ 96126326Sjhb struct sleepqueue *sq; 9783366Sjulian struct thread *td; 9871088Sjasone WITNESS_SAVE_DECL(mp); 9971088Sjasone 10083366Sjulian td = curthread; 10171088Sjasone#ifdef KTRACE 10297995Sjhb if (KTRPOINT(td, KTR_CSW)) 10397995Sjhb ktrcsw(1, 0); 10471088Sjasone#endif 10583366Sjulian CV_ASSERT(cvp, mp, td); 106111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 107111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 10874912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 10971088Sjasone 110126326Sjhb if (cold || panicstr) { 11171088Sjasone /* 112100209Sgallatin * During autoconfiguration, just give interrupts 113100209Sgallatin * a chance, then just return. Don't run any other 114100209Sgallatin * thread or panic below, in case this is the idle 115100209Sgallatin * process and already asleep. 11671088Sjasone */ 11771088Sjasone return; 11871088Sjasone } 11995322Shsu 120126326Sjhb sq = sleepq_lookup(cvp); 12195322Shsu 12288900Sjhb DROP_GIANT(); 12388900Sjhb mtx_unlock(mp); 12471088Sjasone 125126326Sjhb sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 126126326Sjhb sleepq_wait(cvp); 12771088Sjasone 12871088Sjasone#ifdef KTRACE 12997995Sjhb if (KTRPOINT(td, KTR_CSW)) 13097995Sjhb ktrcsw(0, 0); 13171088Sjasone#endif 13271088Sjasone PICKUP_GIANT(); 13372200Sbmilekic mtx_lock(mp); 13474912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 13571088Sjasone} 13671088Sjasone 13771088Sjasone/* 13871088Sjasone * Wait on a condition variable, allowing interruption by signals. Return 0 if 13983366Sjulian * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 14071088Sjasone * a signal was caught. If ERESTART is returned the system call should be 14171088Sjasone * restarted if possible. 14271088Sjasone */ 14371088Sjasoneint 14471088Sjasonecv_wait_sig(struct cv *cvp, struct mtx *mp) 14571088Sjasone{ 146126326Sjhb struct sleepqueue *sq; 14783366Sjulian struct thread *td; 14883658Speter struct proc *p; 149126326Sjhb int rval, sig; 15071088Sjasone WITNESS_SAVE_DECL(mp); 15171088Sjasone 15283366Sjulian td = curthread; 15383650Sjhb p = td->td_proc; 15471088Sjasone rval = 0; 15571088Sjasone#ifdef KTRACE 15697995Sjhb if (KTRPOINT(td, KTR_CSW)) 15797995Sjhb ktrcsw(1, 0); 15871088Sjasone#endif 15983366Sjulian CV_ASSERT(cvp, mp, td); 160111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 161111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 16274912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 16371088Sjasone 16471088Sjasone if (cold || panicstr) { 16571088Sjasone /* 16671088Sjasone * After a panic, or during autoconfiguration, just give 16771088Sjasone * interrupts a chance, then just return; don't run any other 16871088Sjasone * procs or panic below, in case this is the idle process and 16971088Sjasone * already asleep. 17071088Sjasone */ 17171088Sjasone return 0; 17271088Sjasone } 17395322Shsu 174126326Sjhb sq = sleepq_lookup(cvp); 17595322Shsu 176126326Sjhb /* XXX: Missing the threading checks from msleep! */ 17771088Sjasone 17888900Sjhb DROP_GIANT(); 17988900Sjhb mtx_unlock(mp); 18071088Sjasone 181126326Sjhb sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 182126326Sjhb sig = sleepq_catch_signals(cvp); 183126326Sjhb /* 184126326Sjhb * XXX: Missing magic return value handling for no signal 185126326Sjhb * caught but thread woken up during check. 186126326Sjhb */ 187126326Sjhb rval = sleepq_wait_sig(cvp); 188126326Sjhb if (rval == 0) 189126326Sjhb rval = sleepq_calc_signal_retval(sig); 19071088Sjasone 191126326Sjhb /* XXX: Part of missing threading checks? */ 19283650Sjhb PROC_LOCK(p); 19399072Sjulian if (p->p_flag & P_WEXIT) 19499072Sjulian rval = EINTR; 195113625Sjhb PROC_UNLOCK(p); 19671088Sjasone 19771088Sjasone#ifdef KTRACE 19897995Sjhb if (KTRPOINT(td, KTR_CSW)) 19997995Sjhb ktrcsw(0, 0); 20071088Sjasone#endif 20197995Sjhb PICKUP_GIANT(); 20272200Sbmilekic mtx_lock(mp); 20374912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 20471088Sjasone 20571088Sjasone return (rval); 20671088Sjasone} 20771088Sjasone 20871088Sjasone/* 20971088Sjasone * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 21071088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 21171088Sjasone * expires. 21271088Sjasone */ 21371088Sjasoneint 21471088Sjasonecv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 21571088Sjasone{ 216126326Sjhb struct sleepqueue *sq; 21783366Sjulian struct thread *td; 21871088Sjasone int rval; 21971088Sjasone WITNESS_SAVE_DECL(mp); 22071088Sjasone 22183366Sjulian td = curthread; 22271088Sjasone rval = 0; 22371088Sjasone#ifdef KTRACE 22497995Sjhb if (KTRPOINT(td, KTR_CSW)) 22597995Sjhb ktrcsw(1, 0); 22671088Sjasone#endif 22783366Sjulian CV_ASSERT(cvp, mp, td); 228111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 229111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 23074912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 23171088Sjasone 23271088Sjasone if (cold || panicstr) { 23371088Sjasone /* 23471088Sjasone * After a panic, or during autoconfiguration, just give 23571088Sjasone * interrupts a chance, then just return; don't run any other 23683366Sjulian * thread or panic below, in case this is the idle process and 23771088Sjasone * already asleep. 23871088Sjasone */ 23971088Sjasone return 0; 24071088Sjasone } 24195322Shsu 242126326Sjhb sq = sleepq_lookup(cvp); 24395322Shsu 24488900Sjhb DROP_GIANT(); 24588900Sjhb mtx_unlock(mp); 24671088Sjasone 247126326Sjhb sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 248126885Sjhb sleepq_set_timeout(cvp, timo); 249126326Sjhb rval = sleepq_timedwait(cvp, 0); 25071088Sjasone 25171088Sjasone#ifdef KTRACE 25297995Sjhb if (KTRPOINT(td, KTR_CSW)) 25397995Sjhb ktrcsw(0, 0); 25471088Sjasone#endif 25571088Sjasone PICKUP_GIANT(); 25672200Sbmilekic mtx_lock(mp); 25774912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 25871088Sjasone 25971088Sjasone return (rval); 26071088Sjasone} 26171088Sjasone 26271088Sjasone/* 26371088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing 26483366Sjulian * interruption by signals. Returns 0 if the thread was resumed by cv_signal 26571088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 26671088Sjasone * a signal was caught. 26771088Sjasone */ 26871088Sjasoneint 26971088Sjasonecv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 27071088Sjasone{ 271126326Sjhb struct sleepqueue *sq; 27283366Sjulian struct thread *td; 27383650Sjhb struct proc *p; 27471088Sjasone int rval; 27571088Sjasone int sig; 27671088Sjasone WITNESS_SAVE_DECL(mp); 27771088Sjasone 27883366Sjulian td = curthread; 27983650Sjhb p = td->td_proc; 28071088Sjasone rval = 0; 28171088Sjasone#ifdef KTRACE 28297995Sjhb if (KTRPOINT(td, KTR_CSW)) 28397995Sjhb ktrcsw(1, 0); 28471088Sjasone#endif 28583366Sjulian CV_ASSERT(cvp, mp, td); 286111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 287111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 28874912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 28971088Sjasone 29071088Sjasone if (cold || panicstr) { 29171088Sjasone /* 29271088Sjasone * After a panic, or during autoconfiguration, just give 29371088Sjasone * interrupts a chance, then just return; don't run any other 29483366Sjulian * thread or panic below, in case this is the idle process and 29571088Sjasone * already asleep. 29671088Sjasone */ 29771088Sjasone return 0; 29871088Sjasone } 29995322Shsu 300126326Sjhb sq = sleepq_lookup(cvp); 30195322Shsu 30288900Sjhb DROP_GIANT(); 30388900Sjhb mtx_unlock(mp); 30471088Sjasone 305126326Sjhb sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 306126885Sjhb sleepq_set_timeout(cvp, timo); 307126326Sjhb sig = sleepq_catch_signals(cvp); 308126326Sjhb /* 309126326Sjhb * XXX: Missing magic return value handling for no signal 310126326Sjhb * caught but thread woken up during check. 311126326Sjhb */ 312126326Sjhb rval = sleepq_timedwait_sig(cvp, sig != 0); 313126326Sjhb if (rval == 0) 314126326Sjhb rval = sleepq_calc_signal_retval(sig); 31571088Sjasone 316126326Sjhb /* XXX: Part of missing threading checks? */ 31783650Sjhb PROC_LOCK(p); 31899072Sjulian if (p->p_flag & P_WEXIT) 31999072Sjulian rval = EINTR; 320113625Sjhb PROC_UNLOCK(p); 32199072Sjulian 32271088Sjasone#ifdef KTRACE 32397995Sjhb if (KTRPOINT(td, KTR_CSW)) 32497995Sjhb ktrcsw(0, 0); 32571088Sjasone#endif 32697995Sjhb PICKUP_GIANT(); 32772200Sbmilekic mtx_lock(mp); 32874912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 32971088Sjasone 33071088Sjasone return (rval); 33171088Sjasone} 33271088Sjasone 33371088Sjasone/* 33483366Sjulian * Signal a condition variable, wakes up one waiting thread. Will also wakeup 33571088Sjasone * the swapper if the process is not in memory, so that it can bring the 33683366Sjulian * sleeping process in. Note that this may also result in additional threads 33771088Sjasone * being made runnable. Should be called with the same mutex as was passed to 33871088Sjasone * cv_wait held. 33971088Sjasone */ 34071088Sjasonevoid 34171088Sjasonecv_signal(struct cv *cvp) 34271088Sjasone{ 34371088Sjasone 344126326Sjhb sleepq_signal(cvp, SLEEPQ_CONDVAR, -1); 34571088Sjasone} 34671088Sjasone 34771088Sjasone/* 34883366Sjulian * Broadcast a signal to a condition variable. Wakes up all waiting threads. 34971088Sjasone * Should be called with the same mutex as was passed to cv_wait held. 35071088Sjasone */ 35171088Sjasonevoid 352122352Stanimuracv_broadcastpri(struct cv *cvp, int pri) 35371088Sjasone{ 35471088Sjasone 355126326Sjhb sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri); 35671088Sjasone} 357