kern_condvar.c revision 111883
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 * $FreeBSD: head/sys/kern/kern_condvar.c 111883 2003-03-04 21:03:05Z jhb $ 2771088Sjasone */ 2871088Sjasone 2971088Sjasone#include "opt_ktrace.h" 3071088Sjasone 3171088Sjasone#include <sys/param.h> 3271088Sjasone#include <sys/systm.h> 3376166Smarkm#include <sys/lock.h> 3476166Smarkm#include <sys/mutex.h> 3571088Sjasone#include <sys/proc.h> 3671088Sjasone#include <sys/kernel.h> 3771088Sjasone#include <sys/ktr.h> 3871088Sjasone#include <sys/condvar.h> 39109862Sjeff#include <sys/sched.h> 4071088Sjasone#include <sys/signalvar.h> 4171088Sjasone#include <sys/resourcevar.h> 4271088Sjasone#ifdef KTRACE 4371088Sjasone#include <sys/uio.h> 4471088Sjasone#include <sys/ktrace.h> 4571088Sjasone#endif 4671088Sjasone 4771088Sjasone/* 4871088Sjasone * Common sanity checks for cv_wait* functions. 4971088Sjasone */ 5083366Sjulian#define CV_ASSERT(cvp, mp, td) do { \ 5187594Sobrien KASSERT((td) != NULL, ("%s: curthread NULL", __func__)); \ 52103216Sjulian KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__)); \ 5387594Sobrien KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__)); \ 5487594Sobrien KASSERT((mp) != NULL, ("%s: mp NULL", __func__)); \ 5571088Sjasone mtx_assert((mp), MA_OWNED | MA_NOTRECURSED); \ 5671088Sjasone} while (0) 5771088Sjasone 5893408Sdan#ifdef INVARIANTS 5971088Sjasone#define CV_WAIT_VALIDATE(cvp, mp) do { \ 6071088Sjasone if (TAILQ_EMPTY(&(cvp)->cv_waitq)) { \ 6171088Sjasone /* Only waiter. */ \ 6271088Sjasone (cvp)->cv_mtx = (mp); \ 6371088Sjasone } else { \ 6471088Sjasone /* \ 6571088Sjasone * Other waiter; assert that we're using the \ 6671088Sjasone * same mutex. \ 6771088Sjasone */ \ 6871088Sjasone KASSERT((cvp)->cv_mtx == (mp), \ 6987594Sobrien ("%s: Multiple mutexes", __func__)); \ 7071088Sjasone } \ 7171088Sjasone} while (0) 72103216Sjulian 7371088Sjasone#define CV_SIGNAL_VALIDATE(cvp) do { \ 7471088Sjasone if (!TAILQ_EMPTY(&(cvp)->cv_waitq)) { \ 7571088Sjasone KASSERT(mtx_owned((cvp)->cv_mtx), \ 76103216Sjulian ("%s: Mutex not owned", __func__)); \ 7771088Sjasone } \ 7871088Sjasone} while (0) 79103216Sjulian 8071088Sjasone#else 8171088Sjasone#define CV_WAIT_VALIDATE(cvp, mp) 8271088Sjasone#define CV_SIGNAL_VALIDATE(cvp) 8371088Sjasone#endif 8471088Sjasone 8571088Sjasonestatic void cv_timedwait_end(void *arg); 8671088Sjasone 8771088Sjasone/* 8871088Sjasone * Initialize a condition variable. Must be called before use. 8971088Sjasone */ 9071088Sjasonevoid 9171088Sjasonecv_init(struct cv *cvp, const char *desc) 9271088Sjasone{ 9371088Sjasone 9471088Sjasone TAILQ_INIT(&cvp->cv_waitq); 9571088Sjasone cvp->cv_mtx = NULL; 9671088Sjasone cvp->cv_description = desc; 9771088Sjasone} 9871088Sjasone 9971088Sjasone/* 10071088Sjasone * Destroy a condition variable. The condition variable must be re-initialized 10171088Sjasone * in order to be re-used. 10271088Sjasone */ 10371088Sjasonevoid 10471088Sjasonecv_destroy(struct cv *cvp) 10571088Sjasone{ 10671088Sjasone 10787594Sobrien KASSERT(cv_waitq_empty(cvp), ("%s: cv_waitq non-empty", __func__)); 10871088Sjasone} 10971088Sjasone 11071088Sjasone/* 11171088Sjasone * Common code for cv_wait* functions. All require sched_lock. 11271088Sjasone */ 11371088Sjasone 11471088Sjasone/* 115105911Sjulian * Switch context. 11699072Sjulian */ 117105911Sjulianstatic __inline void 118105911Sjuliancv_switch(struct thread *td) 11999072Sjulian{ 120103216Sjulian TD_SET_SLEEPING(td); 12183366Sjulian td->td_proc->p_stats->p_ru.ru_nvcsw++; 12271088Sjasone mi_switch(); 12383650Sjhb CTR3(KTR_PROC, "cv_switch: resume thread %p (pid %d, %s)", td, 12483650Sjhb td->td_proc->p_pid, td->td_proc->p_comm); 12571088Sjasone} 12671088Sjasone 12771088Sjasone/* 12871088Sjasone * Switch context, catching signals. 12971088Sjasone */ 13071088Sjasonestatic __inline int 13183366Sjuliancv_switch_catch(struct thread *td) 13271088Sjasone{ 13383650Sjhb struct proc *p; 13471088Sjasone int sig; 13571088Sjasone 13671088Sjasone /* 13771088Sjasone * We put ourselves on the sleep queue and start our timeout before 13897526Sjulian * calling cursig, as we could stop there, and a wakeup or a SIGCONT (or 13971088Sjasone * both) could occur while we were stopped. A SIGCONT would cause us to 14099072Sjulian * be marked as TDS_SLP without resuming us, thus we must be ready for 14197526Sjulian * sleep when cursig is called. If the wakeup happens while we're 142103216Sjulian * stopped, td->td_wchan will be 0 upon return from cursig, 143103216Sjulian * and TD_ON_SLEEPQ() will return false. 14471088Sjasone */ 14583366Sjulian td->td_flags |= TDF_SINTR; 14672200Sbmilekic mtx_unlock_spin(&sched_lock); 14783650Sjhb p = td->td_proc; 14883650Sjhb PROC_LOCK(p); 149103216Sjulian sig = cursig(td); 15099072Sjulian if (thread_suspend_check(1)) 15199072Sjulian sig = SIGSTOP; 15272200Sbmilekic mtx_lock_spin(&sched_lock); 15388900Sjhb PROC_UNLOCK(p); 15471088Sjasone if (sig != 0) { 155103216Sjulian if (TD_ON_SLEEPQ(td)) 15683366Sjulian cv_waitq_remove(td); 157103216Sjulian TD_SET_RUNNING(td); 158103216Sjulian } else if (TD_ON_SLEEPQ(td)) { 15983366Sjulian cv_switch(td); 16071088Sjasone } 16183366Sjulian td->td_flags &= ~TDF_SINTR; 16271088Sjasone 16371088Sjasone return sig; 16471088Sjasone} 16571088Sjasone 16671088Sjasone/* 16783366Sjulian * Add a thread to the wait queue of a condition variable. 16871088Sjasone */ 16971088Sjasonestatic __inline void 17083366Sjuliancv_waitq_add(struct cv *cvp, struct thread *td) 17171088Sjasone{ 17271088Sjasone 17383366Sjulian td->td_flags |= TDF_CVWAITQ; 174103216Sjulian TD_SET_ON_SLEEPQ(td); 17583366Sjulian td->td_wchan = cvp; 17683366Sjulian td->td_wmesg = cvp->cv_description; 17783366Sjulian CTR3(KTR_PROC, "cv_waitq_add: thread %p (pid %d, %s)", td, 17883650Sjhb td->td_proc->p_pid, td->td_proc->p_comm); 17983366Sjulian TAILQ_INSERT_TAIL(&cvp->cv_waitq, td, td_slpq); 180109862Sjeff sched_sleep(td, td->td_priority); 18171088Sjasone} 18271088Sjasone 18371088Sjasone/* 18483366Sjulian * Wait on a condition variable. The current thread is placed on the condition 18571088Sjasone * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 18683366Sjulian * condition variable will resume the thread. The mutex is released before 18771088Sjasone * sleeping and will be held on return. It is recommended that the mutex be 18871088Sjasone * held when cv_signal or cv_broadcast are called. 18971088Sjasone */ 19071088Sjasonevoid 19171088Sjasonecv_wait(struct cv *cvp, struct mtx *mp) 19271088Sjasone{ 19383366Sjulian struct thread *td; 19471088Sjasone WITNESS_SAVE_DECL(mp); 19571088Sjasone 19683366Sjulian td = curthread; 19771088Sjasone#ifdef KTRACE 19897995Sjhb if (KTRPOINT(td, KTR_CSW)) 19997995Sjhb ktrcsw(1, 0); 20071088Sjasone#endif 20183366Sjulian CV_ASSERT(cvp, mp, td); 202111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 203111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 20474912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 20571088Sjasone 206100209Sgallatin if (cold ) { 20771088Sjasone /* 208100209Sgallatin * During autoconfiguration, just give interrupts 209100209Sgallatin * a chance, then just return. Don't run any other 210100209Sgallatin * thread or panic below, in case this is the idle 211100209Sgallatin * process and already asleep. 21271088Sjasone */ 21371088Sjasone return; 21471088Sjasone } 21595322Shsu 21695322Shsu mtx_lock_spin(&sched_lock); 21795322Shsu 21871088Sjasone CV_WAIT_VALIDATE(cvp, mp); 21971088Sjasone 22088900Sjhb DROP_GIANT(); 22188900Sjhb mtx_unlock(mp); 22271088Sjasone 22383366Sjulian cv_waitq_add(cvp, td); 22483366Sjulian cv_switch(td); 22571088Sjasone 22672200Sbmilekic mtx_unlock_spin(&sched_lock); 22771088Sjasone#ifdef KTRACE 22897995Sjhb if (KTRPOINT(td, KTR_CSW)) 22997995Sjhb ktrcsw(0, 0); 23071088Sjasone#endif 23171088Sjasone PICKUP_GIANT(); 23272200Sbmilekic mtx_lock(mp); 23374912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 23471088Sjasone} 23571088Sjasone 23671088Sjasone/* 23771088Sjasone * Wait on a condition variable, allowing interruption by signals. Return 0 if 23883366Sjulian * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 23971088Sjasone * a signal was caught. If ERESTART is returned the system call should be 24071088Sjasone * restarted if possible. 24171088Sjasone */ 24271088Sjasoneint 24371088Sjasonecv_wait_sig(struct cv *cvp, struct mtx *mp) 24471088Sjasone{ 24583366Sjulian struct thread *td; 24683658Speter struct proc *p; 24771088Sjasone int rval; 24871088Sjasone int sig; 24971088Sjasone WITNESS_SAVE_DECL(mp); 25071088Sjasone 25183366Sjulian td = curthread; 25283650Sjhb p = td->td_proc; 25371088Sjasone rval = 0; 25471088Sjasone#ifdef KTRACE 25597995Sjhb if (KTRPOINT(td, KTR_CSW)) 25697995Sjhb ktrcsw(1, 0); 25771088Sjasone#endif 25883366Sjulian CV_ASSERT(cvp, mp, td); 259111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 260111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 26174912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 26271088Sjasone 26371088Sjasone if (cold || panicstr) { 26471088Sjasone /* 26571088Sjasone * After a panic, or during autoconfiguration, just give 26671088Sjasone * interrupts a chance, then just return; don't run any other 26771088Sjasone * procs or panic below, in case this is the idle process and 26871088Sjasone * already asleep. 26971088Sjasone */ 27071088Sjasone return 0; 27171088Sjasone } 27295322Shsu 27395322Shsu mtx_lock_spin(&sched_lock); 27495322Shsu 27571088Sjasone CV_WAIT_VALIDATE(cvp, mp); 27671088Sjasone 27788900Sjhb DROP_GIANT(); 27888900Sjhb mtx_unlock(mp); 27971088Sjasone 28083366Sjulian cv_waitq_add(cvp, td); 28183366Sjulian sig = cv_switch_catch(td); 28271088Sjasone 28372200Sbmilekic mtx_unlock_spin(&sched_lock); 28471088Sjasone 28583650Sjhb PROC_LOCK(p); 28671088Sjasone if (sig == 0) 28799072Sjulian sig = cursig(td); /* XXXKSE */ 28871088Sjasone if (sig != 0) { 28983650Sjhb if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) 29071088Sjasone rval = EINTR; 29171088Sjasone else 29271088Sjasone rval = ERESTART; 29371088Sjasone } 29483650Sjhb PROC_UNLOCK(p); 29599072Sjulian if (p->p_flag & P_WEXIT) 29699072Sjulian rval = EINTR; 29771088Sjasone 29871088Sjasone#ifdef KTRACE 29997995Sjhb if (KTRPOINT(td, KTR_CSW)) 30097995Sjhb ktrcsw(0, 0); 30171088Sjasone#endif 30297995Sjhb PICKUP_GIANT(); 30372200Sbmilekic mtx_lock(mp); 30474912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 30571088Sjasone 30671088Sjasone return (rval); 30771088Sjasone} 30871088Sjasone 30971088Sjasone/* 31071088Sjasone * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 31171088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 31271088Sjasone * expires. 31371088Sjasone */ 31471088Sjasoneint 31571088Sjasonecv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 31671088Sjasone{ 31783366Sjulian struct thread *td; 31871088Sjasone int rval; 31971088Sjasone WITNESS_SAVE_DECL(mp); 32071088Sjasone 32183366Sjulian td = curthread; 32271088Sjasone rval = 0; 32371088Sjasone#ifdef KTRACE 32497995Sjhb if (KTRPOINT(td, KTR_CSW)) 32597995Sjhb ktrcsw(1, 0); 32671088Sjasone#endif 32783366Sjulian CV_ASSERT(cvp, mp, td); 328111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 329111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 33074912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 33171088Sjasone 33271088Sjasone if (cold || panicstr) { 33371088Sjasone /* 33471088Sjasone * After a panic, or during autoconfiguration, just give 33571088Sjasone * interrupts a chance, then just return; don't run any other 33683366Sjulian * thread or panic below, in case this is the idle process and 33771088Sjasone * already asleep. 33871088Sjasone */ 33971088Sjasone return 0; 34071088Sjasone } 34195322Shsu 34295322Shsu mtx_lock_spin(&sched_lock); 34395322Shsu 34471088Sjasone CV_WAIT_VALIDATE(cvp, mp); 34571088Sjasone 34688900Sjhb DROP_GIANT(); 34788900Sjhb mtx_unlock(mp); 34871088Sjasone 34983366Sjulian cv_waitq_add(cvp, td); 35083366Sjulian callout_reset(&td->td_slpcallout, timo, cv_timedwait_end, td); 35183366Sjulian cv_switch(td); 35271088Sjasone 35383366Sjulian if (td->td_flags & TDF_TIMEOUT) { 35483366Sjulian td->td_flags &= ~TDF_TIMEOUT; 35571088Sjasone rval = EWOULDBLOCK; 35683366Sjulian } else if (td->td_flags & TDF_TIMOFAIL) 35783366Sjulian td->td_flags &= ~TDF_TIMOFAIL; 35883366Sjulian else if (callout_stop(&td->td_slpcallout) == 0) { 35982085Sjhb /* 36082085Sjhb * Work around race with cv_timedwait_end similar to that 36182085Sjhb * between msleep and endtsleep. 36299247Sjulian * Go back to sleep. 36382085Sjhb */ 364103216Sjulian TD_SET_SLEEPING(td); 36583366Sjulian td->td_proc->p_stats->p_ru.ru_nivcsw++; 36682085Sjhb mi_switch(); 367103216Sjulian td->td_flags &= ~TDF_TIMOFAIL; 36882085Sjhb } 36971088Sjasone 37099072Sjulian if (td->td_proc->p_flag & P_WEXIT) 37199072Sjulian rval = EWOULDBLOCK; 37272200Sbmilekic mtx_unlock_spin(&sched_lock); 37371088Sjasone#ifdef KTRACE 37497995Sjhb if (KTRPOINT(td, KTR_CSW)) 37597995Sjhb ktrcsw(0, 0); 37671088Sjasone#endif 37771088Sjasone PICKUP_GIANT(); 37872200Sbmilekic mtx_lock(mp); 37974912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 38071088Sjasone 38171088Sjasone return (rval); 38271088Sjasone} 38371088Sjasone 38471088Sjasone/* 38571088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing 38683366Sjulian * interruption by signals. Returns 0 if the thread was resumed by cv_signal 38771088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 38871088Sjasone * a signal was caught. 38971088Sjasone */ 39071088Sjasoneint 39171088Sjasonecv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 39271088Sjasone{ 39383366Sjulian struct thread *td; 39483650Sjhb struct proc *p; 39571088Sjasone int rval; 39671088Sjasone int sig; 39771088Sjasone WITNESS_SAVE_DECL(mp); 39871088Sjasone 39983366Sjulian td = curthread; 40083650Sjhb p = td->td_proc; 40171088Sjasone rval = 0; 40271088Sjasone#ifdef KTRACE 40397995Sjhb if (KTRPOINT(td, KTR_CSW)) 40497995Sjhb ktrcsw(1, 0); 40571088Sjasone#endif 40683366Sjulian CV_ASSERT(cvp, mp, td); 407111883Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object, 408111883Sjhb "Waiting on \"%s\"", cvp->cv_description); 40974912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 41071088Sjasone 41171088Sjasone if (cold || panicstr) { 41271088Sjasone /* 41371088Sjasone * After a panic, or during autoconfiguration, just give 41471088Sjasone * interrupts a chance, then just return; don't run any other 41583366Sjulian * thread or panic below, in case this is the idle process and 41671088Sjasone * already asleep. 41771088Sjasone */ 41871088Sjasone return 0; 41971088Sjasone } 42095322Shsu 42195322Shsu mtx_lock_spin(&sched_lock); 42295322Shsu 42371088Sjasone CV_WAIT_VALIDATE(cvp, mp); 42471088Sjasone 42588900Sjhb DROP_GIANT(); 42688900Sjhb mtx_unlock(mp); 42771088Sjasone 42883366Sjulian cv_waitq_add(cvp, td); 42983366Sjulian callout_reset(&td->td_slpcallout, timo, cv_timedwait_end, td); 43083366Sjulian sig = cv_switch_catch(td); 43171088Sjasone 43283366Sjulian if (td->td_flags & TDF_TIMEOUT) { 43383366Sjulian td->td_flags &= ~TDF_TIMEOUT; 43471088Sjasone rval = EWOULDBLOCK; 43583366Sjulian } else if (td->td_flags & TDF_TIMOFAIL) 43683366Sjulian td->td_flags &= ~TDF_TIMOFAIL; 43783366Sjulian else if (callout_stop(&td->td_slpcallout) == 0) { 43882085Sjhb /* 43982085Sjhb * Work around race with cv_timedwait_end similar to that 44082085Sjhb * between msleep and endtsleep. 44199247Sjulian * Go back to sleep. 44282085Sjhb */ 443103216Sjulian TD_SET_SLEEPING(td); 44483366Sjulian td->td_proc->p_stats->p_ru.ru_nivcsw++; 44582085Sjhb mi_switch(); 446103216Sjulian td->td_flags &= ~TDF_TIMOFAIL; 44782085Sjhb } 44872200Sbmilekic mtx_unlock_spin(&sched_lock); 44971088Sjasone 45083650Sjhb PROC_LOCK(p); 45171088Sjasone if (sig == 0) 45299072Sjulian sig = cursig(td); 45371088Sjasone if (sig != 0) { 45483650Sjhb if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) 45571088Sjasone rval = EINTR; 45671088Sjasone else 45771088Sjasone rval = ERESTART; 45871088Sjasone } 45983650Sjhb PROC_UNLOCK(p); 46071088Sjasone 46199072Sjulian if (p->p_flag & P_WEXIT) 46299072Sjulian rval = EINTR; 46399072Sjulian 46471088Sjasone#ifdef KTRACE 46597995Sjhb if (KTRPOINT(td, KTR_CSW)) 46697995Sjhb ktrcsw(0, 0); 46771088Sjasone#endif 46897995Sjhb PICKUP_GIANT(); 46972200Sbmilekic mtx_lock(mp); 47074912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 47171088Sjasone 47271088Sjasone return (rval); 47371088Sjasone} 47471088Sjasone 47571088Sjasone/* 47671088Sjasone * Common code for signal and broadcast. Assumes waitq is not empty. Must be 47771088Sjasone * called with sched_lock held. 47871088Sjasone */ 47971088Sjasonestatic __inline void 48071088Sjasonecv_wakeup(struct cv *cvp) 48171088Sjasone{ 48283366Sjulian struct thread *td; 48371088Sjasone 48471557Sjhb mtx_assert(&sched_lock, MA_OWNED); 48583366Sjulian td = TAILQ_FIRST(&cvp->cv_waitq); 48687594Sobrien KASSERT(td->td_wchan == cvp, ("%s: bogus wchan", __func__)); 48787594Sobrien KASSERT(td->td_flags & TDF_CVWAITQ, ("%s: not on waitq", __func__)); 488103216Sjulian cv_waitq_remove(td); 489103216Sjulian TD_CLR_SLEEPING(td); 490103216Sjulian setrunnable(td); 49171088Sjasone} 49271088Sjasone 49371088Sjasone/* 49483366Sjulian * Signal a condition variable, wakes up one waiting thread. Will also wakeup 49571088Sjasone * the swapper if the process is not in memory, so that it can bring the 49683366Sjulian * sleeping process in. Note that this may also result in additional threads 49771088Sjasone * being made runnable. Should be called with the same mutex as was passed to 49871088Sjasone * cv_wait held. 49971088Sjasone */ 50071088Sjasonevoid 50171088Sjasonecv_signal(struct cv *cvp) 50271088Sjasone{ 50371088Sjasone 50487594Sobrien KASSERT(cvp != NULL, ("%s: cvp NULL", __func__)); 50572200Sbmilekic mtx_lock_spin(&sched_lock); 50671088Sjasone if (!TAILQ_EMPTY(&cvp->cv_waitq)) { 50771088Sjasone CV_SIGNAL_VALIDATE(cvp); 50871088Sjasone cv_wakeup(cvp); 50971088Sjasone } 51072200Sbmilekic mtx_unlock_spin(&sched_lock); 51171088Sjasone} 51271088Sjasone 51371088Sjasone/* 51483366Sjulian * Broadcast a signal to a condition variable. Wakes up all waiting threads. 51571088Sjasone * Should be called with the same mutex as was passed to cv_wait held. 51671088Sjasone */ 51771088Sjasonevoid 51871088Sjasonecv_broadcast(struct cv *cvp) 51971088Sjasone{ 52071088Sjasone 52187594Sobrien KASSERT(cvp != NULL, ("%s: cvp NULL", __func__)); 52272200Sbmilekic mtx_lock_spin(&sched_lock); 52371088Sjasone CV_SIGNAL_VALIDATE(cvp); 52471088Sjasone while (!TAILQ_EMPTY(&cvp->cv_waitq)) 52571088Sjasone cv_wakeup(cvp); 52672200Sbmilekic mtx_unlock_spin(&sched_lock); 52771088Sjasone} 52871088Sjasone 52971088Sjasone/* 53083366Sjulian * Remove a thread from the wait queue of its condition variable. This may be 53171088Sjasone * called externally. 53271088Sjasone */ 53371088Sjasonevoid 53483366Sjuliancv_waitq_remove(struct thread *td) 53571088Sjasone{ 53671088Sjasone struct cv *cvp; 53771088Sjasone 538103216Sjulian mtx_assert(&sched_lock, MA_OWNED); 53983366Sjulian if ((cvp = td->td_wchan) != NULL && td->td_flags & TDF_CVWAITQ) { 54083366Sjulian TAILQ_REMOVE(&cvp->cv_waitq, td, td_slpq); 54183366Sjulian td->td_flags &= ~TDF_CVWAITQ; 542111605Sharti td->td_wmesg = NULL; 543103216Sjulian TD_CLR_ON_SLEEPQ(td); 54471088Sjasone } 54571088Sjasone} 54671088Sjasone 54771088Sjasone/* 54883366Sjulian * Timeout function for cv_timedwait. Put the thread on the runqueue and set 54971088Sjasone * its timeout flag. 55071088Sjasone */ 55171088Sjasonestatic void 55271088Sjasonecv_timedwait_end(void *arg) 55371088Sjasone{ 55483366Sjulian struct thread *td; 55571088Sjasone 55683366Sjulian td = arg; 557103216Sjulian CTR3(KTR_PROC, "cv_timedwait_end: thread %p (pid %d, %s)", 558103216Sjulian td, td->td_proc->p_pid, td->td_proc->p_comm); 55972200Sbmilekic mtx_lock_spin(&sched_lock); 560103216Sjulian if (TD_ON_SLEEPQ(td)) { 561103216Sjulian cv_waitq_remove(td); 56283366Sjulian td->td_flags |= TDF_TIMEOUT; 563103216Sjulian } else { 56483366Sjulian td->td_flags |= TDF_TIMOFAIL; 565103216Sjulian } 566103216Sjulian TD_CLR_SLEEPING(td); 567103216Sjulian setrunnable(td); 56872200Sbmilekic mtx_unlock_spin(&sched_lock); 56971088Sjasone} 57099072Sjulian 57199072Sjulian/* 57299072Sjulian * For now only abort interruptable waits. 57399072Sjulian * The others will have to either complete on their own or have a timeout. 57499072Sjulian */ 57599072Sjulianvoid 57699072Sjuliancv_abort(struct thread *td) 57799072Sjulian{ 57899072Sjulian 57999072Sjulian CTR3(KTR_PROC, "cv_abort: thread %p (pid %d, %s)", td, 580103216Sjulian td->td_proc->p_pid, td->td_proc->p_comm); 58199072Sjulian mtx_lock_spin(&sched_lock); 58299072Sjulian if ((td->td_flags & (TDF_SINTR|TDF_TIMEOUT)) == TDF_SINTR) { 583103216Sjulian if (TD_ON_SLEEPQ(td)) { 584103216Sjulian cv_waitq_remove(td); 58599072Sjulian } 586103216Sjulian TD_CLR_SLEEPING(td); 587103216Sjulian setrunnable(td); 58899072Sjulian } 58999072Sjulian mtx_unlock_spin(&sched_lock); 59099072Sjulian} 59199072Sjulian 592