kern_condvar.c revision 74912
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 74912 2001-03-28 09:03:24Z jhb $ 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; 17472376Sjake p->p_pri.pri_native = p->p_pri.pri_level; 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); 20074912Sjhb WITNESS_SAVE(&mp->mtx_object, 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 22172200Sbmilekic mtx_unlock_spin(&sched_lock); 22271088Sjasone#ifdef KTRACE 22371088Sjasone if (KTRPOINT(p, KTR_CSW)) 22471088Sjasone ktrcsw(p->p_tracep, 0, 0); 22571088Sjasone#endif 22671088Sjasone PICKUP_GIANT(); 22772200Sbmilekic mtx_lock(mp); 22874912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 22971088Sjasone} 23071088Sjasone 23171088Sjasone/* 23271088Sjasone * Wait on a condition variable, allowing interruption by signals. Return 0 if 23371088Sjasone * the process was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if 23471088Sjasone * a signal was caught. If ERESTART is returned the system call should be 23571088Sjasone * restarted if possible. 23671088Sjasone */ 23771088Sjasoneint 23871088Sjasonecv_wait_sig(struct cv *cvp, struct mtx *mp) 23971088Sjasone{ 24071088Sjasone struct proc *p; 24171088Sjasone int rval; 24271088Sjasone int sig; 24371088Sjasone WITNESS_SAVE_DECL(mp); 24471088Sjasone 24571088Sjasone p = CURPROC; 24671088Sjasone rval = 0; 24771088Sjasone#ifdef KTRACE 24871088Sjasone if (p && KTRPOINT(p, KTR_CSW)) 24971088Sjasone ktrcsw(p->p_tracep, 1, 0); 25071088Sjasone#endif 25171088Sjasone CV_ASSERT(cvp, mp, p); 25271088Sjasone WITNESS_SLEEP(0, mp); 25374912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 25471088Sjasone 25572200Sbmilekic mtx_lock_spin(&sched_lock); 25671088Sjasone if (cold || panicstr) { 25771088Sjasone /* 25871088Sjasone * After a panic, or during autoconfiguration, just give 25971088Sjasone * interrupts a chance, then just return; don't run any other 26071088Sjasone * procs or panic below, in case this is the idle process and 26171088Sjasone * already asleep. 26271088Sjasone */ 26372200Sbmilekic mtx_unlock_spin(&sched_lock); 26471088Sjasone return 0; 26571088Sjasone } 26671088Sjasone CV_WAIT_VALIDATE(cvp, mp); 26771088Sjasone 26871088Sjasone DROP_GIANT_NOSWITCH(); 26972200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 27071088Sjasone 27171088Sjasone cv_waitq_add(cvp, p); 27271088Sjasone sig = cv_switch_catch(p); 27371088Sjasone 27472200Sbmilekic mtx_unlock_spin(&sched_lock); 27571088Sjasone PICKUP_GIANT(); 27671088Sjasone 27771088Sjasone if (sig == 0) 27871088Sjasone sig = CURSIG(p); 27971088Sjasone if (sig != 0) { 28073925Sjhb PROC_LOCK(p); 28171088Sjasone if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) 28271088Sjasone rval = EINTR; 28371088Sjasone else 28471088Sjasone rval = ERESTART; 28573925Sjhb PROC_UNLOCK(p); 28671088Sjasone } 28771088Sjasone 28871088Sjasone#ifdef KTRACE 28971088Sjasone if (KTRPOINT(p, KTR_CSW)) 29071088Sjasone ktrcsw(p->p_tracep, 0, 0); 29171088Sjasone#endif 29272200Sbmilekic mtx_lock(mp); 29374912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 29471088Sjasone 29571088Sjasone return (rval); 29671088Sjasone} 29771088Sjasone 29871088Sjasone/* 29971088Sjasone * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the 30071088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout 30171088Sjasone * expires. 30271088Sjasone */ 30371088Sjasoneint 30471088Sjasonecv_timedwait(struct cv *cvp, struct mtx *mp, int timo) 30571088Sjasone{ 30671088Sjasone struct proc *p; 30771088Sjasone int rval; 30871088Sjasone WITNESS_SAVE_DECL(mp); 30971088Sjasone 31071088Sjasone p = CURPROC; 31171088Sjasone rval = 0; 31271088Sjasone#ifdef KTRACE 31371088Sjasone if (p && KTRPOINT(p, KTR_CSW)) 31471088Sjasone ktrcsw(p->p_tracep, 1, 0); 31571088Sjasone#endif 31671088Sjasone CV_ASSERT(cvp, mp, p); 31771088Sjasone WITNESS_SLEEP(0, mp); 31874912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 31971088Sjasone 32072200Sbmilekic mtx_lock_spin(&sched_lock); 32171088Sjasone if (cold || panicstr) { 32271088Sjasone /* 32371088Sjasone * After a panic, or during autoconfiguration, just give 32471088Sjasone * interrupts a chance, then just return; don't run any other 32571088Sjasone * procs or panic below, in case this is the idle process and 32671088Sjasone * already asleep. 32771088Sjasone */ 32872200Sbmilekic mtx_unlock_spin(&sched_lock); 32971088Sjasone return 0; 33071088Sjasone } 33171088Sjasone CV_WAIT_VALIDATE(cvp, mp); 33271088Sjasone 33371088Sjasone DROP_GIANT_NOSWITCH(); 33472200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 33571088Sjasone 33671088Sjasone cv_waitq_add(cvp, p); 33771088Sjasone callout_reset(&p->p_slpcallout, timo, cv_timedwait_end, p); 33871088Sjasone cv_switch(p); 33971088Sjasone 34071557Sjhb if (p->p_sflag & PS_TIMEOUT) { 34171557Sjhb p->p_sflag &= ~PS_TIMEOUT; 34271088Sjasone rval = EWOULDBLOCK; 34371088Sjasone } else 34471088Sjasone callout_stop(&p->p_slpcallout); 34571088Sjasone 34672200Sbmilekic mtx_unlock_spin(&sched_lock); 34771088Sjasone#ifdef KTRACE 34871088Sjasone if (KTRPOINT(p, KTR_CSW)) 34971088Sjasone ktrcsw(p->p_tracep, 0, 0); 35071088Sjasone#endif 35171088Sjasone PICKUP_GIANT(); 35272200Sbmilekic mtx_lock(mp); 35374912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 35471088Sjasone 35571088Sjasone return (rval); 35671088Sjasone} 35771088Sjasone 35871088Sjasone/* 35971088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing 36071088Sjasone * interruption by signals. Returns 0 if the process was resumed by cv_signal 36171088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if 36271088Sjasone * a signal was caught. 36371088Sjasone */ 36471088Sjasoneint 36571088Sjasonecv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo) 36671088Sjasone{ 36771088Sjasone struct proc *p; 36871088Sjasone int rval; 36971088Sjasone int sig; 37071088Sjasone WITNESS_SAVE_DECL(mp); 37171088Sjasone 37271088Sjasone p = CURPROC; 37371088Sjasone rval = 0; 37471088Sjasone#ifdef KTRACE 37571088Sjasone if (p && KTRPOINT(p, KTR_CSW)) 37671088Sjasone ktrcsw(p->p_tracep, 1, 0); 37771088Sjasone#endif 37871088Sjasone CV_ASSERT(cvp, mp, p); 37971088Sjasone WITNESS_SLEEP(0, mp); 38074912Sjhb WITNESS_SAVE(&mp->mtx_object, mp); 38171088Sjasone 38272200Sbmilekic mtx_lock_spin(&sched_lock); 38371088Sjasone if (cold || panicstr) { 38471088Sjasone /* 38571088Sjasone * After a panic, or during autoconfiguration, just give 38671088Sjasone * interrupts a chance, then just return; don't run any other 38771088Sjasone * procs or panic below, in case this is the idle process and 38871088Sjasone * already asleep. 38971088Sjasone */ 39072200Sbmilekic mtx_unlock_spin(&sched_lock); 39171088Sjasone return 0; 39271088Sjasone } 39371088Sjasone CV_WAIT_VALIDATE(cvp, mp); 39471088Sjasone 39571088Sjasone DROP_GIANT_NOSWITCH(); 39672200Sbmilekic mtx_unlock_flags(mp, MTX_NOSWITCH); 39771088Sjasone 39871088Sjasone cv_waitq_add(cvp, p); 39971088Sjasone callout_reset(&p->p_slpcallout, timo, cv_timedwait_end, p); 40071088Sjasone sig = cv_switch_catch(p); 40171088Sjasone 40271557Sjhb if (p->p_sflag & PS_TIMEOUT) { 40371557Sjhb p->p_sflag &= ~PS_TIMEOUT; 40471088Sjasone rval = EWOULDBLOCK; 40571088Sjasone } else 40671088Sjasone callout_stop(&p->p_slpcallout); 40771088Sjasone 40872200Sbmilekic mtx_unlock_spin(&sched_lock); 40971088Sjasone PICKUP_GIANT(); 41071088Sjasone 41171088Sjasone if (sig == 0) 41271088Sjasone sig = CURSIG(p); 41371088Sjasone if (sig != 0) { 41473925Sjhb PROC_LOCK(p); 41571088Sjasone if (SIGISMEMBER(p->p_sigacts->ps_sigintr, sig)) 41671088Sjasone rval = EINTR; 41771088Sjasone else 41871088Sjasone rval = ERESTART; 41973925Sjhb PROC_UNLOCK(p); 42071088Sjasone } 42171088Sjasone 42271088Sjasone#ifdef KTRACE 42371088Sjasone if (KTRPOINT(p, KTR_CSW)) 42471088Sjasone ktrcsw(p->p_tracep, 0, 0); 42571088Sjasone#endif 42672200Sbmilekic mtx_lock(mp); 42774912Sjhb WITNESS_RESTORE(&mp->mtx_object, mp); 42871088Sjasone 42971088Sjasone return (rval); 43071088Sjasone} 43171088Sjasone 43271088Sjasone/* 43371088Sjasone * Common code for signal and broadcast. Assumes waitq is not empty. Must be 43471088Sjasone * called with sched_lock held. 43571088Sjasone */ 43671088Sjasonestatic __inline void 43771088Sjasonecv_wakeup(struct cv *cvp) 43871088Sjasone{ 43971088Sjasone struct proc *p; 44071088Sjasone 44171557Sjhb mtx_assert(&sched_lock, MA_OWNED); 44271088Sjasone p = TAILQ_FIRST(&cvp->cv_waitq); 44371088Sjasone KASSERT(p->p_wchan == cvp, ("%s: bogus wchan", __FUNCTION__)); 44471557Sjhb KASSERT(p->p_sflag & PS_CVWAITQ, ("%s: not on waitq", __FUNCTION__)); 44571088Sjasone TAILQ_REMOVE(&cvp->cv_waitq, p, p_slpq); 44671557Sjhb p->p_sflag &= ~PS_CVWAITQ; 44771088Sjasone p->p_wchan = 0; 44871088Sjasone if (p->p_stat == SSLEEP) { 44971088Sjasone /* OPTIMIZED EXPANSION OF setrunnable(p); */ 45071088Sjasone CTR3(KTR_PROC, "cv_signal: proc %p (pid %d, %s)", 45171088Sjasone p, p->p_pid, p->p_comm); 45271088Sjasone if (p->p_slptime > 1) 45371088Sjasone updatepri(p); 45471088Sjasone p->p_slptime = 0; 45571088Sjasone p->p_stat = SRUN; 45671557Sjhb if (p->p_sflag & PS_INMEM) { 45771088Sjasone setrunqueue(p); 45871088Sjasone maybe_resched(p); 45971088Sjasone } else { 46071557Sjhb p->p_sflag |= PS_SWAPINREQ; 46171088Sjasone wakeup(&proc0); 46271088Sjasone } 46371088Sjasone /* END INLINE EXPANSION */ 46471088Sjasone } 46571088Sjasone} 46671088Sjasone 46771088Sjasone/* 46871088Sjasone * Signal a condition variable, wakes up one waiting process. Will also wakeup 46971088Sjasone * the swapper if the process is not in memory, so that it can bring the 47071088Sjasone * sleeping process in. Note that this may also result in additional processes 47171088Sjasone * being made runnable. Should be called with the same mutex as was passed to 47271088Sjasone * cv_wait held. 47371088Sjasone */ 47471088Sjasonevoid 47571088Sjasonecv_signal(struct cv *cvp) 47671088Sjasone{ 47771088Sjasone 47871088Sjasone KASSERT(cvp != NULL, ("%s: cvp NULL", __FUNCTION__)); 47972200Sbmilekic mtx_lock_spin(&sched_lock); 48071088Sjasone if (!TAILQ_EMPTY(&cvp->cv_waitq)) { 48171088Sjasone CV_SIGNAL_VALIDATE(cvp); 48271088Sjasone cv_wakeup(cvp); 48371088Sjasone } 48472200Sbmilekic mtx_unlock_spin(&sched_lock); 48571088Sjasone} 48671088Sjasone 48771088Sjasone/* 48871088Sjasone * Broadcast a signal to a condition variable. Wakes up all waiting processes. 48971088Sjasone * Should be called with the same mutex as was passed to cv_wait held. 49071088Sjasone */ 49171088Sjasonevoid 49271088Sjasonecv_broadcast(struct cv *cvp) 49371088Sjasone{ 49471088Sjasone 49571088Sjasone KASSERT(cvp != NULL, ("%s: cvp NULL", __FUNCTION__)); 49672200Sbmilekic mtx_lock_spin(&sched_lock); 49771088Sjasone CV_SIGNAL_VALIDATE(cvp); 49871088Sjasone while (!TAILQ_EMPTY(&cvp->cv_waitq)) 49971088Sjasone cv_wakeup(cvp); 50072200Sbmilekic mtx_unlock_spin(&sched_lock); 50171088Sjasone} 50271088Sjasone 50371088Sjasone/* 50471088Sjasone * Remove a process from the wait queue of its condition variable. This may be 50571088Sjasone * called externally. 50671088Sjasone */ 50771088Sjasonevoid 50871088Sjasonecv_waitq_remove(struct proc *p) 50971088Sjasone{ 51071088Sjasone struct cv *cvp; 51171088Sjasone 51272200Sbmilekic mtx_lock_spin(&sched_lock); 51371557Sjhb if ((cvp = p->p_wchan) != NULL && p->p_sflag & PS_CVWAITQ) { 51471088Sjasone TAILQ_REMOVE(&cvp->cv_waitq, p, p_slpq); 51571557Sjhb p->p_sflag &= ~PS_CVWAITQ; 51671088Sjasone p->p_wchan = NULL; 51771088Sjasone } 51872200Sbmilekic mtx_unlock_spin(&sched_lock); 51971088Sjasone} 52071088Sjasone 52171088Sjasone/* 52271088Sjasone * Timeout function for cv_timedwait. Put the process on the runqueue and set 52371088Sjasone * its timeout flag. 52471088Sjasone */ 52571088Sjasonestatic void 52671088Sjasonecv_timedwait_end(void *arg) 52771088Sjasone{ 52871088Sjasone struct proc *p; 52971088Sjasone 53071088Sjasone p = arg; 53171088Sjasone CTR3(KTR_PROC, "cv_timedwait_end: proc %p (pid %d, %s)", p, p->p_pid, 53271088Sjasone p->p_comm); 53372200Sbmilekic mtx_lock_spin(&sched_lock); 53471088Sjasone if (p->p_wchan != NULL) { 53571088Sjasone if (p->p_stat == SSLEEP) 53671088Sjasone setrunnable(p); 53771088Sjasone else 53871088Sjasone cv_waitq_remove(p); 53971557Sjhb p->p_sflag |= PS_TIMEOUT; 54071088Sjasone } 54172200Sbmilekic mtx_unlock_spin(&sched_lock); 54271088Sjasone} 543