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