kern_condvar.c revision 167789
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 167789 2007-03-21 22:22:13Z 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 */ 52167789Sjhb#define CV_ASSERT(cvp, lock, 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__)); \ 56167789Sjhb KASSERT((lock) != NULL, ("%s: lock NULL", __func__)); \ 5771088Sjasone} while (0) 5871088Sjasone 5971088Sjasone/* 6071088Sjasone * Initialize a condition variable. Must be called before use. 6171088Sjasone */ 6271088Sjasonevoid 6371088Sjasonecv_init(struct cv *cvp, const char *desc) 6471088Sjasone{ 6571088Sjasone 6671088Sjasone cvp->cv_description = desc; 67127954Sjhb cvp->cv_waiters = 0; 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 78136445Sjhb struct sleepqueue *sq; 7971088Sjasone 80136445Sjhb sleepq_lock(cvp); 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 95167789Sjhb_cv_wait(struct cv *cvp, struct lock_object *lock) 9671088Sjasone{ 97167789Sjhb WITNESS_SAVE_DECL(lock_witness); 98167789Sjhb struct lock_class *class; 99167786Sjhb struct thread *td; 100167789Sjhb int lock_state; 10171088Sjasone 102167786Sjhb td = curthread; 103167786Sjhb#ifdef KTRACE 104167786Sjhb if (KTRPOINT(td, KTR_CSW)) 105167786Sjhb ktrcsw(1, 0); 106167786Sjhb#endif 107167789Sjhb CV_ASSERT(cvp, lock, td); 108167789Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 109167786Sjhb "Waiting on \"%s\"", cvp->cv_description); 110167789Sjhb WITNESS_SAVE(lock, lock_witness); 111167789Sjhb class = LOCK_CLASS(lock); 112153321Srodrigc 113153321Srodrigc if (cold || panicstr) { 114153321Srodrigc /* 115153321Srodrigc * During autoconfiguration, just give interrupts 116153321Srodrigc * a chance, then just return. Don't run any other 117153321Srodrigc * thread or panic below, in case this is the idle 118153321Srodrigc * process and already asleep. 119153321Srodrigc */ 120153321Srodrigc return; 121153321Srodrigc } 122153321Srodrigc 123167786Sjhb sleepq_lock(cvp); 124167786Sjhb 125167786Sjhb cvp->cv_waiters++; 126167786Sjhb DROP_GIANT(); 127167789Sjhb lock_state = class->lc_unlock(lock); 128167786Sjhb 129167789Sjhb sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); 130167786Sjhb sleepq_wait(cvp); 131167786Sjhb 132167786Sjhb#ifdef KTRACE 133167786Sjhb if (KTRPOINT(td, KTR_CSW)) 134167786Sjhb ktrcsw(0, 0); 135167786Sjhb#endif 136167786Sjhb PICKUP_GIANT(); 137167789Sjhb class->lc_lock(lock, lock_state); 138167789Sjhb WITNESS_RESTORE(lock, lock_witness); 139153321Srodrigc} 140153321Srodrigc 141153321Srodrigc/* 142153321Srodrigc * Wait on a condition variable. This function differs from cv_wait by 143153321Srodrigc * not aquiring the mutex after condition variable was signaled. 144153321Srodrigc */ 145153321Srodrigcvoid 146167789Sjhb_cv_wait_unlock(struct cv *cvp, struct lock_object *lock) 147153321Srodrigc{ 148167789Sjhb struct lock_class *class; 149153321Srodrigc struct thread *td; 150153321Srodrigc 15183366Sjulian td = curthread; 15271088Sjasone#ifdef KTRACE 15397995Sjhb if (KTRPOINT(td, KTR_CSW)) 15497995Sjhb ktrcsw(1, 0); 15571088Sjasone#endif 156167789Sjhb CV_ASSERT(cvp, lock, td); 157167789Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 158111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 159167789Sjhb class = LOCK_CLASS(lock); 16071088Sjasone 161126326Sjhb if (cold || panicstr) { 16271088Sjasone /* 163100209Sgallatin * During autoconfiguration, just give interrupts 164100209Sgallatin * a chance, then just return. Don't run any other 165100209Sgallatin * thread or panic below, in case this is the idle 166100209Sgallatin * process and already asleep. 16771088Sjasone */ 168167789Sjhb class->lc_unlock(lock); 16971088Sjasone return; 17071088Sjasone } 17195322Shsu 172136445Sjhb sleepq_lock(cvp); 17395322Shsu 174127954Sjhb cvp->cv_waiters++; 17588900Sjhb DROP_GIANT(); 176167789Sjhb class->lc_unlock(lock); 17771088Sjasone 178167789Sjhb sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); 179126326Sjhb sleepq_wait(cvp); 18071088Sjasone 181167786Sjhb#ifdef KTRACE 182167786Sjhb if (KTRPOINT(td, KTR_CSW)) 183167786Sjhb ktrcsw(0, 0); 184167786Sjhb#endif 18571088Sjasone PICKUP_GIANT(); 18671088Sjasone} 18771088Sjasone 18871088Sjasone/* 18971088Sjasone * Wait on a condition variable, allowing interruption by signals. Return 0 if 19083366Sjulian * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 19171088Sjasone * a signal was caught. If ERESTART is returned the system call should be 19271088Sjasone * restarted if possible. 19371088Sjasone */ 19471088Sjasoneint 195167789Sjhb_cv_wait_sig(struct cv *cvp, struct lock_object *lock) 19671088Sjasone{ 197167789Sjhb WITNESS_SAVE_DECL(lock_witness); 198167789Sjhb struct lock_class *class; 19983366Sjulian struct thread *td; 20083658Speter struct proc *p; 201167789Sjhb int lock_state, rval; 20271088Sjasone 20383366Sjulian td = curthread; 20483650Sjhb p = td->td_proc; 20571088Sjasone#ifdef KTRACE 20697995Sjhb if (KTRPOINT(td, KTR_CSW)) 20797995Sjhb ktrcsw(1, 0); 20871088Sjasone#endif 209167789Sjhb CV_ASSERT(cvp, lock, td); 210167789Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 211111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 212167789Sjhb WITNESS_SAVE(lock, lock_witness); 213167789Sjhb class = LOCK_CLASS(lock); 21471088Sjasone 21571088Sjasone if (cold || panicstr) { 21671088Sjasone /* 21771088Sjasone * After a panic, or during autoconfiguration, just give 21871088Sjasone * interrupts a chance, then just return; don't run any other 21971088Sjasone * procs or panic below, in case this is the idle process and 22071088Sjasone * already asleep. 22171088Sjasone */ 222133440Sjhb return (0); 22371088Sjasone } 22495322Shsu 225136445Sjhb sleepq_lock(cvp); 22695322Shsu 227127954Sjhb cvp->cv_waiters++; 22888900Sjhb DROP_GIANT(); 229167789Sjhb lock_state = class->lc_unlock(lock); 23071088Sjasone 231167789Sjhb sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | 232165272Skmacy SLEEPQ_INTERRUPTIBLE, 0); 233134013Sjhb rval = sleepq_wait_sig(cvp); 23471088Sjasone 23571088Sjasone#ifdef KTRACE 23697995Sjhb if (KTRPOINT(td, KTR_CSW)) 23797995Sjhb ktrcsw(0, 0); 23871088Sjasone#endif 23997995Sjhb PICKUP_GIANT(); 240167789Sjhb class->lc_lock(lock, lock_state); 241167789Sjhb WITNESS_RESTORE(lock, lock_witness); 24271088Sjasone 24371088Sjasone return (rval); 24471088Sjasone} 24571088Sjasone 24671088Sjasone/* 24771088Sjasone * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 24871088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 24971088Sjasone * expires. 25071088Sjasone */ 25171088Sjasoneint 252167789Sjhb_cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo) 25371088Sjasone{ 254167789Sjhb WITNESS_SAVE_DECL(lock_witness); 255167789Sjhb struct lock_class *class; 25683366Sjulian struct thread *td; 257167789Sjhb int lock_state, rval; 25871088Sjasone 25983366Sjulian td = curthread; 26071088Sjasone rval = 0; 26171088Sjasone#ifdef KTRACE 26297995Sjhb if (KTRPOINT(td, KTR_CSW)) 26397995Sjhb ktrcsw(1, 0); 26471088Sjasone#endif 265167789Sjhb CV_ASSERT(cvp, lock, td); 266167789Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 267111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 268167789Sjhb WITNESS_SAVE(lock, lock_witness); 269167789Sjhb class = LOCK_CLASS(lock); 27071088Sjasone 27171088Sjasone if (cold || panicstr) { 27271088Sjasone /* 27371088Sjasone * After a panic, or during autoconfiguration, just give 27471088Sjasone * interrupts a chance, then just return; don't run any other 27583366Sjulian * thread or panic below, in case this is the idle process and 27671088Sjasone * already asleep. 27771088Sjasone */ 27871088Sjasone return 0; 27971088Sjasone } 28095322Shsu 281136445Sjhb sleepq_lock(cvp); 28295322Shsu 283127954Sjhb cvp->cv_waiters++; 28488900Sjhb DROP_GIANT(); 285167789Sjhb lock_state = class->lc_unlock(lock); 28671088Sjasone 287167789Sjhb sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); 288126885Sjhb sleepq_set_timeout(cvp, timo); 289131249Sjhb rval = sleepq_timedwait(cvp); 29071088Sjasone 29171088Sjasone#ifdef KTRACE 29297995Sjhb if (KTRPOINT(td, KTR_CSW)) 29397995Sjhb ktrcsw(0, 0); 29471088Sjasone#endif 29571088Sjasone PICKUP_GIANT(); 296167789Sjhb class->lc_lock(lock, lock_state); 297167789Sjhb WITNESS_RESTORE(lock, lock_witness); 29871088Sjasone 29971088Sjasone return (rval); 30071088Sjasone} 30171088Sjasone 30271088Sjasone/* 30371088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing 30483366Sjulian * interruption by signals. Returns 0 if the thread was resumed by cv_signal 30571088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 30671088Sjasone * a signal was caught. 30771088Sjasone */ 30871088Sjasoneint 309167789Sjhb_cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo) 31071088Sjasone{ 311167789Sjhb WITNESS_SAVE_DECL(lock_witness); 312167789Sjhb struct lock_class *class; 31383366Sjulian struct thread *td; 31483650Sjhb struct proc *p; 315167789Sjhb int lock_state, rval; 31671088Sjasone 31783366Sjulian td = curthread; 31883650Sjhb p = td->td_proc; 31971088Sjasone rval = 0; 32071088Sjasone#ifdef KTRACE 32197995Sjhb if (KTRPOINT(td, KTR_CSW)) 32297995Sjhb ktrcsw(1, 0); 32371088Sjasone#endif 324167789Sjhb CV_ASSERT(cvp, lock, td); 325167789Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock, 326111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 327167789Sjhb WITNESS_SAVE(lock, lock_witness); 328167789Sjhb class = LOCK_CLASS(lock); 32971088Sjasone 33071088Sjasone if (cold || panicstr) { 33171088Sjasone /* 33271088Sjasone * After a panic, or during autoconfiguration, just give 33371088Sjasone * interrupts a chance, then just return; don't run any other 33483366Sjulian * thread or panic below, in case this is the idle process and 33571088Sjasone * already asleep. 33671088Sjasone */ 33771088Sjasone return 0; 33871088Sjasone } 33995322Shsu 340136445Sjhb sleepq_lock(cvp); 34195322Shsu 342127954Sjhb cvp->cv_waiters++; 34388900Sjhb DROP_GIANT(); 344167789Sjhb lock_state = class->lc_unlock(lock); 34571088Sjasone 346167789Sjhb sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | 347165272Skmacy SLEEPQ_INTERRUPTIBLE, 0); 348126885Sjhb sleepq_set_timeout(cvp, timo); 349155741Sdavidxu rval = sleepq_timedwait_sig(cvp); 35071088Sjasone 35171088Sjasone#ifdef KTRACE 35297995Sjhb if (KTRPOINT(td, KTR_CSW)) 35397995Sjhb ktrcsw(0, 0); 35471088Sjasone#endif 35597995Sjhb PICKUP_GIANT(); 356167789Sjhb class->lc_lock(lock, lock_state); 357167789Sjhb WITNESS_RESTORE(lock, lock_witness); 35871088Sjasone 35971088Sjasone return (rval); 36071088Sjasone} 36171088Sjasone 36271088Sjasone/* 36383366Sjulian * Signal a condition variable, wakes up one waiting thread. Will also wakeup 36471088Sjasone * the swapper if the process is not in memory, so that it can bring the 36583366Sjulian * sleeping process in. Note that this may also result in additional threads 36671088Sjasone * being made runnable. Should be called with the same mutex as was passed to 36771088Sjasone * cv_wait held. 36871088Sjasone */ 36971088Sjasonevoid 37071088Sjasonecv_signal(struct cv *cvp) 37171088Sjasone{ 37271088Sjasone 373136445Sjhb sleepq_lock(cvp); 374127954Sjhb if (cvp->cv_waiters > 0) { 375127954Sjhb cvp->cv_waiters--; 376165272Skmacy sleepq_signal(cvp, SLEEPQ_CONDVAR, -1, 0); 377136445Sjhb } else 378136445Sjhb sleepq_release(cvp); 37971088Sjasone} 38071088Sjasone 38171088Sjasone/* 38283366Sjulian * Broadcast a signal to a condition variable. Wakes up all waiting threads. 38371088Sjasone * Should be called with the same mutex as was passed to cv_wait held. 38471088Sjasone */ 38571088Sjasonevoid 386122352Stanimuracv_broadcastpri(struct cv *cvp, int pri) 38771088Sjasone{ 38871088Sjasone 389136445Sjhb sleepq_lock(cvp); 390127954Sjhb if (cvp->cv_waiters > 0) { 391127954Sjhb cvp->cv_waiters = 0; 392165272Skmacy sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0); 393136445Sjhb } else 394136445Sjhb sleepq_release(cvp); 39571088Sjasone} 396