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