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