kern_condvar.c revision 177085
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 177085 2008-03-12 06:31:06Z jeff $");
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#ifdef KTRACE
104	if (KTRPOINT(td, KTR_CSW))
105		ktrcsw(1, 0);
106#endif
107	CV_ASSERT(cvp, lock, td);
108	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
109	    "Waiting on \"%s\"", cvp->cv_description);
110	WITNESS_SAVE(lock, lock_witness);
111	class = LOCK_CLASS(lock);
112
113	if (cold || panicstr) {
114		/*
115		 * During autoconfiguration, just give interrupts
116		 * a chance, then just return.  Don't run any other
117		 * thread or panic below, in case this is the idle
118		 * process and already asleep.
119		 */
120		return;
121	}
122
123	sleepq_lock(cvp);
124
125	cvp->cv_waiters++;
126	DROP_GIANT();
127
128	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
129	if (class->lc_flags & LC_SLEEPABLE)
130		sleepq_release(cvp);
131	lock_state = class->lc_unlock(lock);
132	if (class->lc_flags & LC_SLEEPABLE)
133		sleepq_lock(cvp);
134	sleepq_wait(cvp, 0);
135
136#ifdef KTRACE
137	if (KTRPOINT(td, KTR_CSW))
138		ktrcsw(0, 0);
139#endif
140	PICKUP_GIANT();
141	class->lc_lock(lock, lock_state);
142	WITNESS_RESTORE(lock, lock_witness);
143}
144
145/*
146 * Wait on a condition variable.  This function differs from cv_wait by
147 * not aquiring the mutex after condition variable was signaled.
148 */
149void
150_cv_wait_unlock(struct cv *cvp, struct lock_object *lock)
151{
152	struct lock_class *class;
153	struct thread *td;
154
155	td = curthread;
156#ifdef KTRACE
157	if (KTRPOINT(td, KTR_CSW))
158		ktrcsw(1, 0);
159#endif
160	CV_ASSERT(cvp, lock, td);
161	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
162	    "Waiting on \"%s\"", cvp->cv_description);
163	class = LOCK_CLASS(lock);
164
165	if (cold || panicstr) {
166		/*
167		 * During autoconfiguration, just give interrupts
168		 * a chance, then just return.  Don't run any other
169		 * thread or panic below, in case this is the idle
170		 * process and already asleep.
171		 */
172		class->lc_unlock(lock);
173		return;
174	}
175
176	sleepq_lock(cvp);
177
178	cvp->cv_waiters++;
179	DROP_GIANT();
180
181	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
182	if (class->lc_flags & LC_SLEEPABLE)
183		sleepq_release(cvp);
184	class->lc_unlock(lock);
185	if (class->lc_flags & LC_SLEEPABLE)
186		sleepq_lock(cvp);
187	sleepq_wait(cvp, 0);
188
189#ifdef KTRACE
190	if (KTRPOINT(td, KTR_CSW))
191		ktrcsw(0, 0);
192#endif
193	PICKUP_GIANT();
194}
195
196/*
197 * Wait on a condition variable, allowing interruption by signals.  Return 0 if
198 * the thread was resumed with cv_signal or cv_broadcast, EINTR or ERESTART if
199 * a signal was caught.  If ERESTART is returned the system call should be
200 * restarted if possible.
201 */
202int
203_cv_wait_sig(struct cv *cvp, struct lock_object *lock)
204{
205	WITNESS_SAVE_DECL(lock_witness);
206	struct lock_class *class;
207	struct thread *td;
208	struct proc *p;
209	int lock_state, rval;
210
211	td = curthread;
212	p = td->td_proc;
213#ifdef KTRACE
214	if (KTRPOINT(td, KTR_CSW))
215		ktrcsw(1, 0);
216#endif
217	CV_ASSERT(cvp, lock, td);
218	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
219	    "Waiting on \"%s\"", cvp->cv_description);
220	WITNESS_SAVE(lock, lock_witness);
221	class = LOCK_CLASS(lock);
222
223	if (cold || panicstr) {
224		/*
225		 * After a panic, or during autoconfiguration, just give
226		 * interrupts a chance, then just return; don't run any other
227		 * procs or panic below, in case this is the idle process and
228		 * already asleep.
229		 */
230		return (0);
231	}
232
233	sleepq_lock(cvp);
234
235	cvp->cv_waiters++;
236	DROP_GIANT();
237
238	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
239	    SLEEPQ_INTERRUPTIBLE, 0);
240	if (class->lc_flags & LC_SLEEPABLE)
241		sleepq_release(cvp);
242	lock_state = class->lc_unlock(lock);
243	if (class->lc_flags & LC_SLEEPABLE)
244		sleepq_lock(cvp);
245	rval = sleepq_wait_sig(cvp, 0);
246
247#ifdef KTRACE
248	if (KTRPOINT(td, KTR_CSW))
249		ktrcsw(0, 0);
250#endif
251	PICKUP_GIANT();
252	class->lc_lock(lock, lock_state);
253	WITNESS_RESTORE(lock, lock_witness);
254
255	return (rval);
256}
257
258/*
259 * Wait on a condition variable for at most timo/hz seconds.  Returns 0 if the
260 * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout
261 * expires.
262 */
263int
264_cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo)
265{
266	WITNESS_SAVE_DECL(lock_witness);
267	struct lock_class *class;
268	struct thread *td;
269	int lock_state, rval;
270
271	td = curthread;
272	rval = 0;
273#ifdef KTRACE
274	if (KTRPOINT(td, KTR_CSW))
275		ktrcsw(1, 0);
276#endif
277	CV_ASSERT(cvp, lock, td);
278	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
279	    "Waiting on \"%s\"", cvp->cv_description);
280	WITNESS_SAVE(lock, lock_witness);
281	class = LOCK_CLASS(lock);
282
283	if (cold || panicstr) {
284		/*
285		 * After a panic, or during autoconfiguration, just give
286		 * interrupts a chance, then just return; don't run any other
287		 * thread or panic below, in case this is the idle process and
288		 * already asleep.
289		 */
290		return 0;
291	}
292
293	sleepq_lock(cvp);
294
295	cvp->cv_waiters++;
296	DROP_GIANT();
297
298	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0);
299	sleepq_set_timeout(cvp, timo);
300	if (class->lc_flags & LC_SLEEPABLE)
301		sleepq_release(cvp);
302	lock_state = class->lc_unlock(lock);
303	if (class->lc_flags & LC_SLEEPABLE)
304		sleepq_lock(cvp);
305	rval = sleepq_timedwait(cvp, 0);
306
307#ifdef KTRACE
308	if (KTRPOINT(td, KTR_CSW))
309		ktrcsw(0, 0);
310#endif
311	PICKUP_GIANT();
312	class->lc_lock(lock, lock_state);
313	WITNESS_RESTORE(lock, lock_witness);
314
315	return (rval);
316}
317
318/*
319 * Wait on a condition variable for at most timo/hz seconds, allowing
320 * interruption by signals.  Returns 0 if the thread was resumed by cv_signal
321 * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if
322 * a signal was caught.
323 */
324int
325_cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo)
326{
327	WITNESS_SAVE_DECL(lock_witness);
328	struct lock_class *class;
329	struct thread *td;
330	struct proc *p;
331	int lock_state, rval;
332
333	td = curthread;
334	p = td->td_proc;
335	rval = 0;
336#ifdef KTRACE
337	if (KTRPOINT(td, KTR_CSW))
338		ktrcsw(1, 0);
339#endif
340	CV_ASSERT(cvp, lock, td);
341	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,
342	    "Waiting on \"%s\"", cvp->cv_description);
343	WITNESS_SAVE(lock, lock_witness);
344	class = LOCK_CLASS(lock);
345
346	if (cold || panicstr) {
347		/*
348		 * After a panic, or during autoconfiguration, just give
349		 * interrupts a chance, then just return; don't run any other
350		 * thread or panic below, in case this is the idle process and
351		 * already asleep.
352		 */
353		return 0;
354	}
355
356	sleepq_lock(cvp);
357
358	cvp->cv_waiters++;
359	DROP_GIANT();
360
361	sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR |
362	    SLEEPQ_INTERRUPTIBLE, 0);
363	sleepq_set_timeout(cvp, timo);
364	if (class->lc_flags & LC_SLEEPABLE)
365		sleepq_release(cvp);
366	lock_state = class->lc_unlock(lock);
367	if (class->lc_flags & LC_SLEEPABLE)
368		sleepq_lock(cvp);
369	rval = sleepq_timedwait_sig(cvp, 0);
370
371#ifdef KTRACE
372	if (KTRPOINT(td, KTR_CSW))
373		ktrcsw(0, 0);
374#endif
375	PICKUP_GIANT();
376	class->lc_lock(lock, lock_state);
377	WITNESS_RESTORE(lock, lock_witness);
378
379	return (rval);
380}
381
382/*
383 * Signal a condition variable, wakes up one waiting thread.  Will also wakeup
384 * the swapper if the process is not in memory, so that it can bring the
385 * sleeping process in.  Note that this may also result in additional threads
386 * being made runnable.  Should be called with the same mutex as was passed to
387 * cv_wait held.
388 */
389void
390cv_signal(struct cv *cvp)
391{
392
393	sleepq_lock(cvp);
394	if (cvp->cv_waiters > 0) {
395		cvp->cv_waiters--;
396		sleepq_signal(cvp, SLEEPQ_CONDVAR, 0, 0);
397	}
398	sleepq_release(cvp);
399}
400
401/*
402 * Broadcast a signal to a condition variable.  Wakes up all waiting threads.
403 * Should be called with the same mutex as was passed to cv_wait held.
404 */
405void
406cv_broadcastpri(struct cv *cvp, int pri)
407{
408	/*
409	 * XXX sleepq_broadcast pri argument changed from -1 meaning
410	 * no pri to 0 meaning no pri.
411	 */
412	if (pri == -1)
413		pri = 0;
414	sleepq_lock(cvp);
415	if (cvp->cv_waiters > 0) {
416		cvp->cv_waiters = 0;
417		sleepq_broadcast(cvp, SLEEPQ_CONDVAR, pri, 0);
418	}
419	sleepq_release(cvp);
420}
421