1 /* $OpenBSD: kern_synch.c,v 1.80 2007/05/16 17:27:30 art Exp $ */
2 /* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */
3
4 /*
5 * Copyright (c) 1982, 1986, 1990, 1991, 1993
6 * The Regents of the University of California. All rights reserved.
7 * (c) UNIX System Laboratories, Inc.
8 * All or some portions of this file are derived from material licensed
9 * to the University of California by American Telephone and Telegraph
10 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11 * the permission of UNIX System Laboratories, Inc.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)kern_synch.c 8.6 (Berkeley) 1/21/94
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/proc.h>
43 #include <sys/kernel.h>
44 #include <sys/buf.h>
45 #include <sys/signalvar.h>
46 #include <sys/resourcevar.h>
47 #include <uvm/uvm_extern.h>
48 #include <sys/sched.h>
49 #include <sys/timeout.h>
50 #include <sys/mount.h>
51 #include <sys/syscallargs.h>
52 #include <sys/pool.h>
53
54 #include <machine/spinlock.h>
55
56 #ifdef KTRACE
57 #include <sys/ktrace.h>
58 #endif
59
60 void updatepri(struct proc *);
61 void endtsleep(void *);
62
63 /*
64 * We're only looking at 7 bits of the address; everything is
65 * aligned to 4, lots of things are aligned to greater powers
66 * of 2. Shift right by 8, i.e. drop the bottom 256 worth.
67 */
68 #define TABLESIZE 128
69 #define LOOKUP(x) (((long)(x) >> 8) & (TABLESIZE - 1))
70 struct slpque {
71 struct proc *sq_head;
72 struct proc **sq_tailp;
73 } slpque[TABLESIZE];
74
75 /*
76 * During autoconfiguration or after a panic, a sleep will simply
77 * lower the priority briefly to allow interrupts, then return.
78 * The priority to be used (safepri) is machine-dependent, thus this
79 * value is initialized and maintained in the machine-dependent layers.
80 * This priority will typically be 0, or the lowest priority
81 * that is safe for use on the interrupt stack; it can be made
82 * higher to block network software interrupts after panics.
83 */
84 int safepri;
85
86 /*
87 * General sleep call. Suspends the current process until a wakeup is
88 * performed on the specified identifier. The process will then be made
89 * runnable with the specified priority. Sleeps at most timo/hz seconds
90 * (0 means no timeout). If pri includes PCATCH flag, signals are checked
91 * before and after sleeping, else signals are not checked. Returns 0 if
92 * awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a
93 * signal needs to be delivered, ERESTART is returned if the current system
94 * call should be restarted if possible, and EINTR is returned if the system
95 * call should be interrupted by the signal (return EINTR).
96 */
97 int
98 tsleep(void *ident, int priority, const char *wmesg, int timo)
99 {
100 struct sleep_state sls;
101 int error, error1;
102
103 if (cold || panicstr) {
104 int s;
105 /*
106 * After a panic, or during autoconfiguration,
107 * just give interrupts a chance, then just return;
108 * don't run any other procs or panic below,
109 * in case this is the idle process and already asleep.
110 */
111 s = splhigh();
112 splx(safepri);
113 splx(s);
114 return (0);
115 }
116
117 sleep_setup(&sls, ident, priority, wmesg);
118 sleep_setup_timeout(&sls, timo);
119 sleep_setup_signal(&sls, priority);
120
121 sleep_finish(&sls, 1);
122 error1 = sleep_finish_timeout(&sls);
123 error = sleep_finish_signal(&sls);
124
125 /* Signal errors are higher priority than timeouts. */
126 if (error == 0 && error1 != 0)
127 error = error1;
128
129 return (error);
130 }
131
132 void
133 sleep_setup(struct sleep_state *sls, void *ident, int prio, const char *wmesg)
134 {
135 struct proc *p = curproc;
136 struct slpque *qp;
137
138 #ifdef DIAGNOSTIC
139 if (ident == NULL)
140 panic("tsleep: no ident");
141 if (p->p_stat != SONPROC)
142 panic("tsleep: not SONPROC");
143 if (p->p_back != NULL)
144 panic("tsleep: p_back not NULL");
145 #endif
146
147 #ifdef KTRACE
148 if (KTRPOINT(p, KTR_CSW))
149 ktrcsw(p, 1, 0);
150 #endif
151
152 sls->sls_catch = 0;
153 sls->sls_do_sleep = 1;
154 sls->sls_sig = 1;
155
156 SCHED_LOCK(sls->sls_s);
157
158 p->p_wchan = ident;
159 p->p_wmesg = wmesg;
160 p->p_slptime = 0;
161 p->p_priority = prio & PRIMASK;
162 qp = &slpque[LOOKUP(ident)];
163 if (qp->sq_head == 0)
164 qp->sq_head = p;
165 else
166 *qp->sq_tailp = p;
167 *(qp->sq_tailp = &p->p_forw) = NULL;
168 }
169
170 void
171 sleep_finish(struct sleep_state *sls, int do_sleep)
172 {
173 struct proc *p = curproc;
174
175 if (sls->sls_do_sleep && do_sleep) {
176 p->p_stat = SSLEEP;
177 p->p_stats->p_ru.ru_nvcsw++;
178 SCHED_ASSERT_LOCKED();
179 mi_switch();
180 } else if (!do_sleep) {
181 unsleep(p);
182 #ifdef DIAGNOSTIC
183 if (p->p_stat != SONPROC)
184 panic("sleep_finish !SONPROC");
185 #endif
186 }
187
188 p->p_cpu->ci_schedstate.spc_curpriority = p->p_usrpri;
189 SCHED_UNLOCK(sls->sls_s);
190
191 /*
192 * Even though this belongs to the signal handling part of sleep,
193 * we need to clear it before the ktrace.
194 */
195 atomic_clearbits_int(&p->p_flag, P_SINTR);
196
197 #ifdef KTRACE
198 if (KTRPOINT(p, KTR_CSW))
199 ktrcsw(p, 0, 0);
200 #endif
201 }
202
203 void
204 sleep_setup_timeout(struct sleep_state *sls, int timo)
205 {
206 if (timo)
207 timeout_add(&curproc->p_sleep_to, timo);
208 }
209
210 int
211 sleep_finish_timeout(struct sleep_state *sls)
212 {
213 struct proc *p = curproc;
214
215 if (p->p_flag & P_TIMEOUT) {
216 atomic_clearbits_int(&p->p_flag, P_TIMEOUT);
217 return (EWOULDBLOCK);
218 } else if (timeout_pending(&p->p_sleep_to)) {
219 timeout_del(&p->p_sleep_to);
220 }
221
222 return (0);
223 }
224
225 void
226 sleep_setup_signal(struct sleep_state *sls, int prio)
227 {
228 struct proc *p = curproc;
229
230 if ((sls->sls_catch = (prio & PCATCH)) == 0)
231 return;
232
233 /*
234 * We put ourselves on the sleep queue and start our timeout
235 * before calling CURSIG, as we could stop there, and a wakeup
236 * or a SIGCONT (or both) could occur while we were stopped.
237 * A SIGCONT would cause us to be marked as SSLEEP
238 * without resuming us, thus we must be ready for sleep
239 * when CURSIG is called. If the wakeup happens while we're
240 * stopped, p->p_wchan will be 0 upon return from CURSIG.
241 */
242 atomic_setbits_int(&p->p_flag, P_SINTR);
243 if ((sls->sls_sig = CURSIG(p)) != 0) {
244 if (p->p_wchan)
245 unsleep(p);
246 p->p_stat = SONPROC;
247 sls->sls_do_sleep = 0;
248 } else if (p->p_wchan == 0) {
249 sls->sls_catch = 0;
250 sls->sls_do_sleep = 0;
251 }
252 }
253
254 int
255 sleep_finish_signal(struct sleep_state *sls)
256 {
257 struct proc *p = curproc;
258
259 if (sls->sls_catch != 0) {
260 if (sls->sls_sig != 0 || (sls->sls_sig = CURSIG(p)) != 0) {
261 if (p->p_sigacts->ps_sigintr & sigmask(sls->sls_sig))
262 return (EINTR);
263 return (ERESTART);
264 }
265 }
266
267 return (0);
268 }
269
270 /*
271 * Implement timeout for tsleep.
272 * If process hasn't been awakened (wchan non-zero),
273 * set timeout flag and undo the sleep. If proc
274 * is stopped, just unsleep so it will remain stopped.
275 */
276 void
277 endtsleep(void *arg)
278 {
279 struct proc *p = arg;
280 int s;
281
282 SCHED_LOCK(s);
283 if (p->p_wchan) {
284 if (p->p_stat == SSLEEP)
285 setrunnable(p);
286 else
287 unsleep(p);
288 atomic_setbits_int(&p->p_flag, P_TIMEOUT);
289 }
290 SCHED_UNLOCK(s);
291 }
292
293 /*
294 * Remove a process from its wait queue
295 */
296 void
297 unsleep(struct proc *p)
298 {
299 struct slpque *qp;
300 struct proc **hp;
301
302 if (p->p_wchan) {
303 hp = &(qp = &slpque[LOOKUP(p->p_wchan)])->sq_head;
304 while (*hp != p)
305 hp = &(*hp)->p_forw;
306 *hp = p->p_forw;
307 if (qp->sq_tailp == &p->p_forw)
308 qp->sq_tailp = hp;
309 p->p_wchan = 0;
310 }
311 }
312
313 /*
314 * Make a number of processes sleeping on the specified identifier runnable.
315 */
316 void
317 wakeup_n(void *ident, int n)
318 {
319 struct slpque *qp;
320 struct proc *p, **q;
321 int s;
322
323 SCHED_LOCK(s);
324 qp = &slpque[LOOKUP(ident)];
325 restart:
326 for (q = &qp->sq_head; (p = *q) != NULL; ) {
327 #ifdef DIAGNOSTIC
328 if (p->p_back)
329 panic("wakeup: p_back not NULL");
330 if (p->p_stat != SSLEEP && p->p_stat != SSTOP)
331 panic("wakeup: p_stat is %d", (int)p->p_stat);
332 #endif
333 if (p->p_wchan == ident) {
334 --n;
335 p->p_wchan = 0;
336 *q = p->p_forw;
337 if (qp->sq_tailp == &p->p_forw)
338 qp->sq_tailp = q;
339 if (p->p_stat == SSLEEP) {
340 /* OPTIMIZED EXPANSION OF setrunnable(p); */
341 if (p->p_slptime > 1)
342 updatepri(p);
343 p->p_slptime = 0;
344 p->p_stat = SRUN;
345
346 /*
347 * Since curpriority is a user priority,
348 * p->p_priority is always better than
349 * curpriority on the last CPU on
350 * which it ran.
351 *
352 * XXXSMP See affinity comment in
353 * resched_proc().
354 */
355 setrunqueue(p);
356 KASSERT(p->p_cpu != NULL);
357 need_resched(p->p_cpu);
358 /* END INLINE EXPANSION */
359
360 if (n != 0)
361 goto restart;
362 else
363 break;
364 }
365 } else
366 q = &p->p_forw;
367 }
368 SCHED_UNLOCK(s);
369 }
370
371 /*
372 * Make all processes sleeping on the specified identifier runnable.
373 */
374 void
375 wakeup(void *chan)
376 {
377 wakeup_n(chan, -1);
378 }
379
380 int
381 sys_sched_yield(struct proc *p, void *v, register_t *retval)
382 {
383 yield();
384 return (0);
385 }
386
387 #ifdef RTHREADS
388
389 int
390 sys_thrsleep(struct proc *p, void *v, register_t *revtal)
391 {
392 struct sys_thrsleep_args *uap = v;
393 long ident = (long)SCARG(uap, ident);
394 int timo = SCARG(uap, timeout);
395 _spinlock_lock_t *lock = SCARG(uap, lock);
396 _spinlock_lock_t unlocked = _SPINLOCK_UNLOCKED;
397 int error;
398
399 p->p_thrslpid = ident;
400
401 if (lock)
402 copyout(&unlocked, lock, sizeof(unlocked));
403 if (hz > 1000)
404 timo = timo * (hz / 1000);
405 else
406 timo = timo / (1000 / hz);
407 if (timo < 0)
408 timo = 0;
409 error = tsleep(&p->p_thrslpid, PUSER | PCATCH, "thrsleep", timo);
410
411 if (error == ERESTART)
412 error = EINTR;
413
414 return (error);
415
416 }
417
418 int
419 sys_thrwakeup(struct proc *p, void *v, register_t *retval)
420 {
421 struct sys_thrwakeup_args *uap = v;
422 long ident = (long)SCARG(uap, ident);
423 int n = SCARG(uap, n);
424 struct proc *q;
425 int found = 0;
426
427 TAILQ_FOREACH(q, &p->p_p->ps_threads, p_thr_link) {
428 if (q->p_thrslpid == ident) {
429 wakeup(&q->p_thrslpid);
430 q->p_thrslpid = 0;
431 if (++found == n)
432 return (0);
433 }
434 }
435 if (!found)
436 return (ESRCH);
437
438 return (0);
439 }
440 #endif