kern_condvar.c revision 126885
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
27116182Sobrien#include <sys/cdefs.h>
28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_condvar.c 126885 2004-03-12 19:06:18Z jhb $");
29116182Sobrien
3071088Sjasone#include "opt_ktrace.h"
3171088Sjasone
3271088Sjasone#include <sys/param.h>
3371088Sjasone#include <sys/systm.h>
3476166Smarkm#include <sys/lock.h>
3576166Smarkm#include <sys/mutex.h>
3671088Sjasone#include <sys/proc.h>
3771088Sjasone#include <sys/kernel.h>
3871088Sjasone#include <sys/ktr.h>
3971088Sjasone#include <sys/condvar.h>
40109862Sjeff#include <sys/sched.h>
4171088Sjasone#include <sys/signalvar.h>
42126326Sjhb#include <sys/sleepqueue.h>
4371088Sjasone#include <sys/resourcevar.h>
4471088Sjasone#ifdef KTRACE
4571088Sjasone#include <sys/uio.h>
4671088Sjasone#include <sys/ktrace.h>
4771088Sjasone#endif
4871088Sjasone
4971088Sjasone/*
5071088Sjasone * Common sanity checks for cv_wait* functions.
5171088Sjasone */
5283366Sjulian#define	CV_ASSERT(cvp, mp, td) do {					\
5387594Sobrien	KASSERT((td) != NULL, ("%s: curthread NULL", __func__));	\
54103216Sjulian	KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__));	\
5587594Sobrien	KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__));		\
5687594Sobrien	KASSERT((mp) != NULL, ("%s: mp NULL", __func__));		\
5771088Sjasone	mtx_assert((mp), MA_OWNED | MA_NOTRECURSED);			\
5871088Sjasone} while (0)
5971088Sjasone
6071088Sjasone/*
6171088Sjasone * Initialize a condition variable.  Must be called before use.
6271088Sjasone */
6371088Sjasonevoid
6471088Sjasonecv_init(struct cv *cvp, const char *desc)
6571088Sjasone{
6671088Sjasone
6771088Sjasone	cvp->cv_description = desc;
6871088Sjasone}
6971088Sjasone
7071088Sjasone/*
7171088Sjasone * Destroy a condition variable.  The condition variable must be re-initialized
7271088Sjasone * in order to be re-used.
7371088Sjasone */
7471088Sjasonevoid
7571088Sjasonecv_destroy(struct cv *cvp)
7671088Sjasone{
77126326Sjhb#ifdef INVARIANTS
78126326Sjhb	struct sleepqueue *sq;
7971088Sjasone
80126326Sjhb	sq = sleepq_lookup(cvp);
81126326Sjhb	sleepq_release(cvp);
82126326Sjhb	KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__));
83126326Sjhb#endif
8471088Sjasone}
8571088Sjasone
8671088Sjasone/*
8783366Sjulian * Wait on a condition variable.  The current thread is placed on the condition
8871088Sjasone * variable's wait queue and suspended.  A cv_signal or cv_broadcast on the same
8983366Sjulian * condition variable will resume the thread.  The mutex is released before
9071088Sjasone * sleeping and will be held on return.  It is recommended that the mutex be
9171088Sjasone * held when cv_signal or cv_broadcast are called.
9271088Sjasone */
9371088Sjasonevoid
9471088Sjasonecv_wait(struct cv *cvp, struct mtx *mp)
9571088Sjasone{
96126326Sjhb	struct sleepqueue *sq;
9783366Sjulian	struct thread *td;
9871088Sjasone	WITNESS_SAVE_DECL(mp);
9971088Sjasone
10083366Sjulian	td = curthread;
10171088Sjasone#ifdef KTRACE
10297995Sjhb	if (KTRPOINT(td, KTR_CSW))
10397995Sjhb		ktrcsw(1, 0);
10471088Sjasone#endif
10583366Sjulian	CV_ASSERT(cvp, mp, td);
106111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
107111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
10874912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
10971088Sjasone
110126326Sjhb	if (cold || panicstr) {
11171088Sjasone		/*
112100209Sgallatin		 * During autoconfiguration, just give interrupts
113100209Sgallatin		 * a chance, then just return.  Don't run any other
114100209Sgallatin		 * thread or panic below, in case this is the idle
115100209Sgallatin		 * process and already asleep.
11671088Sjasone		 */
11771088Sjasone		return;
11871088Sjasone	}
11995322Shsu
120126326Sjhb	sq = sleepq_lookup(cvp);
12195322Shsu
12288900Sjhb	DROP_GIANT();
12388900Sjhb	mtx_unlock(mp);
12471088Sjasone
125126326Sjhb	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
126126326Sjhb	sleepq_wait(cvp);
12771088Sjasone
12871088Sjasone#ifdef KTRACE
12997995Sjhb	if (KTRPOINT(td, KTR_CSW))
13097995Sjhb		ktrcsw(0, 0);
13171088Sjasone#endif
13271088Sjasone	PICKUP_GIANT();
13372200Sbmilekic	mtx_lock(mp);
13474912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
13571088Sjasone}
13671088Sjasone
13771088Sjasone/*
13871088Sjasone * Wait on a condition variable, allowing interruption by signals.  Return 0 if
13983366Sjulian * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
14071088Sjasone * a signal was caught.  If ERESTART is returned the system call should be
14171088Sjasone * restarted if possible.
14271088Sjasone */
14371088Sjasoneint
14471088Sjasonecv_wait_sig(struct cv *cvp, struct mtx *mp)
14571088Sjasone{
146126326Sjhb	struct sleepqueue *sq;
14783366Sjulian	struct thread *td;
14883658Speter	struct proc *p;
149126326Sjhb	int rval, sig;
15071088Sjasone	WITNESS_SAVE_DECL(mp);
15171088Sjasone
15283366Sjulian	td = curthread;
15383650Sjhb	p = td->td_proc;
15471088Sjasone	rval = 0;
15571088Sjasone#ifdef KTRACE
15697995Sjhb	if (KTRPOINT(td, KTR_CSW))
15797995Sjhb		ktrcsw(1, 0);
15871088Sjasone#endif
15983366Sjulian	CV_ASSERT(cvp, mp, td);
160111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
161111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
16274912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
16371088Sjasone
16471088Sjasone	if (cold || panicstr) {
16571088Sjasone		/*
16671088Sjasone		 * After a panic, or during autoconfiguration, just give
16771088Sjasone		 * interrupts a chance, then just return; don't run any other
16871088Sjasone		 * procs or panic below, in case this is the idle process and
16971088Sjasone		 * already asleep.
17071088Sjasone		 */
17171088Sjasone		return 0;
17271088Sjasone	}
17395322Shsu
174126326Sjhb	sq = sleepq_lookup(cvp);
17595322Shsu
176126326Sjhb	/* XXX: Missing the threading checks from msleep! */
17771088Sjasone
17888900Sjhb	DROP_GIANT();
17988900Sjhb	mtx_unlock(mp);
18071088Sjasone
181126326Sjhb	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
182126326Sjhb	sig = sleepq_catch_signals(cvp);
183126326Sjhb	/*
184126326Sjhb	 * XXX: Missing magic return value handling for no signal
185126326Sjhb	 * caught but thread woken up during check.
186126326Sjhb	 */
187126326Sjhb	rval = sleepq_wait_sig(cvp);
188126326Sjhb	if (rval == 0)
189126326Sjhb		rval = sleepq_calc_signal_retval(sig);
19071088Sjasone
191126326Sjhb	/* XXX: Part of missing threading checks? */
19283650Sjhb	PROC_LOCK(p);
19399072Sjulian	if (p->p_flag & P_WEXIT)
19499072Sjulian		rval = EINTR;
195113625Sjhb	PROC_UNLOCK(p);
19671088Sjasone
19771088Sjasone#ifdef KTRACE
19897995Sjhb	if (KTRPOINT(td, KTR_CSW))
19997995Sjhb		ktrcsw(0, 0);
20071088Sjasone#endif
20197995Sjhb	PICKUP_GIANT();
20272200Sbmilekic	mtx_lock(mp);
20374912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
20471088Sjasone
20571088Sjasone	return (rval);
20671088Sjasone}
20771088Sjasone
20871088Sjasone/*
20971088Sjasone * Wait on a condition variable for at most timo/hz seconds.  Returns 0 if the
21071088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout
21171088Sjasone * expires.
21271088Sjasone */
21371088Sjasoneint
21471088Sjasonecv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
21571088Sjasone{
216126326Sjhb	struct sleepqueue *sq;
21783366Sjulian	struct thread *td;
21871088Sjasone	int rval;
21971088Sjasone	WITNESS_SAVE_DECL(mp);
22071088Sjasone
22183366Sjulian	td = curthread;
22271088Sjasone	rval = 0;
22371088Sjasone#ifdef KTRACE
22497995Sjhb	if (KTRPOINT(td, KTR_CSW))
22597995Sjhb		ktrcsw(1, 0);
22671088Sjasone#endif
22783366Sjulian	CV_ASSERT(cvp, mp, td);
228111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
229111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
23074912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
23171088Sjasone
23271088Sjasone	if (cold || panicstr) {
23371088Sjasone		/*
23471088Sjasone		 * After a panic, or during autoconfiguration, just give
23571088Sjasone		 * interrupts a chance, then just return; don't run any other
23683366Sjulian		 * thread or panic below, in case this is the idle process and
23771088Sjasone		 * already asleep.
23871088Sjasone		 */
23971088Sjasone		return 0;
24071088Sjasone	}
24195322Shsu
242126326Sjhb	sq = sleepq_lookup(cvp);
24395322Shsu
24488900Sjhb	DROP_GIANT();
24588900Sjhb	mtx_unlock(mp);
24671088Sjasone
247126326Sjhb	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
248126885Sjhb	sleepq_set_timeout(cvp, timo);
249126326Sjhb	rval = sleepq_timedwait(cvp, 0);
25071088Sjasone
25171088Sjasone#ifdef KTRACE
25297995Sjhb	if (KTRPOINT(td, KTR_CSW))
25397995Sjhb		ktrcsw(0, 0);
25471088Sjasone#endif
25571088Sjasone	PICKUP_GIANT();
25672200Sbmilekic	mtx_lock(mp);
25774912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
25871088Sjasone
25971088Sjasone	return (rval);
26071088Sjasone}
26171088Sjasone
26271088Sjasone/*
26371088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing
26483366Sjulian * interruption by signals.  Returns 0 if the thread was resumed by cv_signal
26571088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if
26671088Sjasone * a signal was caught.
26771088Sjasone */
26871088Sjasoneint
26971088Sjasonecv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
27071088Sjasone{
271126326Sjhb	struct sleepqueue *sq;
27283366Sjulian	struct thread *td;
27383650Sjhb	struct proc *p;
27471088Sjasone	int rval;
27571088Sjasone	int sig;
27671088Sjasone	WITNESS_SAVE_DECL(mp);
27771088Sjasone
27883366Sjulian	td = curthread;
27983650Sjhb	p = td->td_proc;
28071088Sjasone	rval = 0;
28171088Sjasone#ifdef KTRACE
28297995Sjhb	if (KTRPOINT(td, KTR_CSW))
28397995Sjhb		ktrcsw(1, 0);
28471088Sjasone#endif
28583366Sjulian	CV_ASSERT(cvp, mp, td);
286111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
287111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
28874912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
28971088Sjasone
29071088Sjasone	if (cold || panicstr) {
29171088Sjasone		/*
29271088Sjasone		 * After a panic, or during autoconfiguration, just give
29371088Sjasone		 * interrupts a chance, then just return; don't run any other
29483366Sjulian		 * thread or panic below, in case this is the idle process and
29571088Sjasone		 * already asleep.
29671088Sjasone		 */
29771088Sjasone		return 0;
29871088Sjasone	}
29995322Shsu
300126326Sjhb	sq = sleepq_lookup(cvp);
30195322Shsu
30288900Sjhb	DROP_GIANT();
30388900Sjhb	mtx_unlock(mp);
30471088Sjasone
305126326Sjhb	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
306126885Sjhb	sleepq_set_timeout(cvp, timo);
307126326Sjhb	sig = sleepq_catch_signals(cvp);
308126326Sjhb	/*
309126326Sjhb	 * XXX: Missing magic return value handling for no signal
310126326Sjhb	 * caught but thread woken up during check.
311126326Sjhb	 */
312126326Sjhb	rval = sleepq_timedwait_sig(cvp, sig != 0);
313126326Sjhb	if (rval == 0)
314126326Sjhb		rval = sleepq_calc_signal_retval(sig);
31571088Sjasone
316126326Sjhb	/* XXX: Part of missing threading checks? */
31783650Sjhb	PROC_LOCK(p);
31899072Sjulian	if (p->p_flag & P_WEXIT)
31999072Sjulian		rval = EINTR;
320113625Sjhb	PROC_UNLOCK(p);
32199072Sjulian
32271088Sjasone#ifdef KTRACE
32397995Sjhb	if (KTRPOINT(td, KTR_CSW))
32497995Sjhb		ktrcsw(0, 0);
32571088Sjasone#endif
32697995Sjhb	PICKUP_GIANT();
32772200Sbmilekic	mtx_lock(mp);
32874912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
32971088Sjasone
33071088Sjasone	return (rval);
33171088Sjasone}
33271088Sjasone
33371088Sjasone/*
33483366Sjulian * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
33571088Sjasone * the swapper if the process is not in memory, so that it can bring the
33683366Sjulian * sleeping process in.  Note that this may also result in additional threads
33771088Sjasone * being made runnable.  Should be called with the same mutex as was passed to
33871088Sjasone * cv_wait held.
33971088Sjasone */
34071088Sjasonevoid
34171088Sjasonecv_signal(struct cv *cvp)
34271088Sjasone{
34371088Sjasone
344126326Sjhb	sleepq_signal(cvp, SLEEPQ_CONDVAR, -1);
34571088Sjasone}
34671088Sjasone
34771088Sjasone/*
34883366Sjulian * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
34971088Sjasone * Should be called with the same mutex as was passed to cv_wait held.
35071088Sjasone */
35171088Sjasonevoid
352122352Stanimuracv_broadcastpri(struct cv *cvp, int pri)
35371088Sjasone{
35471088Sjasone
355126326Sjhb	sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri);
35671088Sjasone}
357