kern_condvar.c revision 131249
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 131249 2004-06-28 18:57:06Z 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; 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 79126326Sjhb struct sleepqueue *sq; 8071088Sjasone 81126326Sjhb sq = sleepq_lookup(cvp); 82126326Sjhb sleepq_release(cvp); 83126326Sjhb KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__)); 84126326Sjhb#endif 8571088Sjasone} 8671088Sjasone 8771088Sjasone/* 8883366Sjulian * Wait on a condition variable. The current thread is placed on the condition 8971088Sjasone * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 9083366Sjulian * condition variable will resume the thread. The mutex is released before 9171088Sjasone * sleeping and will be held on return. It is recommended that the mutex be 9271088Sjasone * held when cv_signal or cv_broadcast are called. 9371088Sjasone */ 9471088Sjasonevoid 9571088Sjasonecv_wait(struct cv *cvp, struct mtx *mp) 9671088Sjasone{ 97126326Sjhb struct sleepqueue *sq; 9883366Sjulian struct thread *td; 9971088Sjasone WITNESS_SAVE_DECL(mp); 10071088Sjasone 10183366Sjulian td = curthread; 10271088Sjasone#ifdef KTRACE 10397995Sjhb if (KTRPOINT(td, KTR_CSW)) 10497995Sjhb ktrcsw(1, 0); 10571088Sjasone#endif 10683366Sjulian CV_ASSERT(cvp, mp, td); 107111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 108111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 10974912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 11071088Sjasone 111126326Sjhb if (cold || panicstr) { 11271088Sjasone /* 113100209Sgallatin * During autoconfiguration, just give interrupts 114100209Sgallatin * a chance, then just return. Don't run any other 115100209Sgallatin * thread or panic below, in case this is the idle 116100209Sgallatin * process and already asleep. 11771088Sjasone */ 11871088Sjasone return; 11971088Sjasone } 12095322Shsu 121126326Sjhb sq = sleepq_lookup(cvp); 12295322Shsu 123127954Sjhb cvp->cv_waiters++; 12488900Sjhb DROP_GIANT(); 12588900Sjhb mtx_unlock(mp); 12671088Sjasone 127126326Sjhb sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 128126326Sjhb sleepq_wait(cvp); 12971088Sjasone 13071088Sjasone#ifdef KTRACE 13197995Sjhb if (KTRPOINT(td, KTR_CSW)) 13297995Sjhb ktrcsw(0, 0); 13371088Sjasone#endif 13471088Sjasone PICKUP_GIANT(); 13572200Sbmilekic mtx_lock(mp); 13674912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 13771088Sjasone} 13871088Sjasone 13971088Sjasone/* 14071088Sjasone * Wait on a condition variable, allowing interruption by signals. Return 0 if 14183366Sjulian * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 14271088Sjasone * a signal was caught. If ERESTART is returned the system call should be 14371088Sjasone * restarted if possible. 14471088Sjasone */ 14571088Sjasoneint 14671088Sjasonecv_wait_sig(struct cv *cvp, struct mtx *mp) 14771088Sjasone{ 148126326Sjhb struct sleepqueue *sq; 14983366Sjulian struct thread *td; 15083658Speter struct proc *p; 151126326Sjhb int rval, sig; 15271088Sjasone WITNESS_SAVE_DECL(mp); 15371088Sjasone 15483366Sjulian td = curthread; 15583650Sjhb p = td->td_proc; 15671088Sjasone rval = 0; 15771088Sjasone#ifdef KTRACE 15897995Sjhb if (KTRPOINT(td, KTR_CSW)) 15997995Sjhb ktrcsw(1, 0); 16071088Sjasone#endif 16183366Sjulian CV_ASSERT(cvp, mp, td); 162111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 163111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 16474912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 16571088Sjasone 16671088Sjasone if (cold || panicstr) { 16771088Sjasone /* 16871088Sjasone * After a panic, or during autoconfiguration, just give 16971088Sjasone * interrupts a chance, then just return; don't run any other 17071088Sjasone * procs or panic below, in case this is the idle process and 17171088Sjasone * already asleep. 17271088Sjasone */ 17371088Sjasone return 0; 17471088Sjasone } 17595322Shsu 176126326Sjhb sq = sleepq_lookup(cvp); 17795322Shsu 178126326Sjhb /* XXX: Missing the threading checks from msleep! */ 17971088Sjasone 180127954Sjhb cvp->cv_waiters++; 18188900Sjhb DROP_GIANT(); 18288900Sjhb mtx_unlock(mp); 18371088Sjasone 184126326Sjhb sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 185126326Sjhb sig = sleepq_catch_signals(cvp); 186126326Sjhb /* 187126326Sjhb * XXX: Missing magic return value handling for no signal 188126326Sjhb * caught but thread woken up during check. 189126326Sjhb */ 190126326Sjhb rval = sleepq_wait_sig(cvp); 191126326Sjhb if (rval == 0) 192126326Sjhb rval = sleepq_calc_signal_retval(sig); 19371088Sjasone 194126326Sjhb /* XXX: Part of missing threading checks? */ 19583650Sjhb PROC_LOCK(p); 19699072Sjulian if (p->p_flag & P_WEXIT) 19799072Sjulian rval = EINTR; 198113625Sjhb PROC_UNLOCK(p); 19971088Sjasone 20071088Sjasone#ifdef KTRACE 20197995Sjhb if (KTRPOINT(td, KTR_CSW)) 20297995Sjhb ktrcsw(0, 0); 20371088Sjasone#endif 20497995Sjhb PICKUP_GIANT(); 20572200Sbmilekic mtx_lock(mp); 20674912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 20771088Sjasone 20871088Sjasone return (rval); 20971088Sjasone} 21071088Sjasone 21171088Sjasone/* 21271088Sjasone * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 21371088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 21471088Sjasone * expires. 21571088Sjasone */ 21671088Sjasoneint 21771088Sjasonecv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 21871088Sjasone{ 219126326Sjhb struct sleepqueue *sq; 22083366Sjulian struct thread *td; 22171088Sjasone int rval; 22271088Sjasone WITNESS_SAVE_DECL(mp); 22371088Sjasone 22483366Sjulian td = curthread; 22571088Sjasone rval = 0; 22671088Sjasone#ifdef KTRACE 22797995Sjhb if (KTRPOINT(td, KTR_CSW)) 22897995Sjhb ktrcsw(1, 0); 22971088Sjasone#endif 23083366Sjulian CV_ASSERT(cvp, mp, td); 231111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 232111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 23374912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 23471088Sjasone 23571088Sjasone if (cold || panicstr) { 23671088Sjasone /* 23771088Sjasone * After a panic, or during autoconfiguration, just give 23871088Sjasone * interrupts a chance, then just return; don't run any other 23983366Sjulian * thread or panic below, in case this is the idle process and 24071088Sjasone * already asleep. 24171088Sjasone */ 24271088Sjasone return 0; 24371088Sjasone } 24495322Shsu 245126326Sjhb sq = sleepq_lookup(cvp); 24695322Shsu 247127954Sjhb cvp->cv_waiters++; 24888900Sjhb DROP_GIANT(); 24988900Sjhb mtx_unlock(mp); 25071088Sjasone 251126326Sjhb sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 252126885Sjhb sleepq_set_timeout(cvp, timo); 253131249Sjhb rval = sleepq_timedwait(cvp); 25471088Sjasone 25571088Sjasone#ifdef KTRACE 25697995Sjhb if (KTRPOINT(td, KTR_CSW)) 25797995Sjhb ktrcsw(0, 0); 25871088Sjasone#endif 25971088Sjasone PICKUP_GIANT(); 26072200Sbmilekic mtx_lock(mp); 26174912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 26271088Sjasone 26371088Sjasone return (rval); 26471088Sjasone} 26571088Sjasone 26671088Sjasone/* 26771088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing 26883366Sjulian * interruption by signals. Returns 0 if the thread was resumed by cv_signal 26971088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 27071088Sjasone * a signal was caught. 27171088Sjasone */ 27271088Sjasoneint 27371088Sjasonecv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 27471088Sjasone{ 275126326Sjhb struct sleepqueue *sq; 27683366Sjulian struct thread *td; 27783650Sjhb struct proc *p; 27871088Sjasone int rval; 27971088Sjasone int sig; 28071088Sjasone WITNESS_SAVE_DECL(mp); 28171088Sjasone 28283366Sjulian td = curthread; 28383650Sjhb p = td->td_proc; 28471088Sjasone rval = 0; 28571088Sjasone#ifdef KTRACE 28697995Sjhb if (KTRPOINT(td, KTR_CSW)) 28797995Sjhb ktrcsw(1, 0); 28871088Sjasone#endif 28983366Sjulian CV_ASSERT(cvp, mp, td); 290111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 291111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 29274912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 29371088Sjasone 29471088Sjasone if (cold || panicstr) { 29571088Sjasone /* 29671088Sjasone * After a panic, or during autoconfiguration, just give 29771088Sjasone * interrupts a chance, then just return; don't run any other 29883366Sjulian * thread or panic below, in case this is the idle process and 29971088Sjasone * already asleep. 30071088Sjasone */ 30171088Sjasone return 0; 30271088Sjasone } 30395322Shsu 304126326Sjhb sq = sleepq_lookup(cvp); 30595322Shsu 306127954Sjhb cvp->cv_waiters++; 30788900Sjhb DROP_GIANT(); 30888900Sjhb mtx_unlock(mp); 30971088Sjasone 310126326Sjhb sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR); 311126885Sjhb sleepq_set_timeout(cvp, timo); 312126326Sjhb sig = sleepq_catch_signals(cvp); 313126326Sjhb /* 314126326Sjhb * XXX: Missing magic return value handling for no signal 315126326Sjhb * caught but thread woken up during check. 316126326Sjhb */ 317126326Sjhb rval = sleepq_timedwait_sig(cvp, sig != 0); 318126326Sjhb if (rval == 0) 319126326Sjhb rval = sleepq_calc_signal_retval(sig); 32071088Sjasone 321126326Sjhb /* XXX: Part of missing threading checks? */ 32283650Sjhb PROC_LOCK(p); 32399072Sjulian if (p->p_flag & P_WEXIT) 32499072Sjulian rval = EINTR; 325113625Sjhb PROC_UNLOCK(p); 32699072Sjulian 32771088Sjasone#ifdef KTRACE 32897995Sjhb if (KTRPOINT(td, KTR_CSW)) 32997995Sjhb ktrcsw(0, 0); 33071088Sjasone#endif 33197995Sjhb PICKUP_GIANT(); 33272200Sbmilekic mtx_lock(mp); 33374912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 33471088Sjasone 33571088Sjasone return (rval); 33671088Sjasone} 33771088Sjasone 33871088Sjasone/* 33983366Sjulian * Signal a condition variable, wakes up one waiting thread. Will also wakeup 34071088Sjasone * the swapper if the process is not in memory, so that it can bring the 34183366Sjulian * sleeping process in. Note that this may also result in additional threads 34271088Sjasone * being made runnable. Should be called with the same mutex as was passed to 34371088Sjasone * cv_wait held. 34471088Sjasone */ 34571088Sjasonevoid 34671088Sjasonecv_signal(struct cv *cvp) 34771088Sjasone{ 34871088Sjasone 349127954Sjhb if (cvp->cv_waiters > 0) { 350127954Sjhb cvp->cv_waiters--; 351127954Sjhb sleepq_signal(cvp, SLEEPQ_CONDVAR, -1); 352127954Sjhb } 35371088Sjasone} 35471088Sjasone 35571088Sjasone/* 35683366Sjulian * Broadcast a signal to a condition variable. Wakes up all waiting threads. 35771088Sjasone * Should be called with the same mutex as was passed to cv_wait held. 35871088Sjasone */ 35971088Sjasonevoid 360122352Stanimuracv_broadcastpri(struct cv *cvp, int pri) 36171088Sjasone{ 36271088Sjasone 363127954Sjhb if (cvp->cv_waiters > 0) { 364127954Sjhb cvp->cv_waiters = 0; 365127954Sjhb sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri); 366127954Sjhb } 36771088Sjasone} 368