kern_condvar.c revision 87594
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 87594 2001-12-10 05:51:45Z obrien $ 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> 3971088Sjasone#include <sys/signalvar.h> 4071088Sjasone#include <sys/resourcevar.h> 4171088Sjasone#ifdef KTRACE 4271088Sjasone#include <sys/uio.h> 4371088Sjasone#include <sys/ktrace.h> 4471088Sjasone#endif 4571088Sjasone 4671088Sjasone/* 4771088Sjasone * Common sanity checks for cv_wait* functions. 4871088Sjasone */ 4983366Sjulian#define CV_ASSERT(cvp, mp, td) do { \ 5087594Sobrien KASSERT((td) != NULL, ("%s: curthread NULL", __func__)); \ 5187594Sobrien KASSERT((td)->td_proc->p_stat == SRUN, ("%s: not SRUN", __func__)); \ 5287594Sobrien KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__)); \ 5387594Sobrien KASSERT((mp) != NULL, ("%s: mp NULL", __func__)); \ 5471088Sjasone mtx_assert((mp), MA_OWNED | MA_NOTRECURSED); \ 5571088Sjasone} while (0) 5671088Sjasone 5771088Sjasone#ifdef CV_DEBUG 5871088Sjasone#define CV_WAIT_VALIDATE(cvp, mp) do { \ 5971088Sjasone if (TAILQ_EMPTY(&(cvp)->cv_waitq)) { \ 6071088Sjasone /* Only waiter. */ \ 6171088Sjasone (cvp)->cv_mtx = (mp); \ 6271088Sjasone } else { \ 6371088Sjasone /* \ 6471088Sjasone * Other waiter; assert that we're using the \ 6571088Sjasone * same mutex. \ 6671088Sjasone */ \ 6771088Sjasone KASSERT((cvp)->cv_mtx == (mp), \ 6887594Sobrien ("%s: Multiple mutexes", __func__)); \ 6971088Sjasone } \ 7071088Sjasone} while (0) 7171088Sjasone#define CV_SIGNAL_VALIDATE(cvp) do { \ 7271088Sjasone if (!TAILQ_EMPTY(&(cvp)->cv_waitq)) { \ 7371088Sjasone KASSERT(mtx_owned((cvp)->cv_mtx), \ 7487594Sobrien ("%s: Mutex not owned", __func__)); \ 7571088Sjasone } \ 7671088Sjasone} while (0) 7771088Sjasone#else 7871088Sjasone#define CV_WAIT_VALIDATE(cvp, mp) 7971088Sjasone#define CV_SIGNAL_VALIDATE(cvp) 8071088Sjasone#endif 8171088Sjasone 8271088Sjasonestatic void cv_timedwait_end(void *arg); 8371088Sjasone 8471088Sjasone/* 8571088Sjasone * Initialize a condition variable. Must be called before use. 8671088Sjasone */ 8771088Sjasonevoid 8871088Sjasonecv_init(struct cv *cvp, const char *desc) 8971088Sjasone{ 9071088Sjasone 9171088Sjasone TAILQ_INIT(&cvp->cv_waitq); 9271088Sjasone cvp->cv_mtx = NULL; 9371088Sjasone cvp->cv_description = desc; 9471088Sjasone} 9571088Sjasone 9671088Sjasone/* 9771088Sjasone * Destroy a condition variable. The condition variable must be re-initialized 9871088Sjasone * in order to be re-used. 9971088Sjasone */ 10071088Sjasonevoid 10171088Sjasonecv_destroy(struct cv *cvp) 10271088Sjasone{ 10371088Sjasone 10487594Sobrien KASSERT(cv_waitq_empty(cvp), ("%s: cv_waitq non-empty", __func__)); 10571088Sjasone} 10671088Sjasone 10771088Sjasone/* 10871088Sjasone * Common code for cv_wait* functions. All require sched_lock. 10971088Sjasone */ 11071088Sjasone 11171088Sjasone/* 11271088Sjasone * Switch context. 11371088Sjasone */ 11471088Sjasonestatic __inline void 11583366Sjuliancv_switch(struct thread *td) 11671088Sjasone{ 11771088Sjasone 11883366Sjulian td->td_proc->p_stat = SSLEEP; 11983366Sjulian td->td_proc->p_stats->p_ru.ru_nvcsw++; 12071088Sjasone mi_switch(); 12183650Sjhb CTR3(KTR_PROC, "cv_switch: resume thread %p (pid %d, %s)", td, 12283650Sjhb td->td_proc->p_pid, td->td_proc->p_comm); 12371088Sjasone} 12471088Sjasone 12571088Sjasone/* 12671088Sjasone * Switch context, catching signals. 12771088Sjasone */ 12871088Sjasonestatic __inline int 12983366Sjuliancv_switch_catch(struct thread *td) 13071088Sjasone{ 13183650Sjhb struct proc *p; 13271088Sjasone int sig; 13371088Sjasone 13471088Sjasone /* 13571088Sjasone * We put ourselves on the sleep queue and start our timeout before 13671088Sjasone * calling CURSIG, as we could stop there, and a wakeup or a SIGCONT (or 13771088Sjasone * both) could occur while we were stopped. A SIGCONT would cause us to 13871088Sjasone * be marked as SSLEEP without resuming us, thus we must be ready for 13971088Sjasone * sleep when CURSIG is called. If the wakeup happens while we're 14083366Sjulian * stopped, td->td_wchan will be 0 upon return from CURSIG. 14171088Sjasone */ 14283366Sjulian td->td_flags |= TDF_SINTR; 14372200Sbmilekic mtx_unlock_spin(&sched_lock); 14483650Sjhb p = td->td_proc; 14583650Sjhb PROC_LOCK(p); 14683650Sjhb sig = CURSIG(p); /* XXXKSE */ 14772200Sbmilekic mtx_lock_spin(&sched_lock); 14883650Sjhb PROC_UNLOCK_NOSWITCH(p); 14971088Sjasone if (sig != 0) { 15083366Sjulian if (td->td_wchan != NULL) 15183366Sjulian cv_waitq_remove(td); 15283366Sjulian td->td_proc->p_stat = SRUN; 15383366Sjulian } else if (td->td_wchan != NULL) { 15483366Sjulian cv_switch(td); 15571088Sjasone } 15683366Sjulian td->td_flags &= ~TDF_SINTR; 15771088Sjasone 15871088Sjasone return sig; 15971088Sjasone} 16071088Sjasone 16171088Sjasone/* 16283366Sjulian * Add a thread to the wait queue of a condition variable. 16371088Sjasone */ 16471088Sjasonestatic __inline void 16583366Sjuliancv_waitq_add(struct cv *cvp, struct thread *td) 16671088Sjasone{ 16771088Sjasone 16871088Sjasone /* 16971088Sjasone * Process may be sitting on a slpque if asleep() was called, remove it 17071088Sjasone * before re-adding. 17171088Sjasone */ 17283366Sjulian if (td->td_wchan != NULL) 17383366Sjulian unsleep(td); 17471088Sjasone 17583366Sjulian td->td_flags |= TDF_CVWAITQ; 17683366Sjulian td->td_wchan = cvp; 17783366Sjulian td->td_wmesg = cvp->cv_description; 17883366Sjulian td->td_kse->ke_slptime = 0; /* XXXKSE */ 17983366Sjulian td->td_ksegrp->kg_slptime = 0; /* XXXKSE */ 18083366Sjulian td->td_ksegrp->kg_pri.pri_native = td->td_ksegrp->kg_pri.pri_level; 18183366Sjulian CTR3(KTR_PROC, "cv_waitq_add: thread %p (pid %d, %s)", td, 18283650Sjhb td->td_proc->p_pid, td->td_proc->p_comm); 18383366Sjulian TAILQ_INSERT_TAIL(&cvp->cv_waitq, td, td_slpq); 18471088Sjasone} 18571088Sjasone 18671088Sjasone/* 18783366Sjulian * Wait on a condition variable. The current thread is placed on the condition 18871088Sjasone * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 18983366Sjulian * condition variable will resume the thread. The mutex is released before 19071088Sjasone * sleeping and will be held on return. It is recommended that the mutex be 19171088Sjasone * held when cv_signal or cv_broadcast are called. 19271088Sjasone */ 19371088Sjasonevoid 19471088Sjasonecv_wait(struct cv *cvp, struct mtx *mp) 19571088Sjasone{ 19683366Sjulian struct thread *td; 19771088Sjasone WITNESS_SAVE_DECL(mp); 19871088Sjasone 19983366Sjulian td = curthread; 20071088Sjasone#ifdef KTRACE 20183366Sjulian if (td->td_proc && KTRPOINT(td->td_proc, KTR_CSW)) 20283366Sjulian ktrcsw(td->td_proc->p_tracep, 1, 0); 20371088Sjasone#endif 20483366Sjulian CV_ASSERT(cvp, mp, td); 20574920Sjhb WITNESS_SLEEP(0, &mp->mtx_object); 20674912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 20771088Sjasone 20872200Sbmilekic mtx_lock_spin(&sched_lock); 20971088Sjasone if (cold || panicstr) { 21071088Sjasone /* 21171088Sjasone * After a panic, or during autoconfiguration, just give 21271088Sjasone * interrupts a chance, then just return; don't run any other 21383366Sjulian * thread or panic below, in case this is the idle process and 21471088Sjasone * already asleep. 21571088Sjasone */ 21672200Sbmilekic mtx_unlock_spin(&sched_lock); 21771088Sjasone return; 21871088Sjasone } 21971088Sjasone CV_WAIT_VALIDATE(cvp, mp); 22071088Sjasone 22171088Sjasone DROP_GIANT_NOSWITCH(); 22272200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 22371088Sjasone 22483366Sjulian cv_waitq_add(cvp, td); 22583366Sjulian cv_switch(td); 22671088Sjasone 22772200Sbmilekic mtx_unlock_spin(&sched_lock); 22871088Sjasone#ifdef KTRACE 22983366Sjulian if (KTRPOINT(td->td_proc, KTR_CSW)) 23083366Sjulian ktrcsw(td->td_proc->p_tracep, 0, 0); 23171088Sjasone#endif 23271088Sjasone PICKUP_GIANT(); 23372200Sbmilekic mtx_lock(mp); 23474912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 23571088Sjasone} 23671088Sjasone 23771088Sjasone/* 23871088Sjasone * Wait on a condition variable, allowing interruption by signals. Return 0 if 23983366Sjulian * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 24071088Sjasone * a signal was caught. If ERESTART is returned the system call should be 24171088Sjasone * restarted if possible. 24271088Sjasone */ 24371088Sjasoneint 24471088Sjasonecv_wait_sig(struct cv *cvp, struct mtx *mp) 24571088Sjasone{ 24683366Sjulian struct thread *td; 24783658Speter struct proc *p; 24871088Sjasone int rval; 24971088Sjasone int sig; 25071088Sjasone WITNESS_SAVE_DECL(mp); 25171088Sjasone 25283366Sjulian td = curthread; 25383650Sjhb p = td->td_proc; 25471088Sjasone rval = 0; 25571088Sjasone#ifdef KTRACE 25683366Sjulian if (td->td_proc && KTRPOINT(td->td_proc, KTR_CSW)) 25783366Sjulian ktrcsw(td->td_proc->p_tracep, 1, 0); 25871088Sjasone#endif 25983366Sjulian CV_ASSERT(cvp, mp, td); 26074920Sjhb WITNESS_SLEEP(0, &mp->mtx_object); 26174912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 26271088Sjasone 26372200Sbmilekic mtx_lock_spin(&sched_lock); 26471088Sjasone if (cold || panicstr) { 26571088Sjasone /* 26671088Sjasone * After a panic, or during autoconfiguration, just give 26771088Sjasone * interrupts a chance, then just return; don't run any other 26871088Sjasone * procs or panic below, in case this is the idle process and 26971088Sjasone * already asleep. 27071088Sjasone */ 27172200Sbmilekic mtx_unlock_spin(&sched_lock); 27271088Sjasone return 0; 27371088Sjasone } 27471088Sjasone CV_WAIT_VALIDATE(cvp, mp); 27571088Sjasone 27671088Sjasone DROP_GIANT_NOSWITCH(); 27772200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 27871088Sjasone 27983366Sjulian cv_waitq_add(cvp, td); 28083366Sjulian sig = cv_switch_catch(td); 28171088Sjasone 28272200Sbmilekic mtx_unlock_spin(&sched_lock); 28371088Sjasone PICKUP_GIANT(); 28471088Sjasone 28583650Sjhb PROC_LOCK(p); 28671088Sjasone if (sig == 0) 28783650Sjhb sig = CURSIG(p); /* 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); 29571088Sjasone 29671088Sjasone#ifdef KTRACE 29778637Sjhb mtx_lock(&Giant); 29883366Sjulian if (KTRPOINT(td->td_proc, KTR_CSW)) 29983366Sjulian ktrcsw(td->td_proc->p_tracep, 0, 0); 30078637Sjhb mtx_unlock(&Giant); 30171088Sjasone#endif 30272200Sbmilekic mtx_lock(mp); 30374912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 30471088Sjasone 30571088Sjasone return (rval); 30671088Sjasone} 30771088Sjasone 30871088Sjasone/* 30971088Sjasone * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 31071088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 31171088Sjasone * expires. 31271088Sjasone */ 31371088Sjasoneint 31471088Sjasonecv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 31571088Sjasone{ 31683366Sjulian struct thread *td; 31771088Sjasone int rval; 31871088Sjasone WITNESS_SAVE_DECL(mp); 31971088Sjasone 32083366Sjulian td = curthread; 32171088Sjasone rval = 0; 32271088Sjasone#ifdef KTRACE 32383366Sjulian ktrcsw(td->td_proc->p_tracep, 1, 0); 32471088Sjasone#endif 32583366Sjulian CV_ASSERT(cvp, mp, td); 32674920Sjhb WITNESS_SLEEP(0, &mp->mtx_object); 32774912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 32871088Sjasone 32972200Sbmilekic mtx_lock_spin(&sched_lock); 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 */ 33772200Sbmilekic mtx_unlock_spin(&sched_lock); 33871088Sjasone return 0; 33971088Sjasone } 34071088Sjasone CV_WAIT_VALIDATE(cvp, mp); 34171088Sjasone 34271088Sjasone DROP_GIANT_NOSWITCH(); 34372200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 34471088Sjasone 34583366Sjulian cv_waitq_add(cvp, td); 34683366Sjulian callout_reset(&td->td_slpcallout, timo, cv_timedwait_end, td); 34783366Sjulian cv_switch(td); 34871088Sjasone 34983366Sjulian if (td->td_flags & TDF_TIMEOUT) { 35083366Sjulian td->td_flags &= ~TDF_TIMEOUT; 35171088Sjasone rval = EWOULDBLOCK; 35283366Sjulian } else if (td->td_flags & TDF_TIMOFAIL) 35383366Sjulian td->td_flags &= ~TDF_TIMOFAIL; 35483366Sjulian else if (callout_stop(&td->td_slpcallout) == 0) { 35582085Sjhb /* 35682085Sjhb * Work around race with cv_timedwait_end similar to that 35782085Sjhb * between msleep and endtsleep. 35882085Sjhb */ 35983366Sjulian td->td_flags |= TDF_TIMEOUT; 36083366Sjulian td->td_proc->p_stats->p_ru.ru_nivcsw++; 36182085Sjhb mi_switch(); 36282085Sjhb } 36371088Sjasone 36472200Sbmilekic mtx_unlock_spin(&sched_lock); 36571088Sjasone#ifdef KTRACE 36683366Sjulian if (KTRPOINT(td->td_proc, KTR_CSW)) 36783366Sjulian ktrcsw(td->td_proc->p_tracep, 0, 0); 36871088Sjasone#endif 36971088Sjasone PICKUP_GIANT(); 37072200Sbmilekic mtx_lock(mp); 37174912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 37271088Sjasone 37371088Sjasone return (rval); 37471088Sjasone} 37571088Sjasone 37671088Sjasone/* 37771088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing 37883366Sjulian * interruption by signals. Returns 0 if the thread was resumed by cv_signal 37971088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 38071088Sjasone * a signal was caught. 38171088Sjasone */ 38271088Sjasoneint 38371088Sjasonecv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 38471088Sjasone{ 38583366Sjulian struct thread *td; 38683650Sjhb struct proc *p; 38771088Sjasone int rval; 38871088Sjasone int sig; 38971088Sjasone WITNESS_SAVE_DECL(mp); 39071088Sjasone 39183366Sjulian td = curthread; 39283650Sjhb p = td->td_proc; 39371088Sjasone rval = 0; 39471088Sjasone#ifdef KTRACE 39583366Sjulian if (td->td_proc && KTRPOINT(td->td_proc, KTR_CSW)) 39683366Sjulian ktrcsw(td->td_proc->p_tracep, 1, 0); 39771088Sjasone#endif 39883366Sjulian CV_ASSERT(cvp, mp, td); 39974920Sjhb WITNESS_SLEEP(0, &mp->mtx_object); 40074912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 40171088Sjasone 40272200Sbmilekic mtx_lock_spin(&sched_lock); 40371088Sjasone if (cold || panicstr) { 40471088Sjasone /* 40571088Sjasone * After a panic, or during autoconfiguration, just give 40671088Sjasone * interrupts a chance, then just return; don't run any other 40783366Sjulian * thread or panic below, in case this is the idle process and 40871088Sjasone * already asleep. 40971088Sjasone */ 41072200Sbmilekic mtx_unlock_spin(&sched_lock); 41171088Sjasone return 0; 41271088Sjasone } 41371088Sjasone CV_WAIT_VALIDATE(cvp, mp); 41471088Sjasone 41571088Sjasone DROP_GIANT_NOSWITCH(); 41672200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 41771088Sjasone 41883366Sjulian cv_waitq_add(cvp, td); 41983366Sjulian callout_reset(&td->td_slpcallout, timo, cv_timedwait_end, td); 42083366Sjulian sig = cv_switch_catch(td); 42171088Sjasone 42283366Sjulian if (td->td_flags & TDF_TIMEOUT) { 42383366Sjulian td->td_flags &= ~TDF_TIMEOUT; 42471088Sjasone rval = EWOULDBLOCK; 42583366Sjulian } else if (td->td_flags & TDF_TIMOFAIL) 42683366Sjulian td->td_flags &= ~TDF_TIMOFAIL; 42783366Sjulian else if (callout_stop(&td->td_slpcallout) == 0) { 42882085Sjhb /* 42982085Sjhb * Work around race with cv_timedwait_end similar to that 43082085Sjhb * between msleep and endtsleep. 43182085Sjhb */ 43283366Sjulian td->td_flags |= TDF_TIMEOUT; 43383366Sjulian td->td_proc->p_stats->p_ru.ru_nivcsw++; 43482085Sjhb mi_switch(); 43582085Sjhb } 43671088Sjasone 43772200Sbmilekic mtx_unlock_spin(&sched_lock); 43871088Sjasone PICKUP_GIANT(); 43971088Sjasone 44083650Sjhb PROC_LOCK(p); 44171088Sjasone if (sig == 0) 44283650Sjhb sig = CURSIG(p); 44371088Sjasone if (sig != 0) { 44483650Sjhb if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) 44571088Sjasone rval = EINTR; 44671088Sjasone else 44771088Sjasone rval = ERESTART; 44871088Sjasone } 44983650Sjhb PROC_UNLOCK(p); 45071088Sjasone 45171088Sjasone#ifdef KTRACE 45278637Sjhb mtx_lock(&Giant); 45383366Sjulian if (KTRPOINT(td->td_proc, KTR_CSW)) 45483366Sjulian ktrcsw(td->td_proc->p_tracep, 0, 0); 45578637Sjhb mtx_unlock(&Giant); 45671088Sjasone#endif 45772200Sbmilekic mtx_lock(mp); 45874912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 45971088Sjasone 46071088Sjasone return (rval); 46171088Sjasone} 46271088Sjasone 46371088Sjasone/* 46471088Sjasone * Common code for signal and broadcast. Assumes waitq is not empty. Must be 46571088Sjasone * called with sched_lock held. 46671088Sjasone */ 46771088Sjasonestatic __inline void 46871088Sjasonecv_wakeup(struct cv *cvp) 46971088Sjasone{ 47083366Sjulian struct thread *td; 47171088Sjasone 47271557Sjhb mtx_assert(&sched_lock, MA_OWNED); 47383366Sjulian td = TAILQ_FIRST(&cvp->cv_waitq); 47487594Sobrien KASSERT(td->td_wchan == cvp, ("%s: bogus wchan", __func__)); 47587594Sobrien KASSERT(td->td_flags & TDF_CVWAITQ, ("%s: not on waitq", __func__)); 47683366Sjulian TAILQ_REMOVE(&cvp->cv_waitq, td, td_slpq); 47783366Sjulian td->td_flags &= ~TDF_CVWAITQ; 47883366Sjulian td->td_wchan = 0; 47983366Sjulian if (td->td_proc->p_stat == SSLEEP) { 48083366Sjulian /* OPTIMIZED EXPANSION OF setrunnable(td); */ 48183366Sjulian CTR3(KTR_PROC, "cv_signal: thread %p (pid %d, %s)", 48283366Sjulian td, td->td_proc->p_pid, td->td_proc->p_comm); 48383366Sjulian if (td->td_ksegrp->kg_slptime > 1) /* XXXKSE */ 48483366Sjulian updatepri(td); 48583366Sjulian td->td_kse->ke_slptime = 0; 48683366Sjulian td->td_ksegrp->kg_slptime = 0; 48783366Sjulian td->td_proc->p_stat = SRUN; 48883366Sjulian if (td->td_proc->p_sflag & PS_INMEM) { 48983366Sjulian setrunqueue(td); 49083366Sjulian maybe_resched(td->td_ksegrp); 49171088Sjasone } else { 49283366Sjulian td->td_proc->p_sflag |= PS_SWAPINREQ; 49383366Sjulian wakeup(&proc0); /* XXXKSE */ 49471088Sjasone } 49571088Sjasone /* END INLINE EXPANSION */ 49671088Sjasone } 49771088Sjasone} 49871088Sjasone 49971088Sjasone/* 50083366Sjulian * Signal a condition variable, wakes up one waiting thread. Will also wakeup 50171088Sjasone * the swapper if the process is not in memory, so that it can bring the 50283366Sjulian * sleeping process in. Note that this may also result in additional threads 50371088Sjasone * being made runnable. Should be called with the same mutex as was passed to 50471088Sjasone * cv_wait held. 50571088Sjasone */ 50671088Sjasonevoid 50771088Sjasonecv_signal(struct cv *cvp) 50871088Sjasone{ 50971088Sjasone 51087594Sobrien KASSERT(cvp != NULL, ("%s: cvp NULL", __func__)); 51172200Sbmilekic mtx_lock_spin(&sched_lock); 51271088Sjasone if (!TAILQ_EMPTY(&cvp->cv_waitq)) { 51371088Sjasone CV_SIGNAL_VALIDATE(cvp); 51471088Sjasone cv_wakeup(cvp); 51571088Sjasone } 51672200Sbmilekic mtx_unlock_spin(&sched_lock); 51771088Sjasone} 51871088Sjasone 51971088Sjasone/* 52083366Sjulian * Broadcast a signal to a condition variable. Wakes up all waiting threads. 52171088Sjasone * Should be called with the same mutex as was passed to cv_wait held. 52271088Sjasone */ 52371088Sjasonevoid 52471088Sjasonecv_broadcast(struct cv *cvp) 52571088Sjasone{ 52671088Sjasone 52787594Sobrien KASSERT(cvp != NULL, ("%s: cvp NULL", __func__)); 52872200Sbmilekic mtx_lock_spin(&sched_lock); 52971088Sjasone CV_SIGNAL_VALIDATE(cvp); 53071088Sjasone while (!TAILQ_EMPTY(&cvp->cv_waitq)) 53171088Sjasone cv_wakeup(cvp); 53272200Sbmilekic mtx_unlock_spin(&sched_lock); 53371088Sjasone} 53471088Sjasone 53571088Sjasone/* 53683366Sjulian * Remove a thread from the wait queue of its condition variable. This may be 53771088Sjasone * called externally. 53871088Sjasone */ 53971088Sjasonevoid 54083366Sjuliancv_waitq_remove(struct thread *td) 54171088Sjasone{ 54271088Sjasone struct cv *cvp; 54371088Sjasone 54472200Sbmilekic mtx_lock_spin(&sched_lock); 54583366Sjulian if ((cvp = td->td_wchan) != NULL && td->td_flags & TDF_CVWAITQ) { 54683366Sjulian TAILQ_REMOVE(&cvp->cv_waitq, td, td_slpq); 54783366Sjulian td->td_flags &= ~TDF_CVWAITQ; 54883366Sjulian td->td_wchan = NULL; 54971088Sjasone } 55072200Sbmilekic mtx_unlock_spin(&sched_lock); 55171088Sjasone} 55271088Sjasone 55371088Sjasone/* 55483366Sjulian * Timeout function for cv_timedwait. Put the thread on the runqueue and set 55571088Sjasone * its timeout flag. 55671088Sjasone */ 55771088Sjasonestatic void 55871088Sjasonecv_timedwait_end(void *arg) 55971088Sjasone{ 56083366Sjulian struct thread *td; 56171088Sjasone 56283366Sjulian td = arg; 56383366Sjulian CTR3(KTR_PROC, "cv_timedwait_end: thread %p (pid %d, %s)", td, td->td_proc->p_pid, 56483366Sjulian td->td_proc->p_comm); 56572200Sbmilekic mtx_lock_spin(&sched_lock); 56683366Sjulian if (td->td_flags & TDF_TIMEOUT) { 56783366Sjulian td->td_flags &= ~TDF_TIMEOUT; 56883366Sjulian setrunqueue(td); 56983366Sjulian } else if (td->td_wchan != NULL) { 57083366Sjulian if (td->td_proc->p_stat == SSLEEP) /* XXXKSE */ 57183366Sjulian setrunnable(td); 57271088Sjasone else 57383366Sjulian cv_waitq_remove(td); 57483366Sjulian td->td_flags |= TDF_TIMEOUT; 57582085Sjhb } else 57683366Sjulian td->td_flags |= TDF_TIMOFAIL; 57772200Sbmilekic mtx_unlock_spin(&sched_lock); 57871088Sjasone} 579