kern_sleepq.c revision 1.1.2.4 1 /* $NetBSD: kern_sleepq.c,v 1.1.2.4 2006/10/24 21:10:21 ad Exp $ */
2
3 /*-
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Sleep queue implementation, used by turnstiles and general sleep/wakeup
41 * interfaces.
42 */
43
44 #include "opt_multiprocessor.h"
45
46 #include <sys/cdefs.h>
47 __KERNEL_RCSID(0, "$NetBSD: kern_sleepq.c,v 1.1.2.4 2006/10/24 21:10:21 ad Exp $");
48
49 #include <sys/param.h>
50 #include <sys/lock.h>
51 #include <sys/kernel.h>
52 #include <sys/pool.h>
53 #include <sys/proc.h>
54 #include <sys/resourcevar.h>
55 #include <sys/sched.h>
56 #include <sys/systm.h>
57 #include <sys/sa.h>
58 #include <sys/savar.h>
59 #include <sys/sleepq.h>
60
61 int sleepq_sigtoerror(struct lwp *, int);
62 void sleepq_exit(sleepq_t *, struct lwp *);
63 void updatepri(struct lwp *);
64 void sa_awaken(struct lwp *);
65
66 sleepq_t sleeptab[SLEEPTAB_HASH_SIZE];
67 #ifdef MULTIPROCESSOR
68 kmutex_t sleeptab_mutexes[SLEEPTAB_HASH_SIZE];
69 #endif
70
71 /*
72 * sleeptab_init:
73 *
74 * Initialize the general-purpose sleep queues.
75 */
76 void
77 sleeptab_init(void)
78 {
79 sleepq_t *sq;
80 int i;
81
82 for (i = 0; i < SLEEPTAB_HASH_SIZE; i++) {
83 sq = &sleeptab[i];
84 #ifdef MULTIPROCESSOR
85 mutex_init(&sleeptab_mutexes[i], MUTEX_SPIN, IPL_SCHED);
86 sleepq_init(&sleeptab[i], &sleeptab_mutexes[i]);
87 #else
88 sleepq_init(&sleeptab[i], &sched_mutex);
89 #endif
90 }
91 }
92
93 /*
94 * sleepq_init:
95 *
96 * Prepare a sleep queue for use.
97 */
98 void
99 sleepq_init(sleepq_t *sq, kmutex_t *mtx)
100 {
101
102 sq->sq_waiters = 0;
103 sq->sq_mutex = mtx;
104 TAILQ_INIT(&sq->sq_queue);
105 }
106
107 /*
108 * sleepq_remove:
109 *
110 * Remove an LWP from a sleep queue and wake it up. Return non-zero if
111 * the LWP is swapped out; if so the caller needs to awaken the swapper
112 * to bring the LWP into memory.
113 */
114 int
115 sleepq_remove(sleepq_t *sq, struct lwp *l)
116 {
117 struct cpu_info *ci;
118
119 LOCK_ASSERT(lwp_locked(l, sq->sq_mutex));
120 LOCK_ASSERT(mutex_owned(&sched_mutex));
121 KASSERT(sq->sq_waiters > 0);
122
123 sq->sq_waiters--;
124 TAILQ_REMOVE(&sq->sq_queue, l, l_sleepq);
125
126 #ifdef DIAGNOSTIC
127 if (sq->sq_waiters == 0)
128 KASSERT(TAILQ_FIRST(&sq->sq_queue) == NULL);
129 else
130 KASSERT(TAILQ_FIRST(&sq->sq_queue) != NULL);
131 #endif
132
133 l->l_wchan = NULL;
134 l->l_flag &= ~L_SINTR;
135
136 /*
137 * If not sleeping, the LWP must have been suspended. Let whoever
138 * holds it stopped set it running again.
139 */
140 if (l->l_stat != LSSLEEP) {
141 KASSERT(l->l_stat == LSSTOP || l->l_stat == LSSUSPENDED);
142 return 0;
143 }
144
145 if (l->l_proc->p_sa)
146 sa_awaken(l);
147
148 lwp_setlock(l, &sched_mutex);
149
150 /*
151 * If the LWP is still on the CPU, mark it as LSONPROC. It may be
152 * about to call mi_switch(), in which case it will yield.
153 */
154 if ((ci = l->l_cpu) != NULL && ci->ci_curlwp == l) {
155 l->l_stat = LSONPROC;
156 l->l_slptime = 0;
157 return 0;
158 }
159
160 /*
161 * Set it running. We'll try to get the last CPU that ran
162 * this LWP to pick it up again.
163 */
164 l->l_stat = LSRUN;
165 if (l->l_slptime > 1)
166 updatepri(l);
167 l->l_slptime = 0;
168 if ((l->l_flag & L_INMEM) != 0) {
169 setrunqueue(l);
170 cpu_need_resched(l->l_cpu);
171 return 0;
172 }
173
174 return 1;
175 }
176
177 /*
178 * sleepq_enter:
179 *
180 * Enter an LWP into the sleep queue and prepare for sleep. Any interlocking
181 * step such as releasing a mutex or checking for signals may be safely done
182 * by the caller once on the sleep queue.
183 */
184 void
185 sleepq_enter(sleepq_t *sq, int pri, wchan_t wchan, const char *wmesg, int timo,
186 int catch)
187 {
188 struct lwp *l = curlwp;
189
190 LOCK_ASSERT(mutex_owned(sq->sq_mutex));
191
192 #ifdef KTRACE
193 if (KTRPOINT(p, KTR_CSW))
194 ktrcsw(l, 1, 0);
195 #endif
196
197 sq->sq_waiters++;
198 TAILQ_INSERT_TAIL(&sq->sq_queue, l, l_sleepq);
199
200 /*
201 * Acquire the per-LWP mutex.
202 */
203 lwp_lock(l);
204
205 KASSERT(l->l_wchan == NULL);
206
207 l->l_wchan = wchan;
208 l->l_wmesg = wmesg;
209 l->l_slptime = 0;
210 l->l_priority = pri & PRIMASK;
211 l->l_flag &= ~L_CANCELLED;
212 if (catch)
213 l->l_flag |= L_SINTR;
214 if (l->l_stat == LSONPROC)
215 l->l_stat = LSSLEEP;
216 l->l_nvcsw++;
217
218 if (timo)
219 callout_reset(&l->l_tsleep_ch, timo, sleepq_timeout, l);
220
221 /*
222 * The LWP is now on the sleep queue. Release its old mutex and
223 * lend it ours for the duration of the sleep.
224 */
225 lwp_setlock_unlock(l, sq->sq_mutex);
226 }
227
228 /*
229 * sleepq_exit:
230 *
231 * Remove the current LWP from a sleep queue after the sleep has been
232 * interrupted.
233 */
234 void
235 sleepq_exit(sleepq_t *sq, struct lwp *l)
236 {
237
238 LOCK_ASSERT(lwp_locked(l, sq->sq_mutex));
239 KASSERT(sq->sq_waiters > 0);
240 KASSERT(l->l_stat == LSSLEEP);
241
242 l->l_wchan = NULL;
243 l->l_slptime = 0;
244 l->l_flag &= ~L_SINTR;
245
246 sq->sq_waiters--;
247 TAILQ_REMOVE(&sq->sq_queue, l, l_sleepq);
248
249 #ifdef DIAGNOSTIC
250 if (sq->sq_waiters == 0)
251 KASSERT(TAILQ_FIRST(&sq->sq_queue) == NULL);
252 else
253 KASSERT(TAILQ_FIRST(&sq->sq_queue) != NULL);
254 #endif
255
256 l->l_stat = LSONPROC;
257
258 lwp_setlock_unlock(l, &sched_mutex);
259 }
260
261 /*
262 * sleepq_block:
263 *
264 * The calling LWP has been entered into the sleep queue by
265 * sleepq_enter(), and now wants to block. sleepq_block() may return
266 * early under exceptional conditions, for example if the LWP's process
267 * is exiting. sleepq_block() must be called if sleepq_enter() has
268 * been called.
269 */
270 int
271 sleepq_block(sleepq_t *sq, int timo)
272 {
273 int error, flag, expired, sig;
274 struct lwp *l = curlwp;
275 struct proc *p;
276
277 LOCK_ASSERT(lwp_locked(l, sq->sq_mutex));
278
279 flag = l->l_flag;
280 error = 0;
281
282 /*
283 * If sleeping interruptably, check for pending signals, exits or
284 * core dump events.
285 */
286 if ((flag & L_SINTR) != 0) {
287 while ((l->l_flag & L_PENDSIG) != 0 && error == 0) {
288 lwp_unlock(l);
289 p = l->l_proc;
290 mutex_enter(&p->p_smutex);
291 if ((sig = issignal(l)) != 0)
292 error = sleepq_sigtoerror(l, sig);
293 mutex_exit(&p->p_smutex);
294 lwp_lock(l);
295 }
296
297 if ((l->l_flag & (L_CANCELLED | L_WEXIT | L_WCORE)) != 0)
298 error = EINTR;
299 }
300
301 if (error != 0 && l->l_stat == LSSLEEP)
302 sleepq_exit(sq, l);
303 else if (l->l_stat != LSONPROC) {
304 if ((flag & L_SA) != 0) {
305 sa_switch(l, sadata_upcall_alloc(0), SA_UPCALL_BLOCKED);
306 /* XXXAD verify sa_switch restores SPL. */
307 } else {
308 mi_switch(l, NULL);
309 l->l_cpu->ci_schedstate.spc_curpriority = l->l_usrpri;
310 }
311 }
312
313 KASSERT(l->l_wchan == NULL);
314
315 if (timo) {
316 /*
317 * Even if the callout appears to have fired, we need to
318 * stop it in order to synchronise with other CPUs.
319 */
320 expired = callout_expired(&l->l_tsleep_ch);
321 callout_stop(&l->l_tsleep_ch);
322 if (expired && error == 0)
323 return EWOULDBLOCK;
324 }
325
326 if (error == 0 && (flag & L_SINTR) != 0) {
327 if ((l->l_flag & (L_CANCELLED | L_WEXIT | L_WCORE)) != 0)
328 error = EINTR;
329 else if ((l->l_flag & L_PENDSIG) != 0) {
330 p = l->l_proc;
331 mutex_enter(&p->p_smutex);
332 if ((sig = issignal(l)) != 0)
333 error = sleepq_sigtoerror(l, sig);
334 mutex_exit(&p->p_smutex);
335 }
336 }
337
338 #ifdef KTRACE
339 if (KTRPOINT(p, KTR_CSW))
340 ktrcsw(l, 0, 0);
341 #endif
342 return error;
343 }
344
345 /*
346 * sleepq_wakeone:
347 *
348 * Remove one LWP from the sleep queue and wake it. We search among
349 * the higest priority LWPs waiting on a single wait channel, and pick
350 * the longest waiting one.
351 */
352 void
353 sleepq_wakeone(sleepq_t *sq, wchan_t wchan)
354 {
355 struct lwp *l, *bl;
356 int bpri, swapin;
357
358 LOCK_ASSERT(mutex_owned(sq->sq_mutex));
359
360 swapin = 0;
361 bpri = MAXPRI;
362 bl = NULL;
363
364 TAILQ_FOREACH(l, &sq->sq_queue, l_sleepq) {
365 if (l->l_wchan != wchan || l->l_priority > bpri)
366 continue;
367 bl = l;
368 bpri = l->l_priority;
369 }
370
371 if (bl != NULL) {
372 sched_lock();
373 swapin = sleepq_remove(sq, bl);
374 sched_unlock();
375 }
376
377 mutex_exit(sq->sq_mutex);
378
379 if (swapin)
380 wakeup(&proc0);
381 }
382
383 /*
384 * sleepq_wakeall:
385 *
386 * Wake all LWPs blocked on a single wait channel.
387 */
388 void
389 sleepq_wakeall(sleepq_t *sq, wchan_t wchan, u_int expected)
390 {
391 struct lwp *l, *next;
392 int swapin = 0;
393
394 LOCK_ASSERT(mutex_owned(sq->sq_mutex));
395
396 sched_lock();
397 for (l = TAILQ_FIRST(&sq->sq_queue); l != NULL; l = next) {
398 next = TAILQ_NEXT(l, l_sleepq);
399 if (l->l_wchan != wchan)
400 continue;
401 swapin |= sleepq_remove(sq, l);
402 if (--expected == 0)
403 break;
404 }
405 sched_unlock();
406
407 LOCK_ASSERT(mutex_owned(sq->sq_mutex));
408 mutex_exit(sq->sq_mutex);
409
410 /*
411 * If there are newly awakend threads that need to be swapped in,
412 * then kick the swapper into action.
413 */
414 if (swapin)
415 wakeup(&proc0);
416 }
417
418 /*
419 * sleepq_unsleep:
420 *
421 * Remove an LWP from its sleep queue and set it runnable again.
422 * sleepq_unsleep() is called with the LWP's mutex held, and will
423 * always release it.
424 */
425 void
426 sleepq_unsleep(struct lwp *l)
427 {
428 sleepq_t *sq;
429 int swapin;
430
431 sq = &sleeptab[SLEEPTAB_HASH(l->l_wchan)];
432 KASSERT(l->l_wchan != NULL);
433 KASSERT(l->l_mutex == sq->sq_mutex);
434
435 sched_lock();
436 swapin = sleepq_remove(sq, l);
437 sched_unlock();
438
439 mutex_exit(sq->sq_mutex);
440
441 if (swapin)
442 wakeup(&proc0);
443 }
444
445 /*
446 * sleepq_timeout:
447 *
448 * Entered via the callout(9) subsystem to time out an LWP that is on a
449 * sleep queue.
450 */
451 void
452 sleepq_timeout(void *arg)
453 {
454 struct lwp *l = arg;
455
456 /*
457 * Lock the LWP. Assuming it's still on the sleep queue, its
458 * current mutex will also be the sleep queue mutex.
459 */
460 lwp_lock(l);
461
462 if (l->l_wchan == NULL) {
463 /* Somebody beat us to it. */
464 lwp_unlock(l);
465 return;
466 }
467
468 sleepq_unsleep(arg);
469 }
470
471 /*
472 * sleepq_sigtoerror:
473 *
474 * Given a signal number, interpret and return an error code.
475 */
476 int
477 sleepq_sigtoerror(struct lwp *l, int sig)
478 {
479 struct proc *p = l->l_proc;
480 int error;
481
482 LOCK_ASSERT(mutex_owned(&p->p_smutex));
483
484 /*
485 * If this sleep was canceled, don't let the syscall restart.
486 */
487 if ((SIGACTION(p, sig).sa_flags & SA_RESTART) == 0)
488 error = EINTR;
489 else
490 error = ERESTART;
491
492 return error;
493 }
494
495 /*
496 * sleepq_abort:
497 *
498 * After a panic or during autoconfiguration, lower the interrupt
499 * priority level to give pending interrupts a chance to run, and
500 * then return. Called if sleepq_dontsleep() returns non-zero, and
501 * always returns zero.
502 */
503 int
504 sleepq_abort(kmutex_t *mtx, int unlock)
505 {
506 extern int safepri;
507 int s;
508
509 s = splhigh();
510 splx(safepri);
511 splx(s);
512 if (mtx != NULL && unlock != 0)
513 mutex_exit(mtx);
514
515 return 0;
516 }
517