kern_condvar.c revision 131249
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 131249 2004-06-28 18:57:06Z 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;
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
79126326Sjhb	struct sleepqueue *sq;
8071088Sjasone
81126326Sjhb	sq = sleepq_lookup(cvp);
82126326Sjhb	sleepq_release(cvp);
83126326Sjhb	KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__));
84126326Sjhb#endif
8571088Sjasone}
8671088Sjasone
8771088Sjasone/*
8883366Sjulian * Wait on a condition variable.  The current thread is placed on the condition
8971088Sjasone * variable's wait queue and suspended.  A cv_signal or cv_broadcast on the same
9083366Sjulian * condition variable will resume the thread.  The mutex is released before
9171088Sjasone * sleeping and will be held on return.  It is recommended that the mutex be
9271088Sjasone * held when cv_signal or cv_broadcast are called.
9371088Sjasone */
9471088Sjasonevoid
9571088Sjasonecv_wait(struct cv *cvp, struct mtx *mp)
9671088Sjasone{
97126326Sjhb	struct sleepqueue *sq;
9883366Sjulian	struct thread *td;
9971088Sjasone	WITNESS_SAVE_DECL(mp);
10071088Sjasone
10183366Sjulian	td = curthread;
10271088Sjasone#ifdef KTRACE
10397995Sjhb	if (KTRPOINT(td, KTR_CSW))
10497995Sjhb		ktrcsw(1, 0);
10571088Sjasone#endif
10683366Sjulian	CV_ASSERT(cvp, mp, td);
107111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
108111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
10974912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
11071088Sjasone
111126326Sjhb	if (cold || panicstr) {
11271088Sjasone		/*
113100209Sgallatin		 * During autoconfiguration, just give interrupts
114100209Sgallatin		 * a chance, then just return.  Don't run any other
115100209Sgallatin		 * thread or panic below, in case this is the idle
116100209Sgallatin		 * process and already asleep.
11771088Sjasone		 */
11871088Sjasone		return;
11971088Sjasone	}
12095322Shsu
121126326Sjhb	sq = sleepq_lookup(cvp);
12295322Shsu
123127954Sjhb	cvp->cv_waiters++;
12488900Sjhb	DROP_GIANT();
12588900Sjhb	mtx_unlock(mp);
12671088Sjasone
127126326Sjhb	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
128126326Sjhb	sleepq_wait(cvp);
12971088Sjasone
13071088Sjasone#ifdef KTRACE
13197995Sjhb	if (KTRPOINT(td, KTR_CSW))
13297995Sjhb		ktrcsw(0, 0);
13371088Sjasone#endif
13471088Sjasone	PICKUP_GIANT();
13572200Sbmilekic	mtx_lock(mp);
13674912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
13771088Sjasone}
13871088Sjasone
13971088Sjasone/*
14071088Sjasone * Wait on a condition variable, allowing interruption by signals.  Return 0 if
14183366Sjulian * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
14271088Sjasone * a signal was caught.  If ERESTART is returned the system call should be
14371088Sjasone * restarted if possible.
14471088Sjasone */
14571088Sjasoneint
14671088Sjasonecv_wait_sig(struct cv *cvp, struct mtx *mp)
14771088Sjasone{
148126326Sjhb	struct sleepqueue *sq;
14983366Sjulian	struct thread *td;
15083658Speter	struct proc *p;
151126326Sjhb	int rval, sig;
15271088Sjasone	WITNESS_SAVE_DECL(mp);
15371088Sjasone
15483366Sjulian	td = curthread;
15583650Sjhb	p = td->td_proc;
15671088Sjasone	rval = 0;
15771088Sjasone#ifdef KTRACE
15897995Sjhb	if (KTRPOINT(td, KTR_CSW))
15997995Sjhb		ktrcsw(1, 0);
16071088Sjasone#endif
16183366Sjulian	CV_ASSERT(cvp, mp, td);
162111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
163111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
16474912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
16571088Sjasone
16671088Sjasone	if (cold || panicstr) {
16771088Sjasone		/*
16871088Sjasone		 * After a panic, or during autoconfiguration, just give
16971088Sjasone		 * interrupts a chance, then just return; don't run any other
17071088Sjasone		 * procs or panic below, in case this is the idle process and
17171088Sjasone		 * already asleep.
17271088Sjasone		 */
17371088Sjasone		return 0;
17471088Sjasone	}
17595322Shsu
176126326Sjhb	sq = sleepq_lookup(cvp);
17795322Shsu
178126326Sjhb	/* XXX: Missing the threading checks from msleep! */
17971088Sjasone
180127954Sjhb	cvp->cv_waiters++;
18188900Sjhb	DROP_GIANT();
18288900Sjhb	mtx_unlock(mp);
18371088Sjasone
184126326Sjhb	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
185126326Sjhb	sig = sleepq_catch_signals(cvp);
186126326Sjhb	/*
187126326Sjhb	 * XXX: Missing magic return value handling for no signal
188126326Sjhb	 * caught but thread woken up during check.
189126326Sjhb	 */
190126326Sjhb	rval = sleepq_wait_sig(cvp);
191126326Sjhb	if (rval == 0)
192126326Sjhb		rval = sleepq_calc_signal_retval(sig);
19371088Sjasone
194126326Sjhb	/* XXX: Part of missing threading checks? */
19583650Sjhb	PROC_LOCK(p);
19699072Sjulian	if (p->p_flag & P_WEXIT)
19799072Sjulian		rval = EINTR;
198113625Sjhb	PROC_UNLOCK(p);
19971088Sjasone
20071088Sjasone#ifdef KTRACE
20197995Sjhb	if (KTRPOINT(td, KTR_CSW))
20297995Sjhb		ktrcsw(0, 0);
20371088Sjasone#endif
20497995Sjhb	PICKUP_GIANT();
20572200Sbmilekic	mtx_lock(mp);
20674912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
20771088Sjasone
20871088Sjasone	return (rval);
20971088Sjasone}
21071088Sjasone
21171088Sjasone/*
21271088Sjasone * Wait on a condition variable for at most timo/hz seconds.  Returns 0 if the
21371088Sjasone * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout
21471088Sjasone * expires.
21571088Sjasone */
21671088Sjasoneint
21771088Sjasonecv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
21871088Sjasone{
219126326Sjhb	struct sleepqueue *sq;
22083366Sjulian	struct thread *td;
22171088Sjasone	int rval;
22271088Sjasone	WITNESS_SAVE_DECL(mp);
22371088Sjasone
22483366Sjulian	td = curthread;
22571088Sjasone	rval = 0;
22671088Sjasone#ifdef KTRACE
22797995Sjhb	if (KTRPOINT(td, KTR_CSW))
22897995Sjhb		ktrcsw(1, 0);
22971088Sjasone#endif
23083366Sjulian	CV_ASSERT(cvp, mp, td);
231111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
232111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
23374912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
23471088Sjasone
23571088Sjasone	if (cold || panicstr) {
23671088Sjasone		/*
23771088Sjasone		 * After a panic, or during autoconfiguration, just give
23871088Sjasone		 * interrupts a chance, then just return; don't run any other
23983366Sjulian		 * thread or panic below, in case this is the idle process and
24071088Sjasone		 * already asleep.
24171088Sjasone		 */
24271088Sjasone		return 0;
24371088Sjasone	}
24495322Shsu
245126326Sjhb	sq = sleepq_lookup(cvp);
24695322Shsu
247127954Sjhb	cvp->cv_waiters++;
24888900Sjhb	DROP_GIANT();
24988900Sjhb	mtx_unlock(mp);
25071088Sjasone
251126326Sjhb	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
252126885Sjhb	sleepq_set_timeout(cvp, timo);
253131249Sjhb	rval = sleepq_timedwait(cvp);
25471088Sjasone
25571088Sjasone#ifdef KTRACE
25697995Sjhb	if (KTRPOINT(td, KTR_CSW))
25797995Sjhb		ktrcsw(0, 0);
25871088Sjasone#endif
25971088Sjasone	PICKUP_GIANT();
26072200Sbmilekic	mtx_lock(mp);
26174912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
26271088Sjasone
26371088Sjasone	return (rval);
26471088Sjasone}
26571088Sjasone
26671088Sjasone/*
26771088Sjasone * Wait on a condition variable for at most timo/hz seconds, allowing
26883366Sjulian * interruption by signals.  Returns 0 if the thread was resumed by cv_signal
26971088Sjasone * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if
27071088Sjasone * a signal was caught.
27171088Sjasone */
27271088Sjasoneint
27371088Sjasonecv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
27471088Sjasone{
275126326Sjhb	struct sleepqueue *sq;
27683366Sjulian	struct thread *td;
27783650Sjhb	struct proc *p;
27871088Sjasone	int rval;
27971088Sjasone	int sig;
28071088Sjasone	WITNESS_SAVE_DECL(mp);
28171088Sjasone
28283366Sjulian	td = curthread;
28383650Sjhb	p = td->td_proc;
28471088Sjasone	rval = 0;
28571088Sjasone#ifdef KTRACE
28697995Sjhb	if (KTRPOINT(td, KTR_CSW))
28797995Sjhb		ktrcsw(1, 0);
28871088Sjasone#endif
28983366Sjulian	CV_ASSERT(cvp, mp, td);
290111883Sjhb	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
291111883Sjhb	    "Waiting on \"%s\"", cvp->cv_description);
29274912Sjhb	WITNESS_SAVE(&mp->mtx_object, mp);
29371088Sjasone
29471088Sjasone	if (cold || panicstr) {
29571088Sjasone		/*
29671088Sjasone		 * After a panic, or during autoconfiguration, just give
29771088Sjasone		 * interrupts a chance, then just return; don't run any other
29883366Sjulian		 * thread or panic below, in case this is the idle process and
29971088Sjasone		 * already asleep.
30071088Sjasone		 */
30171088Sjasone		return 0;
30271088Sjasone	}
30395322Shsu
304126326Sjhb	sq = sleepq_lookup(cvp);
30595322Shsu
306127954Sjhb	cvp->cv_waiters++;
30788900Sjhb	DROP_GIANT();
30888900Sjhb	mtx_unlock(mp);
30971088Sjasone
310126326Sjhb	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
311126885Sjhb	sleepq_set_timeout(cvp, timo);
312126326Sjhb	sig = sleepq_catch_signals(cvp);
313126326Sjhb	/*
314126326Sjhb	 * XXX: Missing magic return value handling for no signal
315126326Sjhb	 * caught but thread woken up during check.
316126326Sjhb	 */
317126326Sjhb	rval = sleepq_timedwait_sig(cvp, sig != 0);
318126326Sjhb	if (rval == 0)
319126326Sjhb		rval = sleepq_calc_signal_retval(sig);
32071088Sjasone
321126326Sjhb	/* XXX: Part of missing threading checks? */
32283650Sjhb	PROC_LOCK(p);
32399072Sjulian	if (p->p_flag & P_WEXIT)
32499072Sjulian		rval = EINTR;
325113625Sjhb	PROC_UNLOCK(p);
32699072Sjulian
32771088Sjasone#ifdef KTRACE
32897995Sjhb	if (KTRPOINT(td, KTR_CSW))
32997995Sjhb		ktrcsw(0, 0);
33071088Sjasone#endif
33197995Sjhb	PICKUP_GIANT();
33272200Sbmilekic	mtx_lock(mp);
33374912Sjhb	WITNESS_RESTORE(&mp->mtx_object, mp);
33471088Sjasone
33571088Sjasone	return (rval);
33671088Sjasone}
33771088Sjasone
33871088Sjasone/*
33983366Sjulian * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
34071088Sjasone * the swapper if the process is not in memory, so that it can bring the
34183366Sjulian * sleeping process in.  Note that this may also result in additional threads
34271088Sjasone * being made runnable.  Should be called with the same mutex as was passed to
34371088Sjasone * cv_wait held.
34471088Sjasone */
34571088Sjasonevoid
34671088Sjasonecv_signal(struct cv *cvp)
34771088Sjasone{
34871088Sjasone
349127954Sjhb	if (cvp->cv_waiters > 0) {
350127954Sjhb		cvp->cv_waiters--;
351127954Sjhb		sleepq_signal(cvp, SLEEPQ_CONDVAR, -1);
352127954Sjhb	}
35371088Sjasone}
35471088Sjasone
35571088Sjasone/*
35683366Sjulian * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
35771088Sjasone * Should be called with the same mutex as was passed to cv_wait held.
35871088Sjasone */
35971088Sjasonevoid
360122352Stanimuracv_broadcastpri(struct cv *cvp, int pri)
36171088Sjasone{
36271088Sjasone
363127954Sjhb	if (cvp->cv_waiters > 0) {
364127954Sjhb		cvp->cv_waiters = 0;
365127954Sjhb		sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri);
366127954Sjhb	}
36771088Sjasone}
368