kern_condvar.c revision 126885
1/*-
2 * Copyright (c) 2000 Jake Burkholder <jake@freebsd.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/kern/kern_condvar.c 126885 2004-03-12 19:06:18Z jhb $");
29
30#include "opt_ktrace.h"
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/lock.h>
35#include <sys/mutex.h>
36#include <sys/proc.h>
37#include <sys/kernel.h>
38#include <sys/ktr.h>
39#include <sys/condvar.h>
40#include <sys/sched.h>
41#include <sys/signalvar.h>
42#include <sys/sleepqueue.h>
43#include <sys/resourcevar.h>
44#ifdef KTRACE
45#include <sys/uio.h>
46#include <sys/ktrace.h>
47#endif
48
49/*
50 * Common sanity checks for cv_wait* functions.
51 */
52#define	CV_ASSERT(cvp, mp, td) do {					\
53	KASSERT((td) != NULL, ("%s: curthread NULL", __func__));	\
54	KASSERT(TD_IS_RUNNING(td), ("%s: not TDS_RUNNING", __func__));	\
55	KASSERT((cvp) != NULL, ("%s: cvp NULL", __func__));		\
56	KASSERT((mp) != NULL, ("%s: mp NULL", __func__));		\
57	mtx_assert((mp), MA_OWNED | MA_NOTRECURSED);			\
58} while (0)
59
60/*
61 * Initialize a condition variable.  Must be called before use.
62 */
63void
64cv_init(struct cv *cvp, const char *desc)
65{
66
67	cvp->cv_description = desc;
68}
69
70/*
71 * Destroy a condition variable.  The condition variable must be re-initialized
72 * in order to be re-used.
73 */
74void
75cv_destroy(struct cv *cvp)
76{
77#ifdef INVARIANTS
78	struct sleepqueue *sq;
79
80	sq = sleepq_lookup(cvp);
81	sleepq_release(cvp);
82	KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__));
83#endif
84}
85
86/*
87 * Wait on a condition variable.  The current thread is placed on the condition
88 * variable's wait queue and suspended.  A cv_signal or cv_broadcast on the same
89 * condition variable will resume the thread.  The mutex is released before
90 * sleeping and will be held on return.  It is recommended that the mutex be
91 * held when cv_signal or cv_broadcast are called.
92 */
93void
94cv_wait(struct cv *cvp, struct mtx *mp)
95{
96	struct sleepqueue *sq;
97	struct thread *td;
98	WITNESS_SAVE_DECL(mp);
99
100	td = curthread;
101#ifdef KTRACE
102	if (KTRPOINT(td, KTR_CSW))
103		ktrcsw(1, 0);
104#endif
105	CV_ASSERT(cvp, mp, td);
106	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
107	    "Waiting on \"%s\"", cvp->cv_description);
108	WITNESS_SAVE(&mp->mtx_object, mp);
109
110	if (cold || panicstr) {
111		/*
112		 * During autoconfiguration, just give interrupts
113		 * a chance, then just return.  Don't run any other
114		 * thread or panic below, in case this is the idle
115		 * process and already asleep.
116		 */
117		return;
118	}
119
120	sq = sleepq_lookup(cvp);
121
122	DROP_GIANT();
123	mtx_unlock(mp);
124
125	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
126	sleepq_wait(cvp);
127
128#ifdef KTRACE
129	if (KTRPOINT(td, KTR_CSW))
130		ktrcsw(0, 0);
131#endif
132	PICKUP_GIANT();
133	mtx_lock(mp);
134	WITNESS_RESTORE(&mp->mtx_object, mp);
135}
136
137/*
138 * Wait on a condition variable, allowing interruption by signals.  Return 0 if
139 * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
140 * a signal was caught.  If ERESTART is returned the system call should be
141 * restarted if possible.
142 */
143int
144cv_wait_sig(struct cv *cvp, struct mtx *mp)
145{
146	struct sleepqueue *sq;
147	struct thread *td;
148	struct proc *p;
149	int rval, sig;
150	WITNESS_SAVE_DECL(mp);
151
152	td = curthread;
153	p = td->td_proc;
154	rval = 0;
155#ifdef KTRACE
156	if (KTRPOINT(td, KTR_CSW))
157		ktrcsw(1, 0);
158#endif
159	CV_ASSERT(cvp, mp, td);
160	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
161	    "Waiting on \"%s\"", cvp->cv_description);
162	WITNESS_SAVE(&mp->mtx_object, mp);
163
164	if (cold || panicstr) {
165		/*
166		 * After a panic, or during autoconfiguration, just give
167		 * interrupts a chance, then just return; don't run any other
168		 * procs or panic below, in case this is the idle process and
169		 * already asleep.
170		 */
171		return 0;
172	}
173
174	sq = sleepq_lookup(cvp);
175
176	/* XXX: Missing the threading checks from msleep! */
177
178	DROP_GIANT();
179	mtx_unlock(mp);
180
181	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
182	sig = sleepq_catch_signals(cvp);
183	/*
184	 * XXX: Missing magic return value handling for no signal
185	 * caught but thread woken up during check.
186	 */
187	rval = sleepq_wait_sig(cvp);
188	if (rval == 0)
189		rval = sleepq_calc_signal_retval(sig);
190
191	/* XXX: Part of missing threading checks? */
192	PROC_LOCK(p);
193	if (p->p_flag & P_WEXIT)
194		rval = EINTR;
195	PROC_UNLOCK(p);
196
197#ifdef KTRACE
198	if (KTRPOINT(td, KTR_CSW))
199		ktrcsw(0, 0);
200#endif
201	PICKUP_GIANT();
202	mtx_lock(mp);
203	WITNESS_RESTORE(&mp->mtx_object, mp);
204
205	return (rval);
206}
207
208/*
209 * Wait on a condition variable for at most timo/hz seconds.  Returns 0 if the
210 * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout
211 * expires.
212 */
213int
214cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
215{
216	struct sleepqueue *sq;
217	struct thread *td;
218	int rval;
219	WITNESS_SAVE_DECL(mp);
220
221	td = curthread;
222	rval = 0;
223#ifdef KTRACE
224	if (KTRPOINT(td, KTR_CSW))
225		ktrcsw(1, 0);
226#endif
227	CV_ASSERT(cvp, mp, td);
228	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
229	    "Waiting on \"%s\"", cvp->cv_description);
230	WITNESS_SAVE(&mp->mtx_object, mp);
231
232	if (cold || panicstr) {
233		/*
234		 * After a panic, or during autoconfiguration, just give
235		 * interrupts a chance, then just return; don't run any other
236		 * thread or panic below, in case this is the idle process and
237		 * already asleep.
238		 */
239		return 0;
240	}
241
242	sq = sleepq_lookup(cvp);
243
244	DROP_GIANT();
245	mtx_unlock(mp);
246
247	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
248	sleepq_set_timeout(cvp, timo);
249	rval = sleepq_timedwait(cvp, 0);
250
251#ifdef KTRACE
252	if (KTRPOINT(td, KTR_CSW))
253		ktrcsw(0, 0);
254#endif
255	PICKUP_GIANT();
256	mtx_lock(mp);
257	WITNESS_RESTORE(&mp->mtx_object, mp);
258
259	return (rval);
260}
261
262/*
263 * Wait on a condition variable for at most timo/hz seconds, allowing
264 * interruption by signals.  Returns 0 if the thread was resumed by cv_signal
265 * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if
266 * a signal was caught.
267 */
268int
269cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
270{
271	struct sleepqueue *sq;
272	struct thread *td;
273	struct proc *p;
274	int rval;
275	int sig;
276	WITNESS_SAVE_DECL(mp);
277
278	td = curthread;
279	p = td->td_proc;
280	rval = 0;
281#ifdef KTRACE
282	if (KTRPOINT(td, KTR_CSW))
283		ktrcsw(1, 0);
284#endif
285	CV_ASSERT(cvp, mp, td);
286	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
287	    "Waiting on \"%s\"", cvp->cv_description);
288	WITNESS_SAVE(&mp->mtx_object, mp);
289
290	if (cold || panicstr) {
291		/*
292		 * After a panic, or during autoconfiguration, just give
293		 * interrupts a chance, then just return; don't run any other
294		 * thread or panic below, in case this is the idle process and
295		 * already asleep.
296		 */
297		return 0;
298	}
299
300	sq = sleepq_lookup(cvp);
301
302	DROP_GIANT();
303	mtx_unlock(mp);
304
305	sleepq_add(sq, cvp, mp, cvp->cv_description, SLEEPQ_CONDVAR);
306	sleepq_set_timeout(cvp, timo);
307	sig = sleepq_catch_signals(cvp);
308	/*
309	 * XXX: Missing magic return value handling for no signal
310	 * caught but thread woken up during check.
311	 */
312	rval = sleepq_timedwait_sig(cvp, sig != 0);
313	if (rval == 0)
314		rval = sleepq_calc_signal_retval(sig);
315
316	/* XXX: Part of missing threading checks? */
317	PROC_LOCK(p);
318	if (p->p_flag & P_WEXIT)
319		rval = EINTR;
320	PROC_UNLOCK(p);
321
322#ifdef KTRACE
323	if (KTRPOINT(td, KTR_CSW))
324		ktrcsw(0, 0);
325#endif
326	PICKUP_GIANT();
327	mtx_lock(mp);
328	WITNESS_RESTORE(&mp->mtx_object, mp);
329
330	return (rval);
331}
332
333/*
334 * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
335 * the swapper if the process is not in memory, so that it can bring the
336 * sleeping process in.  Note that this may also result in additional threads
337 * being made runnable.  Should be called with the same mutex as was passed to
338 * cv_wait held.
339 */
340void
341cv_signal(struct cv *cvp)
342{
343
344	sleepq_signal(cvp, SLEEPQ_CONDVAR, -1);
345}
346
347/*
348 * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
349 * Should be called with the same mutex as was passed to cv_wait held.
350 */
351void
352cv_broadcastpri(struct cv *cvp, int pri)
353{
354
355	sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri);
356}
357