kern_condvar.c revision 165272
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 165272 2006-12-16 06:54:09Z kmacy $");
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	cvp->cv_waiters = 0;
69}
70
71/*
72 * Destroy a condition variable.  The condition variable must be re-initialized
73 * in order to be re-used.
74 */
75void
76cv_destroy(struct cv *cvp)
77{
78#ifdef INVARIANTS
79	struct sleepqueue *sq;
80
81	sleepq_lock(cvp);
82	sq = sleepq_lookup(cvp);
83	sleepq_release(cvp);
84	KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__));
85#endif
86}
87
88/*
89 * Wait on a condition variable.  The current thread is placed on the condition
90 * variable's wait queue and suspended.  A cv_signal or cv_broadcast on the same
91 * condition variable will resume the thread.  The mutex is released before
92 * sleeping and will be held on return.  It is recommended that the mutex be
93 * held when cv_signal or cv_broadcast are called.
94 */
95void
96cv_wait(struct cv *cvp, struct mtx *mp)
97{
98	WITNESS_SAVE_DECL(mp);
99
100	WITNESS_SAVE(&mp->mtx_object, mp);
101
102	if (cold || panicstr) {
103		/*
104		 * During autoconfiguration, just give interrupts
105		 * a chance, then just return.  Don't run any other
106		 * thread or panic below, in case this is the idle
107		 * process and already asleep.
108		 */
109		return;
110	}
111
112	cv_wait_unlock(cvp, mp);
113	mtx_lock(mp);
114	WITNESS_RESTORE(&mp->mtx_object, mp);
115}
116
117/*
118 * Wait on a condition variable.  This function differs from cv_wait by
119 * not aquiring the mutex after condition variable was signaled.
120 */
121void
122cv_wait_unlock(struct cv *cvp, struct mtx *mp)
123{
124	struct thread *td;
125
126	td = curthread;
127#ifdef KTRACE
128	if (KTRPOINT(td, KTR_CSW))
129		ktrcsw(1, 0);
130#endif
131	CV_ASSERT(cvp, mp, td);
132	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
133	    "Waiting on \"%s\"", cvp->cv_description);
134
135	if (cold || panicstr) {
136		/*
137		 * During autoconfiguration, just give interrupts
138		 * a chance, then just return.  Don't run any other
139		 * thread or panic below, in case this is the idle
140		 * process and already asleep.
141		 */
142		mtx_unlock(mp);
143		return;
144	}
145
146	sleepq_lock(cvp);
147
148	cvp->cv_waiters++;
149	DROP_GIANT();
150	mtx_unlock(mp);
151
152	sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR,
153		   0);
154	sleepq_wait(cvp);
155
156	PICKUP_GIANT();
157}
158
159/*
160 * Wait on a condition variable, allowing interruption by signals.  Return 0 if
161 * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
162 * a signal was caught.  If ERESTART is returned the system call should be
163 * restarted if possible.
164 */
165int
166cv_wait_sig(struct cv *cvp, struct mtx *mp)
167{
168	struct thread *td;
169	struct proc *p;
170	int rval;
171	WITNESS_SAVE_DECL(mp);
172
173	td = curthread;
174	p = td->td_proc;
175#ifdef KTRACE
176	if (KTRPOINT(td, KTR_CSW))
177		ktrcsw(1, 0);
178#endif
179	CV_ASSERT(cvp, mp, td);
180	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
181	    "Waiting on \"%s\"", cvp->cv_description);
182	WITNESS_SAVE(&mp->mtx_object, mp);
183
184	if (cold || panicstr) {
185		/*
186		 * After a panic, or during autoconfiguration, just give
187		 * interrupts a chance, then just return; don't run any other
188		 * procs or panic below, in case this is the idle process and
189		 * already asleep.
190		 */
191		return (0);
192	}
193
194	sleepq_lock(cvp);
195
196	cvp->cv_waiters++;
197	DROP_GIANT();
198	mtx_unlock(mp);
199
200	sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR |
201	    SLEEPQ_INTERRUPTIBLE, 0);
202	rval = sleepq_wait_sig(cvp);
203
204#ifdef KTRACE
205	if (KTRPOINT(td, KTR_CSW))
206		ktrcsw(0, 0);
207#endif
208	PICKUP_GIANT();
209	mtx_lock(mp);
210	WITNESS_RESTORE(&mp->mtx_object, mp);
211
212	return (rval);
213}
214
215/*
216 * Wait on a condition variable for at most timo/hz seconds.  Returns 0 if the
217 * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout
218 * expires.
219 */
220int
221cv_timedwait(struct cv *cvp, struct mtx *mp, int timo)
222{
223	struct thread *td;
224	int rval;
225	WITNESS_SAVE_DECL(mp);
226
227	td = curthread;
228	rval = 0;
229#ifdef KTRACE
230	if (KTRPOINT(td, KTR_CSW))
231		ktrcsw(1, 0);
232#endif
233	CV_ASSERT(cvp, mp, td);
234	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
235	    "Waiting on \"%s\"", cvp->cv_description);
236	WITNESS_SAVE(&mp->mtx_object, mp);
237
238	if (cold || panicstr) {
239		/*
240		 * After a panic, or during autoconfiguration, just give
241		 * interrupts a chance, then just return; don't run any other
242		 * thread or panic below, in case this is the idle process and
243		 * already asleep.
244		 */
245		return 0;
246	}
247
248	sleepq_lock(cvp);
249
250	cvp->cv_waiters++;
251	DROP_GIANT();
252	mtx_unlock(mp);
253
254	sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR,
255		   0);
256	sleepq_set_timeout(cvp, timo);
257	rval = sleepq_timedwait(cvp);
258
259#ifdef KTRACE
260	if (KTRPOINT(td, KTR_CSW))
261		ktrcsw(0, 0);
262#endif
263	PICKUP_GIANT();
264	mtx_lock(mp);
265	WITNESS_RESTORE(&mp->mtx_object, mp);
266
267	return (rval);
268}
269
270/*
271 * Wait on a condition variable for at most timo/hz seconds, allowing
272 * interruption by signals.  Returns 0 if the thread was resumed by cv_signal
273 * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if
274 * a signal was caught.
275 */
276int
277cv_timedwait_sig(struct cv *cvp, struct mtx *mp, int timo)
278{
279	struct thread *td;
280	struct proc *p;
281	int rval;
282	WITNESS_SAVE_DECL(mp);
283
284	td = curthread;
285	p = td->td_proc;
286	rval = 0;
287#ifdef KTRACE
288	if (KTRPOINT(td, KTR_CSW))
289		ktrcsw(1, 0);
290#endif
291	CV_ASSERT(cvp, mp, td);
292	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, &mp->mtx_object,
293	    "Waiting on \"%s\"", cvp->cv_description);
294	WITNESS_SAVE(&mp->mtx_object, mp);
295
296	if (cold || panicstr) {
297		/*
298		 * After a panic, or during autoconfiguration, just give
299		 * interrupts a chance, then just return; don't run any other
300		 * thread or panic below, in case this is the idle process and
301		 * already asleep.
302		 */
303		return 0;
304	}
305
306	sleepq_lock(cvp);
307
308	cvp->cv_waiters++;
309	DROP_GIANT();
310	mtx_unlock(mp);
311
312	sleepq_add(cvp, &mp->mtx_object, cvp->cv_description, SLEEPQ_CONDVAR |
313	    SLEEPQ_INTERRUPTIBLE, 0);
314	sleepq_set_timeout(cvp, timo);
315	rval = sleepq_timedwait_sig(cvp);
316
317#ifdef KTRACE
318	if (KTRPOINT(td, KTR_CSW))
319		ktrcsw(0, 0);
320#endif
321	PICKUP_GIANT();
322	mtx_lock(mp);
323	WITNESS_RESTORE(&mp->mtx_object, mp);
324
325	return (rval);
326}
327
328/*
329 * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
330 * the swapper if the process is not in memory, so that it can bring the
331 * sleeping process in.  Note that this may also result in additional threads
332 * being made runnable.  Should be called with the same mutex as was passed to
333 * cv_wait held.
334 */
335void
336cv_signal(struct cv *cvp)
337{
338
339	sleepq_lock(cvp);
340	if (cvp->cv_waiters > 0) {
341		cvp->cv_waiters--;
342		sleepq_signal(cvp, SLEEPQ_CONDVAR, -1, 0);
343	} else
344		sleepq_release(cvp);
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_lock(cvp);
356	if (cvp->cv_waiters > 0) {
357		cvp->cv_waiters = 0;
358		sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0);
359	} else
360		sleepq_release(cvp);
361}
362