kern_condvar.c revision 153321
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 153321 2005-12-12 00:02:22Z rodrigc $");
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;
68127954Sjhb	cvp->cv_waiters = 0;
6971088Sjasone}
7071088Sjasone
7171088Sjasone/*
7271088Sjasone * Destroy a condition variable.  The condition variable must be re-initialized
7371088Sjasone * in order to be re-used.
7471088Sjasone */
7571088Sjasonevoid
7671088Sjasonecv_destroy(struct cv *cvp)
7771088Sjasone{
78126326Sjhb#ifdef INVARIANTS
79136445Sjhb	struct sleepqueue *sq;
8071088Sjasone
81136445Sjhb	sleepq_lock(cvp);
82126326Sjhb	sq = sleepq_lookup(cvp);
83126326Sjhb	sleepq_release(cvp);
84126326Sjhb	KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__));
85126326Sjhb#endif
8671088Sjasone}
8771088Sjasone
8871088Sjasone/*
8983366Sjulian * Wait on a condition variable.  The current thread is placed on the condition
9071088Sjasone * variable's wait queue and suspended.  A cv_signal or cv_broadcast on the same
9183366Sjulian * condition variable will resume the thread.  The mutex is released before
9271088Sjasone * sleeping and will be held on return.  It is recommended that the mutex be
9371088Sjasone * held when cv_signal or cv_broadcast are called.
9471088Sjasone */
9571088Sjasonevoid
9671088Sjasonecv_wait(struct cv *cvp, struct mtx *mp)
9771088Sjasone{
9871088Sjasone	WITNESS_SAVE_DECL(mp);
9971088Sjasone
100153321Srodrigc	WITNESS_SAVE(&mp->mtx_object, mp);
101153321Srodrigc
102153321Srodrigc	if (cold || panicstr) {
103153321Srodrigc		/*
104153321Srodrigc		 * During autoconfiguration, just give interrupts
105153321Srodrigc		 * a chance, then just return.  Don't run any other
106153321Srodrigc		 * thread or panic below, in case this is the idle
107153321Srodrigc		 * process and already asleep.
108153321Srodrigc		 */
109153321Srodrigc		return;
110153321Srodrigc	}
111153321Srodrigc
112153321Srodrigc	cv_wait_unlock(cvp, mp);
113153321Srodrigc	mtx_lock(mp);
114153321Srodrigc	WITNESS_RESTORE(&mp->mtx_object, mp);
115153321Srodrigc}
116153321Srodrigc
117153321Srodrigc/*
118153321Srodrigc * Wait on a condition variable.  This function differs from cv_wait by
119153321Srodrigc * not aquiring the mutex after condition variable was signaled.
120153321Srodrigc */
121153321Srodrigcvoid
122153321Srodrigccv_wait_unlock(struct cv *cvp, struct mtx *mp)
123153321Srodrigc{
124153321Srodrigc	struct thread *td;
125153321Srodrigc
12683366Sjulian	td = curthread;
12771088Sjasone#ifdef KTRACE
12897995Sjhb	if (KTRPOINT(td, KTR_CSW))
12997995Sjhb		ktrcsw(1, 0);
13071088Sjasone#endif
13183366Sjulian	CV_ASSERT(cvp, mp, td);
132111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
133111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
13471088Sjasone
135126326Sjhb	if (cold || panicstr) {
13671088Sjasone		/*
137100209Sgallatin		 * During autoconfiguration, just give interrupts
138100209Sgallatin		 * a chance, then just return.  Don't run any other
139100209Sgallatin		 * thread or panic below, in case this is the idle
140100209Sgallatin		 * process and already asleep.
14171088Sjasone		 */
142153321Srodrigc		mtx_unlock(mp);
14371088Sjasone		return;
14471088Sjasone	}
14595322Shsu
146136445Sjhb	sleepq_lock(cvp);
14795322Shsu
148127954Sjhb	cvp->cv_waiters++;
14988900Sjhb	DROP_GIANT();
15088900Sjhb	mtx_unlock(mp);
15171088Sjasone
152136445Sjhb	sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
153126326Sjhb	sleepq_wait(cvp);
15471088Sjasone
15571088Sjasone	PICKUP_GIANT();
15671088Sjasone}
15771088Sjasone
15871088Sjasone/*
15971088Sjasone * Wait on a condition variable, allowing interruption by signals.  Return 0 if
16083366Sjulian * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
16171088Sjasone * a signal was caught.  If ERESTART is returned the system call should be
16271088Sjasone * restarted if possible.
16371088Sjasone */
16471088Sjasoneint
16571088Sjasonecv_wait_sig(struct cv *cvp, struct mtx *mp)
16671088Sjasone{
16783366Sjulian	struct thread *td;
16883658Speter	struct proc *p;
169126326Sjhb	int rval, sig;
17071088Sjasone	WITNESS_SAVE_DECL(mp);
17171088Sjasone
17283366Sjulian	td = curthread;
17383650Sjhb	p = td->td_proc;
17471088Sjasone#ifdef KTRACE
17597995Sjhb	if (KTRPOINT(td, KTR_CSW))
17697995Sjhb		ktrcsw(1, 0);
17771088Sjasone#endif
17883366Sjulian	CV_ASSERT(cvp, mp, td);
179111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
180111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
18174912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
18271088Sjasone
18371088Sjasone	if (cold || panicstr) {
18471088Sjasone		/*
18571088Sjasone		 * After a panic, or during autoconfiguration, just give
18671088Sjasone		 * interrupts a chance, then just return; don't run any other
18771088Sjasone		 * procs or panic below, in case this is the idle process and
18871088Sjasone		 * already asleep.
18971088Sjasone		 */
190133440Sjhb		return (0);
19171088Sjasone	}
19295322Shsu
193136445Sjhb	sleepq_lock(cvp);
19495322Shsu
195133440Sjhb	/*
196133440Sjhb	 * Don't bother sleeping if we are exiting and not the exiting
197133440Sjhb	 * thread or if our thread is marked as interrupted.
198133440Sjhb	 */
199133440Sjhb	mtx_lock_spin(&sched_lock);
200134013Sjhb	rval = thread_sleep_check(td);
201134013Sjhb	mtx_unlock_spin(&sched_lock);
202134013Sjhb	if (rval != 0) {
203134013Sjhb		sleepq_release(cvp);
204134013Sjhb		return (rval);
205133440Sjhb	}
20671088Sjasone
207127954Sjhb	cvp->cv_waiters++;
20888900Sjhb	DROP_GIANT();
20988900Sjhb	mtx_unlock(mp);
21071088Sjasone
211136445Sjhb	sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR |
212134013Sjhb	    SLEEPQ_INTERRUPTIBLE);
213126326Sjhb	sig = sleepq_catch_signals(cvp);
214134013Sjhb	rval = sleepq_wait_sig(cvp);
215126326Sjhb	if (rval == 0)
216126326Sjhb		rval = sleepq_calc_signal_retval(sig);
21771088Sjasone
21871088Sjasone#ifdef KTRACE
21997995Sjhb	if (KTRPOINT(td, KTR_CSW))
22097995Sjhb		ktrcsw(0, 0);
22171088Sjasone#endif
22297995Sjhb	PICKUP_GIANT();
22372200Sbmilekic	mtx_lock(mp);
22474912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
22571088Sjasone
22671088Sjasone	return (rval);
22771088Sjasone}
22871088Sjasone
22971088Sjasone/*
23071088Sjasone * Wait on a condition variable for at most timo/hz seconds.  Returns 0 if the
23171088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout
23271088Sjasone * expires.
23371088Sjasone */
23471088Sjasoneint
23571088Sjasonecv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
23671088Sjasone{
23783366Sjulian	struct thread *td;
23871088Sjasone	int rval;
23971088Sjasone	WITNESS_SAVE_DECL(mp);
24071088Sjasone
24183366Sjulian	td = curthread;
24271088Sjasone	rval = 0;
24371088Sjasone#ifdef KTRACE
24497995Sjhb	if (KTRPOINT(td, KTR_CSW))
24597995Sjhb		ktrcsw(1, 0);
24671088Sjasone#endif
24783366Sjulian	CV_ASSERT(cvp, mp, td);
248111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
249111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
25074912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
25171088Sjasone
25271088Sjasone	if (cold || panicstr) {
25371088Sjasone		/*
25471088Sjasone		 * After a panic, or during autoconfiguration, just give
25571088Sjasone		 * interrupts a chance, then just return; don't run any other
25683366Sjulian		 * thread or panic below, in case this is the idle process and
25771088Sjasone		 * already asleep.
25871088Sjasone		 */
25971088Sjasone		return 0;
26071088Sjasone	}
26195322Shsu
262136445Sjhb	sleepq_lock(cvp);
26395322Shsu
264127954Sjhb	cvp->cv_waiters++;
26588900Sjhb	DROP_GIANT();
26688900Sjhb	mtx_unlock(mp);
26771088Sjasone
268136445Sjhb	sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
269126885Sjhb	sleepq_set_timeout(cvp, timo);
270131249Sjhb	rval = sleepq_timedwait(cvp);
27171088Sjasone
27271088Sjasone#ifdef KTRACE
27397995Sjhb	if (KTRPOINT(td, KTR_CSW))
27497995Sjhb		ktrcsw(0, 0);
27571088Sjasone#endif
27671088Sjasone	PICKUP_GIANT();
27772200Sbmilekic	mtx_lock(mp);
27874912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
27971088Sjasone
28071088Sjasone	return (rval);
28171088Sjasone}
28271088Sjasone
28371088Sjasone/*
28471088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing
28583366Sjulian * interruption by signals.  Returns 0 if the thread was resumed by cv_signal
28671088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if
28771088Sjasone * a signal was caught.
28871088Sjasone */
28971088Sjasoneint
29071088Sjasonecv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
29171088Sjasone{
29283366Sjulian	struct thread *td;
29383650Sjhb	struct proc *p;
29471088Sjasone	int rval;
29571088Sjasone	int sig;
29671088Sjasone	WITNESS_SAVE_DECL(mp);
29771088Sjasone
29883366Sjulian	td = curthread;
29983650Sjhb	p = td->td_proc;
30071088Sjasone	rval = 0;
30171088Sjasone#ifdef KTRACE
30297995Sjhb	if (KTRPOINT(td, KTR_CSW))
30397995Sjhb		ktrcsw(1, 0);
30471088Sjasone#endif
30583366Sjulian	CV_ASSERT(cvp, mp, td);
306111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
307111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
30874912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
30971088Sjasone
31071088Sjasone	if (cold || panicstr) {
31171088Sjasone		/*
31271088Sjasone		 * After a panic, or during autoconfiguration, just give
31371088Sjasone		 * interrupts a chance, then just return; don't run any other
31483366Sjulian		 * thread or panic below, in case this is the idle process and
31571088Sjasone		 * already asleep.
31671088Sjasone		 */
31771088Sjasone		return 0;
31871088Sjasone	}
31995322Shsu
320136445Sjhb	sleepq_lock(cvp);
32195322Shsu
322133440Sjhb	/*
323133440Sjhb	 * Don't bother sleeping if we are exiting and not the exiting
324133440Sjhb	 * thread or if our thread is marked as interrupted.
325133440Sjhb	 */
326133440Sjhb	mtx_lock_spin(&sched_lock);
327134013Sjhb	rval = thread_sleep_check(td);
328134013Sjhb	mtx_unlock_spin(&sched_lock);
329134013Sjhb	if (rval != 0) {
330134013Sjhb		sleepq_release(cvp);
331134013Sjhb		return (rval);
332133440Sjhb	}
333133440Sjhb
334127954Sjhb	cvp->cv_waiters++;
33588900Sjhb	DROP_GIANT();
33688900Sjhb	mtx_unlock(mp);
33771088Sjasone
338136445Sjhb	sleepq_add(cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR |
339134013Sjhb	    SLEEPQ_INTERRUPTIBLE);
340126885Sjhb	sleepq_set_timeout(cvp, timo);
341126326Sjhb	sig = sleepq_catch_signals(cvp);
342134013Sjhb	rval = sleepq_timedwait_sig(cvp, sig != 0);
343126326Sjhb	if (rval == 0)
344126326Sjhb		rval = sleepq_calc_signal_retval(sig);
34571088Sjasone
34671088Sjasone#ifdef KTRACE
34797995Sjhb	if (KTRPOINT(td, KTR_CSW))
34897995Sjhb		ktrcsw(0, 0);
34971088Sjasone#endif
35097995Sjhb	PICKUP_GIANT();
35172200Sbmilekic	mtx_lock(mp);
35274912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
35371088Sjasone
35471088Sjasone	return (rval);
35571088Sjasone}
35671088Sjasone
35771088Sjasone/*
35883366Sjulian * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
35971088Sjasone * the swapper if the process is not in memory, so that it can bring the
36083366Sjulian * sleeping process in.  Note that this may also result in additional threads
36171088Sjasone * being made runnable.  Should be called with the same mutex as was passed to
36271088Sjasone * cv_wait held.
36371088Sjasone */
36471088Sjasonevoid
36571088Sjasonecv_signal(struct cv *cvp)
36671088Sjasone{
36771088Sjasone
368136445Sjhb	sleepq_lock(cvp);
369127954Sjhb	if (cvp->cv_waiters > 0) {
370127954Sjhb		cvp->cv_waiters--;
371127954Sjhb		sleepq_signal(cvp, SLEEPQ_CONDVAR, -1);
372136445Sjhb	} else
373136445Sjhb		sleepq_release(cvp);
37471088Sjasone}
37571088Sjasone
37671088Sjasone/*
37783366Sjulian * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
37871088Sjasone * Should be called with the same mutex as was passed to cv_wait held.
37971088Sjasone */
38071088Sjasonevoid
381122352Stanimuracv_broadcastpri(struct cv *cvp, int pri)
38271088Sjasone{
38371088Sjasone
384136445Sjhb	sleepq_lock(cvp);
385127954Sjhb	if (cvp->cv_waiters > 0) {
386127954Sjhb		cvp->cv_waiters = 0;
387127954Sjhb		sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri);
388136445Sjhb	} else
389136445Sjhb		sleepq_release(cvp);
39071088Sjasone}
391