Annotation of sys/kern/kern_synch.c, Revision 1.1.1.1
1.1 nbrk 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
CVSweb