kern_condvar.c revision 72200
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 72200 2001-02-09 06:11:45Z bmilekic $ 2771088Sjasone */ 2871088Sjasone 2971088Sjasone#include "opt_ktrace.h" 3071088Sjasone 3171088Sjasone#include <sys/param.h> 3271088Sjasone#include <sys/systm.h> 3371088Sjasone#include <sys/proc.h> 3471088Sjasone#include <sys/kernel.h> 3571088Sjasone#include <sys/ktr.h> 3671088Sjasone#include <sys/condvar.h> 3771088Sjasone#include <sys/mutex.h> 3871088Sjasone#include <sys/signalvar.h> 3971088Sjasone#include <sys/resourcevar.h> 4071088Sjasone#ifdef KTRACE 4171088Sjasone#include <sys/uio.h> 4271088Sjasone#include <sys/ktrace.h> 4371088Sjasone#endif 4471088Sjasone 4571088Sjasone/* 4671088Sjasone * Common sanity checks for cv_wait* functions. 4771088Sjasone */ 4871088Sjasone#define CV_ASSERT(cvp, mp, p) do { \ 4971088Sjasone KASSERT((p) != NULL, ("%s: curproc NULL", __FUNCTION__)); \ 5071088Sjasone KASSERT((p)->p_stat == SRUN, ("%s: not SRUN", __FUNCTION__)); \ 5171088Sjasone KASSERT((cvp) != NULL, ("%s: cvp NULL", __FUNCTION__)); \ 5271088Sjasone KASSERT((mp) != NULL, ("%s: mp NULL", __FUNCTION__)); \ 5371088Sjasone mtx_assert((mp), MA_OWNED | MA_NOTRECURSED); \ 5471088Sjasone} while (0) 5571088Sjasone 5671088Sjasone#ifdef CV_DEBUG 5771088Sjasone#define CV_WAIT_VALIDATE(cvp, mp) do { \ 5871088Sjasone if (TAILQ_EMPTY(&(cvp)->cv_waitq)) { \ 5971088Sjasone /* Only waiter. */ \ 6071088Sjasone (cvp)->cv_mtx = (mp); \ 6171088Sjasone } else { \ 6271088Sjasone /* \ 6371088Sjasone * Other waiter; assert that we're using the \ 6471088Sjasone * same mutex. \ 6571088Sjasone */ \ 6671088Sjasone KASSERT((cvp)->cv_mtx == (mp), \ 6771088Sjasone ("%s: Multiple mutexes", __FUNCTION__)); \ 6871088Sjasone } \ 6971088Sjasone} while (0) 7071088Sjasone#define CV_SIGNAL_VALIDATE(cvp) do { \ 7171088Sjasone if (!TAILQ_EMPTY(&(cvp)->cv_waitq)) { \ 7271088Sjasone KASSERT(mtx_owned((cvp)->cv_mtx), \ 7371088Sjasone ("%s: Mutex not owned", __FUNCTION__)); \ 7471088Sjasone } \ 7571088Sjasone} while (0) 7671088Sjasone#else 7771088Sjasone#define CV_WAIT_VALIDATE(cvp, mp) 7871088Sjasone#define CV_SIGNAL_VALIDATE(cvp) 7971088Sjasone#endif 8071088Sjasone 8171088Sjasonestatic void cv_timedwait_end(void *arg); 8271088Sjasone 8371088Sjasone/* 8471088Sjasone * Initialize a condition variable. Must be called before use. 8571088Sjasone */ 8671088Sjasonevoid 8771088Sjasonecv_init(struct cv *cvp, const char *desc) 8871088Sjasone{ 8971088Sjasone 9071088Sjasone TAILQ_INIT(&cvp->cv_waitq); 9171088Sjasone cvp->cv_mtx = NULL; 9271088Sjasone cvp->cv_description = desc; 9371088Sjasone} 9471088Sjasone 9571088Sjasone/* 9671088Sjasone * Destroy a condition variable. The condition variable must be re-initialized 9771088Sjasone * in order to be re-used. 9871088Sjasone */ 9971088Sjasonevoid 10071088Sjasonecv_destroy(struct cv *cvp) 10171088Sjasone{ 10271088Sjasone 10371088Sjasone KASSERT(cv_waitq_empty(cvp), ("%s: cv_waitq non-empty", __FUNCTION__)); 10471088Sjasone} 10571088Sjasone 10671088Sjasone/* 10771088Sjasone * Common code for cv_wait* functions. All require sched_lock. 10871088Sjasone */ 10971088Sjasone 11071088Sjasone/* 11171088Sjasone * Switch context. 11271088Sjasone */ 11371088Sjasonestatic __inline void 11471088Sjasonecv_switch(struct proc *p) 11571088Sjasone{ 11671088Sjasone 11771088Sjasone p->p_stat = SSLEEP; 11871088Sjasone p->p_stats->p_ru.ru_nvcsw++; 11971088Sjasone mi_switch(); 12071088Sjasone CTR3(KTR_PROC, "cv_switch: resume proc %p (pid %d, %s)", p, p->p_pid, 12171088Sjasone p->p_comm); 12271088Sjasone} 12371088Sjasone 12471088Sjasone/* 12571088Sjasone * Switch context, catching signals. 12671088Sjasone */ 12771088Sjasonestatic __inline int 12871088Sjasonecv_switch_catch(struct proc *p) 12971088Sjasone{ 13071088Sjasone int sig; 13171088Sjasone 13271088Sjasone /* 13371088Sjasone * We put ourselves on the sleep queue and start our timeout before 13471088Sjasone * calling CURSIG, as we could stop there, and a wakeup or a SIGCONT (or 13571088Sjasone * both) could occur while we were stopped. A SIGCONT would cause us to 13671088Sjasone * be marked as SSLEEP without resuming us, thus we must be ready for 13771088Sjasone * sleep when CURSIG is called. If the wakeup happens while we're 13871088Sjasone * stopped, p->p_wchan will be 0 upon return from CURSIG. 13971088Sjasone */ 14071557Sjhb p->p_sflag |= PS_SINTR; 14172200Sbmilekic mtx_unlock_spin(&sched_lock); 14271088Sjasone sig = CURSIG(p); 14372200Sbmilekic mtx_lock_spin(&sched_lock); 14471088Sjasone if (sig != 0) { 14571088Sjasone if (p->p_wchan != NULL) 14671088Sjasone cv_waitq_remove(p); 14771088Sjasone p->p_stat = SRUN; 14871088Sjasone } else if (p->p_wchan != NULL) { 14971088Sjasone cv_switch(p); 15071088Sjasone } 15171557Sjhb p->p_sflag &= ~PS_SINTR; 15271088Sjasone 15371088Sjasone return sig; 15471088Sjasone} 15571088Sjasone 15671088Sjasone/* 15771088Sjasone * Add a process to the wait queue of a condition variable. 15871088Sjasone */ 15971088Sjasonestatic __inline void 16071088Sjasonecv_waitq_add(struct cv *cvp, struct proc *p) 16171088Sjasone{ 16271088Sjasone 16371088Sjasone /* 16471088Sjasone * Process may be sitting on a slpque if asleep() was called, remove it 16571088Sjasone * before re-adding. 16671088Sjasone */ 16771088Sjasone if (p->p_wchan != NULL) 16871088Sjasone unsleep(p); 16971088Sjasone 17071557Sjhb p->p_sflag |= PS_CVWAITQ; 17171088Sjasone p->p_wchan = cvp; 17271088Sjasone p->p_wmesg = cvp->cv_description; 17371088Sjasone p->p_slptime = 0; 17471088Sjasone p->p_nativepri = p->p_priority; 17571088Sjasone CTR3(KTR_PROC, "cv_waitq_add: proc %p (pid %d, %s)", p, p->p_pid, 17671088Sjasone p->p_comm); 17771088Sjasone TAILQ_INSERT_TAIL(&cvp->cv_waitq, p, p_slpq); 17871088Sjasone} 17971088Sjasone 18071088Sjasone/* 18171088Sjasone * Wait on a condition variable. The current process is placed on the condition 18271088Sjasone * variable's wait queue and suspended. A cv_signal or cv_broadcast on the same 18371088Sjasone * condition variable will resume the process. The mutex is released before 18471088Sjasone * sleeping and will be held on return. It is recommended that the mutex be 18571088Sjasone * held when cv_signal or cv_broadcast are called. 18671088Sjasone */ 18771088Sjasonevoid 18871088Sjasonecv_wait(struct cv *cvp, struct mtx *mp) 18971088Sjasone{ 19071088Sjasone struct proc *p; 19171088Sjasone WITNESS_SAVE_DECL(mp); 19271088Sjasone 19371088Sjasone p = CURPROC; 19471088Sjasone#ifdef KTRACE 19571088Sjasone if (p && KTRPOINT(p, KTR_CSW)) 19671088Sjasone ktrcsw(p->p_tracep, 1, 0); 19771088Sjasone#endif 19871088Sjasone CV_ASSERT(cvp, mp, p); 19971088Sjasone WITNESS_SLEEP(0, mp); 20071088Sjasone WITNESS_SAVE(mp, mp); 20171088Sjasone 20272200Sbmilekic mtx_lock_spin(&sched_lock); 20371088Sjasone if (cold || panicstr) { 20471088Sjasone /* 20571088Sjasone * After a panic, or during autoconfiguration, just give 20671088Sjasone * interrupts a chance, then just return; don't run any other 20771088Sjasone * procs or panic below, in case this is the idle process and 20871088Sjasone * already asleep. 20971088Sjasone */ 21072200Sbmilekic mtx_unlock_spin(&sched_lock); 21171088Sjasone return; 21271088Sjasone } 21371088Sjasone CV_WAIT_VALIDATE(cvp, mp); 21471088Sjasone 21571088Sjasone DROP_GIANT_NOSWITCH(); 21672200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 21771088Sjasone 21871088Sjasone cv_waitq_add(cvp, p); 21971088Sjasone cv_switch(p); 22071088Sjasone curpriority = p->p_usrpri; 22171088Sjasone 22272200Sbmilekic mtx_unlock_spin(&sched_lock); 22371088Sjasone#ifdef KTRACE 22471088Sjasone if (KTRPOINT(p, KTR_CSW)) 22571088Sjasone ktrcsw(p->p_tracep, 0, 0); 22671088Sjasone#endif 22771088Sjasone PICKUP_GIANT(); 22872200Sbmilekic mtx_lock(mp); 22971088Sjasone WITNESS_RESTORE(mp, mp); 23071088Sjasone} 23171088Sjasone 23271088Sjasone/* 23371088Sjasone * Wait on a condition variable, allowing interruption by signals. Return 0 if 23471088Sjasone * the process was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 23571088Sjasone * a signal was caught. If ERESTART is returned the system call should be 23671088Sjasone * restarted if possible. 23771088Sjasone */ 23871088Sjasoneint 23971088Sjasonecv_wait_sig(struct cv *cvp, struct mtx *mp) 24071088Sjasone{ 24171088Sjasone struct proc *p; 24271088Sjasone int rval; 24371088Sjasone int sig; 24471088Sjasone WITNESS_SAVE_DECL(mp); 24571088Sjasone 24671088Sjasone p = CURPROC; 24771088Sjasone rval = 0; 24871088Sjasone#ifdef KTRACE 24971088Sjasone if (p && KTRPOINT(p, KTR_CSW)) 25071088Sjasone ktrcsw(p->p_tracep, 1, 0); 25171088Sjasone#endif 25271088Sjasone CV_ASSERT(cvp, mp, p); 25371088Sjasone WITNESS_SLEEP(0, mp); 25471088Sjasone WITNESS_SAVE(mp, mp); 25571088Sjasone 25672200Sbmilekic mtx_lock_spin(&sched_lock); 25771088Sjasone if (cold || panicstr) { 25871088Sjasone /* 25971088Sjasone * After a panic, or during autoconfiguration, just give 26071088Sjasone * interrupts a chance, then just return; don't run any other 26171088Sjasone * procs or panic below, in case this is the idle process and 26271088Sjasone * already asleep. 26371088Sjasone */ 26472200Sbmilekic mtx_unlock_spin(&sched_lock); 26571088Sjasone return 0; 26671088Sjasone } 26771088Sjasone CV_WAIT_VALIDATE(cvp, mp); 26871088Sjasone 26971088Sjasone DROP_GIANT_NOSWITCH(); 27072200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 27171088Sjasone 27271088Sjasone cv_waitq_add(cvp, p); 27371088Sjasone sig = cv_switch_catch(p); 27471088Sjasone curpriority = p->p_usrpri; 27571088Sjasone 27672200Sbmilekic mtx_unlock_spin(&sched_lock); 27771088Sjasone PICKUP_GIANT(); 27871088Sjasone 27971088Sjasone /* proc_lock(p); */ 28071088Sjasone if (sig == 0) 28171088Sjasone sig = CURSIG(p); 28271088Sjasone if (sig != 0) { 28371088Sjasone if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) 28471088Sjasone rval = EINTR; 28571088Sjasone else 28671088Sjasone rval = ERESTART; 28771088Sjasone } 28871088Sjasone /* proc_unlock(p); */ 28971088Sjasone 29071088Sjasone#ifdef KTRACE 29171088Sjasone if (KTRPOINT(p, KTR_CSW)) 29271088Sjasone ktrcsw(p->p_tracep, 0, 0); 29371088Sjasone#endif 29472200Sbmilekic mtx_lock(mp); 29571088Sjasone WITNESS_RESTORE(mp, mp); 29671088Sjasone 29771088Sjasone return (rval); 29871088Sjasone} 29971088Sjasone 30071088Sjasone/* 30171088Sjasone * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 30271088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 30371088Sjasone * expires. 30471088Sjasone */ 30571088Sjasoneint 30671088Sjasonecv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 30771088Sjasone{ 30871088Sjasone struct proc *p; 30971088Sjasone int rval; 31071088Sjasone WITNESS_SAVE_DECL(mp); 31171088Sjasone 31271088Sjasone p = CURPROC; 31371088Sjasone rval = 0; 31471088Sjasone#ifdef KTRACE 31571088Sjasone if (p && KTRPOINT(p, KTR_CSW)) 31671088Sjasone ktrcsw(p->p_tracep, 1, 0); 31771088Sjasone#endif 31871088Sjasone CV_ASSERT(cvp, mp, p); 31971088Sjasone WITNESS_SLEEP(0, mp); 32071088Sjasone WITNESS_SAVE(mp, mp); 32171088Sjasone 32272200Sbmilekic mtx_lock_spin(&sched_lock); 32371088Sjasone if (cold || panicstr) { 32471088Sjasone /* 32571088Sjasone * After a panic, or during autoconfiguration, just give 32671088Sjasone * interrupts a chance, then just return; don't run any other 32771088Sjasone * procs or panic below, in case this is the idle process and 32871088Sjasone * already asleep. 32971088Sjasone */ 33072200Sbmilekic mtx_unlock_spin(&sched_lock); 33171088Sjasone return 0; 33271088Sjasone } 33371088Sjasone CV_WAIT_VALIDATE(cvp, mp); 33471088Sjasone 33571088Sjasone DROP_GIANT_NOSWITCH(); 33672200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 33771088Sjasone 33871088Sjasone cv_waitq_add(cvp, p); 33971088Sjasone callout_reset(&p->p_slpcallout, timo, cv_timedwait_end, p); 34071088Sjasone cv_switch(p); 34171088Sjasone curpriority = p->p_usrpri; 34271088Sjasone 34371557Sjhb if (p->p_sflag & PS_TIMEOUT) { 34471557Sjhb p->p_sflag &= ~PS_TIMEOUT; 34571088Sjasone rval = EWOULDBLOCK; 34671088Sjasone } else 34771088Sjasone callout_stop(&p->p_slpcallout); 34871088Sjasone 34972200Sbmilekic mtx_unlock_spin(&sched_lock); 35071088Sjasone#ifdef KTRACE 35171088Sjasone if (KTRPOINT(p, KTR_CSW)) 35271088Sjasone ktrcsw(p->p_tracep, 0, 0); 35371088Sjasone#endif 35471088Sjasone PICKUP_GIANT(); 35572200Sbmilekic mtx_lock(mp); 35671088Sjasone WITNESS_RESTORE(mp, mp); 35771088Sjasone 35871088Sjasone return (rval); 35971088Sjasone} 36071088Sjasone 36171088Sjasone/* 36271088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing 36371088Sjasone * interruption by signals. Returns 0 if the process was resumed by cv_signal 36471088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 36571088Sjasone * a signal was caught. 36671088Sjasone */ 36771088Sjasoneint 36871088Sjasonecv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 36971088Sjasone{ 37071088Sjasone struct proc *p; 37171088Sjasone int rval; 37271088Sjasone int sig; 37371088Sjasone WITNESS_SAVE_DECL(mp); 37471088Sjasone 37571088Sjasone p = CURPROC; 37671088Sjasone rval = 0; 37771088Sjasone#ifdef KTRACE 37871088Sjasone if (p && KTRPOINT(p, KTR_CSW)) 37971088Sjasone ktrcsw(p->p_tracep, 1, 0); 38071088Sjasone#endif 38171088Sjasone CV_ASSERT(cvp, mp, p); 38271088Sjasone WITNESS_SLEEP(0, mp); 38371088Sjasone WITNESS_SAVE(mp, mp); 38471088Sjasone 38572200Sbmilekic mtx_lock_spin(&sched_lock); 38671088Sjasone if (cold || panicstr) { 38771088Sjasone /* 38871088Sjasone * After a panic, or during autoconfiguration, just give 38971088Sjasone * interrupts a chance, then just return; don't run any other 39071088Sjasone * procs or panic below, in case this is the idle process and 39171088Sjasone * already asleep. 39271088Sjasone */ 39372200Sbmilekic mtx_unlock_spin(&sched_lock); 39471088Sjasone return 0; 39571088Sjasone } 39671088Sjasone CV_WAIT_VALIDATE(cvp, mp); 39771088Sjasone 39871088Sjasone DROP_GIANT_NOSWITCH(); 39972200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 40071088Sjasone 40171088Sjasone cv_waitq_add(cvp, p); 40271088Sjasone callout_reset(&p->p_slpcallout, timo, cv_timedwait_end, p); 40371088Sjasone sig = cv_switch_catch(p); 40471088Sjasone curpriority = p->p_usrpri; 40571088Sjasone 40671557Sjhb if (p->p_sflag & PS_TIMEOUT) { 40771557Sjhb p->p_sflag &= ~PS_TIMEOUT; 40871088Sjasone rval = EWOULDBLOCK; 40971088Sjasone } else 41071088Sjasone callout_stop(&p->p_slpcallout); 41171088Sjasone 41272200Sbmilekic mtx_unlock_spin(&sched_lock); 41371088Sjasone PICKUP_GIANT(); 41471088Sjasone 41571088Sjasone /* proc_lock(p); */ 41671088Sjasone if (sig == 0) 41771088Sjasone sig = CURSIG(p); 41871088Sjasone if (sig != 0) { 41971088Sjasone if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) 42071088Sjasone rval = EINTR; 42171088Sjasone else 42271088Sjasone rval = ERESTART; 42371088Sjasone } 42471088Sjasone /* proc_unlock(p); */ 42571088Sjasone 42671088Sjasone#ifdef KTRACE 42771088Sjasone if (KTRPOINT(p, KTR_CSW)) 42871088Sjasone ktrcsw(p->p_tracep, 0, 0); 42971088Sjasone#endif 43072200Sbmilekic mtx_lock(mp); 43171088Sjasone WITNESS_RESTORE(mp, mp); 43271088Sjasone 43371088Sjasone return (rval); 43471088Sjasone} 43571088Sjasone 43671088Sjasone/* 43771088Sjasone * Common code for signal and broadcast. Assumes waitq is not empty. Must be 43871088Sjasone * called with sched_lock held. 43971088Sjasone */ 44071088Sjasonestatic __inline void 44171088Sjasonecv_wakeup(struct cv *cvp) 44271088Sjasone{ 44371088Sjasone struct proc *p; 44471088Sjasone 44571557Sjhb mtx_assert(&sched_lock, MA_OWNED); 44671088Sjasone p = TAILQ_FIRST(&cvp->cv_waitq); 44771088Sjasone KASSERT(p->p_wchan == cvp, ("%s: bogus wchan", __FUNCTION__)); 44871557Sjhb KASSERT(p->p_sflag & PS_CVWAITQ, ("%s: not on waitq", __FUNCTION__)); 44971088Sjasone TAILQ_REMOVE(&cvp->cv_waitq, p, p_slpq); 45071557Sjhb p->p_sflag &= ~PS_CVWAITQ; 45171088Sjasone p->p_wchan = 0; 45271088Sjasone if (p->p_stat == SSLEEP) { 45371088Sjasone /* OPTIMIZED EXPANSION OF setrunnable(p); */ 45471088Sjasone CTR3(KTR_PROC, "cv_signal: proc %p (pid %d, %s)", 45571088Sjasone p, p->p_pid, p->p_comm); 45671088Sjasone if (p->p_slptime > 1) 45771088Sjasone updatepri(p); 45871088Sjasone p->p_slptime = 0; 45971088Sjasone p->p_stat = SRUN; 46071557Sjhb if (p->p_sflag & PS_INMEM) { 46171088Sjasone setrunqueue(p); 46271088Sjasone maybe_resched(p); 46371088Sjasone } else { 46471557Sjhb p->p_sflag |= PS_SWAPINREQ; 46571088Sjasone wakeup(&proc0); 46671088Sjasone } 46771088Sjasone /* END INLINE EXPANSION */ 46871088Sjasone } 46971088Sjasone} 47071088Sjasone 47171088Sjasone/* 47271088Sjasone * Signal a condition variable, wakes up one waiting process. Will also wakeup 47371088Sjasone * the swapper if the process is not in memory, so that it can bring the 47471088Sjasone * sleeping process in. Note that this may also result in additional processes 47571088Sjasone * being made runnable. Should be called with the same mutex as was passed to 47671088Sjasone * cv_wait held. 47771088Sjasone */ 47871088Sjasonevoid 47971088Sjasonecv_signal(struct cv *cvp) 48071088Sjasone{ 48171088Sjasone 48271088Sjasone KASSERT(cvp != NULL, ("%s: cvp NULL", __FUNCTION__)); 48372200Sbmilekic mtx_lock_spin(&sched_lock); 48471088Sjasone if (!TAILQ_EMPTY(&cvp->cv_waitq)) { 48571088Sjasone CV_SIGNAL_VALIDATE(cvp); 48671088Sjasone cv_wakeup(cvp); 48771088Sjasone } 48872200Sbmilekic mtx_unlock_spin(&sched_lock); 48971088Sjasone} 49071088Sjasone 49171088Sjasone/* 49271088Sjasone * Broadcast a signal to a condition variable. Wakes up all waiting processes. 49371088Sjasone * Should be called with the same mutex as was passed to cv_wait held. 49471088Sjasone */ 49571088Sjasonevoid 49671088Sjasonecv_broadcast(struct cv *cvp) 49771088Sjasone{ 49871088Sjasone 49971088Sjasone KASSERT(cvp != NULL, ("%s: cvp NULL", __FUNCTION__)); 50072200Sbmilekic mtx_lock_spin(&sched_lock); 50171088Sjasone CV_SIGNAL_VALIDATE(cvp); 50271088Sjasone while (!TAILQ_EMPTY(&cvp->cv_waitq)) 50371088Sjasone cv_wakeup(cvp); 50472200Sbmilekic mtx_unlock_spin(&sched_lock); 50571088Sjasone} 50671088Sjasone 50771088Sjasone/* 50871088Sjasone * Remove a process from the wait queue of its condition variable. This may be 50971088Sjasone * called externally. 51071088Sjasone */ 51171088Sjasonevoid 51271088Sjasonecv_waitq_remove(struct proc *p) 51371088Sjasone{ 51471088Sjasone struct cv *cvp; 51571088Sjasone 51672200Sbmilekic mtx_lock_spin(&sched_lock); 51771557Sjhb if ((cvp = p->p_wchan) != NULL && p->p_sflag & PS_CVWAITQ) { 51871088Sjasone TAILQ_REMOVE(&cvp->cv_waitq, p, p_slpq); 51971557Sjhb p->p_sflag &= ~PS_CVWAITQ; 52071088Sjasone p->p_wchan = NULL; 52171088Sjasone } 52272200Sbmilekic mtx_unlock_spin(&sched_lock); 52371088Sjasone} 52471088Sjasone 52571088Sjasone/* 52671088Sjasone * Timeout function for cv_timedwait. Put the process on the runqueue and set 52771088Sjasone * its timeout flag. 52871088Sjasone */ 52971088Sjasonestatic void 53071088Sjasonecv_timedwait_end(void *arg) 53171088Sjasone{ 53271088Sjasone struct proc *p; 53371088Sjasone 53471088Sjasone p = arg; 53571088Sjasone CTR3(KTR_PROC, "cv_timedwait_end: proc %p (pid %d, %s)", p, p->p_pid, 53671088Sjasone p->p_comm); 53772200Sbmilekic mtx_lock_spin(&sched_lock); 53871088Sjasone if (p->p_wchan != NULL) { 53971088Sjasone if (p->p_stat == SSLEEP) 54071088Sjasone setrunnable(p); 54171088Sjasone else 54271088Sjasone cv_waitq_remove(p); 54371557Sjhb p->p_sflag |= PS_TIMEOUT; 54471088Sjasone } 54572200Sbmilekic mtx_unlock_spin(&sched_lock); 54671088Sjasone} 547