kern_condvar.c revision 181394
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 181394 2008-08-07 21:00:13Z 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, lock, 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((lock) != NULL, ("%s: lock NULL", __func__));		\
57} while (0)
58
59/*
60 * Initialize a condition variable.  Must be called before use.
61 */
62void
63cv_init(struct cv *cvp, const char *desc)
64{
65
66	cvp->cv_description = desc;
67	cvp->cv_waiters = 0;
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	sleepq_lock(cvp);
81	sq = sleepq_lookup(cvp);
82	sleepq_release(cvp);
83	KASSERT(sq == NULL, ("%s: associated sleep queue non-empty", __func__));
84#endif
85}
86
87/*
88 * Wait on a condition variable.  The current thread is placed on the condition
89 * variable's wait queue and suspended.  A cv_signal or cv_broadcast on the same
90 * condition variable will resume the thread.  The mutex is released before
91 * sleeping and will be held on return.  It is recommended that the mutex be
92 * held when cv_signal or cv_broadcast are called.
93 */
94void
95_cv_wait(struct cv *cvp, struct lock_object *lock)
96{
97	WITNESS_SAVE_DECL(lock_witness);
98	struct lock_class *class;
99	struct thread *td;
100	int lock_state;
101
102	td = curthread;
103	lock_state = 0;
104#ifdef KTRACE
105	if (KTRPOINT(td, KTR_CSW))
106		ktrcsw(1, 0);
107#endif
108	CV_ASSERT(cvp, lock, td);
109	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
110	    "Waiting on \"%s\"", cvp->cv_description);
111	WITNESS_SAVE(lock, lock_witness);
112	class = LOCK_CLASS(lock);
113
114	if (cold || panicstr) {
115		/*
116		 * During autoconfiguration, just give interrupts
117		 * a chance, then just return.  Don't run any other
118		 * thread or panic below, in case this is the idle
119		 * process and already asleep.
120		 */
121		return;
122	}
123
124	sleepq_lock(cvp);
125
126	cvp->cv_waiters++;
127	DROP_GIANT();
128
129	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
130	if (lock != &Giant.lock_object) {
131		if (class->lc_flags & LC_SLEEPABLE)
132			sleepq_release(cvp);
133		lock_state = class->lc_unlock(lock);
134		if (class->lc_flags & LC_SLEEPABLE)
135			sleepq_lock(cvp);
136	}
137	sleepq_wait(cvp, 0);
138
139#ifdef KTRACE
140	if (KTRPOINT(td, KTR_CSW))
141		ktrcsw(0, 0);
142#endif
143	PICKUP_GIANT();
144	if (lock != &Giant.lock_object) {
145		class->lc_lock(lock, lock_state);
146		WITNESS_RESTORE(lock, lock_witness);
147	}
148}
149
150/*
151 * Wait on a condition variable.  This function differs from cv_wait by
152 * not aquiring the mutex after condition variable was signaled.
153 */
154void
155_cv_wait_unlock(struct cv *cvp, struct lock_object *lock)
156{
157	struct lock_class *class;
158	struct thread *td;
159
160	td = curthread;
161#ifdef KTRACE
162	if (KTRPOINT(td, KTR_CSW))
163		ktrcsw(1, 0);
164#endif
165	CV_ASSERT(cvp, lock, td);
166	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
167	    "Waiting on \"%s\"", cvp->cv_description);
168	KASSERT(lock != &Giant.lock_object,
169	    ("cv_wait_unlock cannot be used with Giant"));
170	class = LOCK_CLASS(lock);
171
172	if (cold || panicstr) {
173		/*
174		 * During autoconfiguration, just give interrupts
175		 * a chance, then just return.  Don't run any other
176		 * thread or panic below, in case this is the idle
177		 * process and already asleep.
178		 */
179		class->lc_unlock(lock);
180		return;
181	}
182
183	sleepq_lock(cvp);
184
185	cvp->cv_waiters++;
186	DROP_GIANT();
187
188	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
189	if (class->lc_flags & LC_SLEEPABLE)
190		sleepq_release(cvp);
191	class->lc_unlock(lock);
192	if (class->lc_flags & LC_SLEEPABLE)
193		sleepq_lock(cvp);
194	sleepq_wait(cvp, 0);
195
196#ifdef KTRACE
197	if (KTRPOINT(td, KTR_CSW))
198		ktrcsw(0, 0);
199#endif
200	PICKUP_GIANT();
201}
202
203/*
204 * Wait on a condition variable, allowing interruption by signals.  Return 0 if
205 * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
206 * a signal was caught.  If ERESTART is returned the system call should be
207 * restarted if possible.
208 */
209int
210_cv_wait_sig(struct cv *cvp, struct lock_object *lock)
211{
212	WITNESS_SAVE_DECL(lock_witness);
213	struct lock_class *class;
214	struct thread *td;
215	struct proc *p;
216	int lock_state, rval;
217
218	td = curthread;
219	p = td->td_proc;
220	lock_state = 0;
221#ifdef KTRACE
222	if (KTRPOINT(td, KTR_CSW))
223		ktrcsw(1, 0);
224#endif
225	CV_ASSERT(cvp, lock, td);
226	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
227	    "Waiting on \"%s\"", cvp->cv_description);
228	WITNESS_SAVE(lock, lock_witness);
229	class = LOCK_CLASS(lock);
230
231	if (cold || panicstr) {
232		/*
233		 * After a panic, or during autoconfiguration, just give
234		 * interrupts a chance, then just return; don't run any other
235		 * procs or panic below, in case this is the idle process and
236		 * already asleep.
237		 */
238		return (0);
239	}
240
241	sleepq_lock(cvp);
242
243	cvp->cv_waiters++;
244	DROP_GIANT();
245
246	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
247	    SLEEPQ_INTERRUPTIBLE, 0);
248	if (lock != &Giant.lock_object) {
249		if (class->lc_flags & LC_SLEEPABLE)
250			sleepq_release(cvp);
251		lock_state = class->lc_unlock(lock);
252		if (class->lc_flags & LC_SLEEPABLE)
253			sleepq_lock(cvp);
254	}
255	rval = sleepq_wait_sig(cvp, 0);
256
257#ifdef KTRACE
258	if (KTRPOINT(td, KTR_CSW))
259		ktrcsw(0, 0);
260#endif
261	PICKUP_GIANT();
262	if (lock != &Giant.lock_object) {
263		class->lc_lock(lock, lock_state);
264		WITNESS_RESTORE(lock, lock_witness);
265	}
266
267	return (rval);
268}
269
270/*
271 * Wait on a condition variable for at most timo/hz seconds.  Returns 0 if the
272 * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout
273 * expires.
274 */
275int
276_cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo)
277{
278	WITNESS_SAVE_DECL(lock_witness);
279	struct lock_class *class;
280	struct thread *td;
281	int lock_state, rval;
282
283	td = curthread;
284	rval = 0;
285	lock_state = 0;
286#ifdef KTRACE
287	if (KTRPOINT(td, KTR_CSW))
288		ktrcsw(1, 0);
289#endif
290	CV_ASSERT(cvp, lock, td);
291	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
292	    "Waiting on \"%s\"", cvp->cv_description);
293	WITNESS_SAVE(lock, lock_witness);
294	class = LOCK_CLASS(lock);
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
311	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
312	sleepq_set_timeout(cvp, timo);
313	if (lock != &Giant.lock_object) {
314		if (class->lc_flags & LC_SLEEPABLE)
315			sleepq_release(cvp);
316		lock_state = class->lc_unlock(lock);
317		if (class->lc_flags & LC_SLEEPABLE)
318			sleepq_lock(cvp);
319	}
320	rval = sleepq_timedwait(cvp, 0);
321
322#ifdef KTRACE
323	if (KTRPOINT(td, KTR_CSW))
324		ktrcsw(0, 0);
325#endif
326	PICKUP_GIANT();
327	if (lock != &Giant.lock_object) {
328		class->lc_lock(lock, lock_state);
329		WITNESS_RESTORE(lock, lock_witness);
330	}
331
332	return (rval);
333}
334
335/*
336 * Wait on a condition variable for at most timo/hz seconds, allowing
337 * interruption by signals.  Returns 0 if the thread was resumed by cv_signal
338 * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if
339 * a signal was caught.
340 */
341int
342_cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo)
343{
344	WITNESS_SAVE_DECL(lock_witness);
345	struct lock_class *class;
346	struct thread *td;
347	struct proc *p;
348	int lock_state, rval;
349
350	td = curthread;
351	p = td->td_proc;
352	rval = 0;
353	lock_state = 0;
354#ifdef KTRACE
355	if (KTRPOINT(td, KTR_CSW))
356		ktrcsw(1, 0);
357#endif
358	CV_ASSERT(cvp, lock, td);
359	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
360	    "Waiting on \"%s\"", cvp->cv_description);
361	WITNESS_SAVE(lock, lock_witness);
362	class = LOCK_CLASS(lock);
363
364	if (cold || panicstr) {
365		/*
366		 * After a panic, or during autoconfiguration, just give
367		 * interrupts a chance, then just return; don't run any other
368		 * thread or panic below, in case this is the idle process and
369		 * already asleep.
370		 */
371		return 0;
372	}
373
374	sleepq_lock(cvp);
375
376	cvp->cv_waiters++;
377	DROP_GIANT();
378
379	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
380	    SLEEPQ_INTERRUPTIBLE, 0);
381	sleepq_set_timeout(cvp, timo);
382	if (lock != &Giant.lock_object) {
383		if (class->lc_flags & LC_SLEEPABLE)
384			sleepq_release(cvp);
385		lock_state = class->lc_unlock(lock);
386		if (class->lc_flags & LC_SLEEPABLE)
387			sleepq_lock(cvp);
388	}
389	rval = sleepq_timedwait_sig(cvp, 0);
390
391#ifdef KTRACE
392	if (KTRPOINT(td, KTR_CSW))
393		ktrcsw(0, 0);
394#endif
395	PICKUP_GIANT();
396	if (lock != &Giant.lock_object) {
397		class->lc_lock(lock, lock_state);
398		WITNESS_RESTORE(lock, lock_witness);
399	}
400
401	return (rval);
402}
403
404/*
405 * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
406 * the swapper if the process is not in memory, so that it can bring the
407 * sleeping process in.  Note that this may also result in additional threads
408 * being made runnable.  Should be called with the same mutex as was passed to
409 * cv_wait held.
410 */
411void
412cv_signal(struct cv *cvp)
413{
414	int wakeup_swapper;
415
416	wakeup_swapper = 0;
417	sleepq_lock(cvp);
418	if (cvp->cv_waiters > 0) {
419		cvp->cv_waiters--;
420		wakeup_swapper = sleepq_signal(cvp, SLEEPQ_CONDVAR, 0, 0);
421	}
422	sleepq_release(cvp);
423	if (wakeup_swapper)
424		kick_proc0();
425}
426
427/*
428 * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
429 * Should be called with the same mutex as was passed to cv_wait held.
430 */
431void
432cv_broadcastpri(struct cv *cvp, int pri)
433{
434	int wakeup_swapper;
435
436	/*
437	 * XXX sleepq_broadcast pri argument changed from -1 meaning
438	 * no pri to 0 meaning no pri.
439	 */
440	wakeup_swapper = 0;
441	if (pri == -1)
442		pri = 0;
443	sleepq_lock(cvp);
444	if (cvp->cv_waiters > 0) {
445		cvp->cv_waiters = 0;
446		wakeup_swapper = sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0);
447	}
448	sleepq_release(cvp);
449	if (wakeup_swapper)
450		kick_proc0();
451}
452