]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_synch.c
xnu-344.tar.gz
[apple/xnu.git] / bsd / kern / kern_synch.c
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Mach Operating System
24 * Copyright (c) 1987 Carnegie-Mellon University
25 * All rights reserved. The CMU software License Agreement specifies
26 * the terms and conditions for use and redistribution.
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/proc.h>
32 #include <sys/user.h>
33 #include <sys/file.h>
34 #include <sys/vnode.h>
35 #include <sys/kernel.h>
36 #include <sys/buf.h>
37
38 #include <machine/spl.h>
39
40 #include <kern/queue.h>
41 #include <sys/lock.h>
42 #include <kern/thread.h>
43 #include <kern/sched_prim.h>
44 #include <kern/ast.h>
45
46 #include <kern/cpu_number.h>
47 #include <vm/vm_kern.h>
48
49 #include <kern/task.h>
50 #include <mach/time_value.h>
51
52 #if KTRACE
53 #include <sys/uio.h>
54 #include <sys/ktrace.h>
55 #endif
56
57 static void
58 _sleep_continue(void)
59 {
60 register struct proc *p;
61 register thread_t thread = current_thread();
62 thread_act_t th_act;
63 struct uthread * ut;
64 int sig, catch;
65 int error = 0;
66
67 th_act = current_act();
68 ut = get_bsdthread_info(th_act);
69 catch = ut->uu_pri & PCATCH;
70 p = current_proc();
71
72 #if FIXME /* [ */
73 thread->wait_mesg = NULL;
74 #endif /* FIXME ] */
75 switch (get_thread_waitresult(thread)) {
76 case THREAD_TIMED_OUT:
77 error = EWOULDBLOCK;
78 break;
79 case THREAD_AWAKENED:
80 /*
81 * Posix implies any signal should be delivered
82 * first, regardless of whether awakened due
83 * to receiving event.
84 */
85 if (!catch)
86 break;
87 /* else fall through */
88 case THREAD_INTERRUPTED:
89 if (catch) {
90 if (thread_should_abort(current_thread())) {
91 error = EINTR;
92 } else if (SHOULDissignal(p,ut)) {
93 if (sig = CURSIG(p)) {
94 if (p->p_sigacts->ps_sigintr & sigmask(sig))
95 error = EINTR;
96 else
97 error = ERESTART;
98 }
99 if (thread_should_abort(current_thread())) {
100 error = EINTR;
101 }
102 }
103 } else
104 error = EINTR;
105 break;
106 }
107
108 if (error == EINTR || error == ERESTART)
109 act_set_astbsd(th_act);
110
111 if (ut->uu_timo)
112 thread_cancel_timer();
113
114 #if KTRACE
115 if (KTRPOINT(p, KTR_CSW))
116 ktrcsw(p->p_tracep, 0, 0, -1);
117 #endif
118
119 unix_syscall_return((*ut->uu_continuation)(error));
120 }
121
122 /*
123 * Give up the processor till a wakeup occurs
124 * on chan, at which time the process
125 * enters the scheduling queue at priority pri.
126 * The most important effect of pri is that when
127 * pri<=PZERO a signal cannot disturb the sleep;
128 * if pri>PZERO signals will be processed.
129 * If pri&PCATCH is set, signals will cause sleep
130 * to return 1, rather than longjmp.
131 * Callers of this routine must be prepared for
132 * premature return, and check that the reason for
133 * sleeping has gone away.
134 */
135
136 static int
137 _sleep(
138 caddr_t chan,
139 int pri,
140 char *wmsg,
141 u_int64_t abstime,
142 int (*continuation)(int))
143 {
144 register struct proc *p;
145 register thread_t thread = current_thread();
146 thread_act_t th_act;
147 struct uthread * ut;
148 int sig, catch = pri & PCATCH;
149 int sigttblock = pri & PTTYBLOCK;
150 int wait_result;
151 int error = 0;
152 spl_t s;
153
154 s = splhigh();
155
156 th_act = current_act();
157 ut = get_bsdthread_info(th_act);
158
159 p = current_proc();
160 #if KTRACE
161 if (KTRPOINT(p, KTR_CSW))
162 ktrcsw(p->p_tracep, 1, 0, -1);
163 #endif
164 p->p_priority = pri & PRIMASK;
165
166 if (chan)
167 wait_result = assert_wait(chan,
168 (catch) ? THREAD_ABORTSAFE : THREAD_UNINT);
169
170 if (abstime)
171 thread_set_timer_deadline(abstime);
172
173 /*
174 * We start our timeout
175 * before calling CURSIG, as we could stop there, and a wakeup
176 * or a SIGCONT (or both) could occur while we were stopped.
177 * A SIGCONT would cause us to be marked as SSLEEP
178 * without resuming us, thus we must be ready for sleep
179 * when CURSIG is called. If the wakeup happens while we're
180 * stopped, p->p_wchan will be 0 upon return from CURSIG.
181 */
182 if (catch) {
183 if (SHOULDissignal(p,ut)) {
184 if (sig = CURSIG(p)) {
185 clear_wait(thread, THREAD_INTERRUPTED);
186 /* if SIGTTOU or SIGTTIN then block till SIGCONT */
187 if (sigttblock && ((sig == SIGTTOU) || (sig == SIGTTIN))) {
188 p->p_flag |= P_TTYSLEEP;
189 /* reset signal bits */
190 clear_procsiglist(p, sig);
191 assert_wait(&p->p_siglist, THREAD_ABORTSAFE);
192 /* assert wait can block and SIGCONT should be checked */
193 if (p->p_flag & P_TTYSLEEP)
194 thread_block(THREAD_CONTINUE_NULL);
195 /* return with success */
196 error = 0;
197 goto out;
198 }
199 if (p->p_sigacts->ps_sigintr & sigmask(sig))
200 error = EINTR;
201 else
202 error = ERESTART;
203 goto out;
204 }
205 }
206 if (thread_should_abort(current_thread())) {
207 clear_wait(thread, THREAD_INTERRUPTED);
208 error = EINTR;
209 goto out;
210 }
211 if (get_thread_waitresult(thread) != THREAD_WAITING) {
212 /*already happened */
213 goto out;
214 }
215 }
216
217 #if FIXME /* [ */
218 thread->wait_mesg = wmsg;
219 #endif /* FIXME ] */
220 splx(s);
221 p->p_stats->p_ru.ru_nvcsw++;
222
223 if (continuation != THREAD_CONTINUE_NULL ) {
224 ut->uu_continuation = continuation;
225 ut->uu_pri = pri;
226 ut->uu_timo = abstime? 1: 0;
227 (void) thread_block(_sleep_continue);
228 /* NOTREACHED */
229 }
230
231 wait_result = thread_block(THREAD_CONTINUE_NULL);
232
233 #if FIXME /* [ */
234 thread->wait_mesg = NULL;
235 #endif /* FIXME ] */
236 switch (wait_result) {
237 case THREAD_TIMED_OUT:
238 error = EWOULDBLOCK;
239 break;
240 case THREAD_AWAKENED:
241 /*
242 * Posix implies any signal should be delivered
243 * first, regardless of whether awakened due
244 * to receiving event.
245 */
246 if (!catch)
247 break;
248 /* else fall through */
249 case THREAD_INTERRUPTED:
250 if (catch) {
251 if (thread_should_abort(current_thread())) {
252 error = EINTR;
253 } else if (SHOULDissignal(p,ut)) {
254 if (sig = CURSIG(p)) {
255 if (p->p_sigacts->ps_sigintr & sigmask(sig))
256 error = EINTR;
257 else
258 error = ERESTART;
259 }
260 if (thread_should_abort(current_thread())) {
261 error = EINTR;
262 }
263 }
264 } else
265 error = EINTR;
266 break;
267 }
268 out:
269 if (error == EINTR || error == ERESTART)
270 act_set_astbsd(th_act);
271 if (abstime)
272 thread_cancel_timer();
273 (void) splx(s);
274 #if KTRACE
275 if (KTRPOINT(p, KTR_CSW))
276 ktrcsw(p->p_tracep, 0, 0, -1);
277 #endif
278 return (error);
279 }
280
281 int
282 sleep(
283 void *chan,
284 int pri)
285 {
286 return _sleep((caddr_t)chan, pri, (char *)NULL, 0, (int (*)(int))0);
287 }
288
289 int
290 tsleep(
291 void *chan,
292 int pri,
293 char *wmsg,
294 int timo)
295 {
296 u_int64_t abstime = 0;
297
298 if (timo)
299 clock_interval_to_deadline(timo, NSEC_PER_SEC / hz, &abstime);
300 return _sleep((caddr_t)chan, pri, wmsg, abstime, (int (*)(int))0);
301 }
302
303 int
304 tsleep0(
305 void *chan,
306 int pri,
307 char *wmsg,
308 int timo,
309 int (*continuation)(int))
310 {
311 u_int64_t abstime = 0;
312
313 if (timo)
314 clock_interval_to_deadline(timo, NSEC_PER_SEC / hz, &abstime);
315 return _sleep((caddr_t)chan, pri, wmsg, abstime, continuation);
316 }
317
318 int
319 tsleep1(
320 void *chan,
321 int pri,
322 char *wmsg,
323 u_int64_t abstime,
324 int (*continuation)(int))
325 {
326 return _sleep((caddr_t)chan, pri, wmsg, abstime, continuation);
327 }
328
329 /*
330 * Wake up all processes sleeping on chan.
331 */
332 void
333 wakeup(chan)
334 register void *chan;
335 {
336 thread_wakeup_prim((caddr_t)chan, FALSE, THREAD_AWAKENED);
337 }
338
339 /*
340 * Wake up the first process sleeping on chan.
341 *
342 * Be very sure that the first process is really
343 * the right one to wakeup.
344 */
345 void
346 wakeup_one(chan)
347 register caddr_t chan;
348 {
349 thread_wakeup_prim((caddr_t)chan, TRUE, THREAD_AWAKENED);
350 }
351
352 /*
353 * Compute the priority of a process when running in user mode.
354 * Arrange to reschedule if the resulting priority is better
355 * than that of the current process.
356 */
357 void
358 resetpriority(p)
359 register struct proc *p;
360 {
361 (void)task_importance(p->task, -p->p_nice);
362 }
363
364 struct loadavg averunnable =
365 { {0, 0, 0}, FSCALE }; /* load average, of runnable procs */
366 /*
367 * Constants for averages over 1, 5, and 15 minutes
368 * when sampling at 5 second intervals.
369 */
370 static fixpt_t cexp[3] = {
371 (fixpt_t)(0.9200444146293232 * FSCALE), /* exp(-1/12) */
372 (fixpt_t)(0.9834714538216174 * FSCALE), /* exp(-1/60) */
373 (fixpt_t)(0.9944598480048967 * FSCALE), /* exp(-1/180) */
374 };
375
376 void
377 compute_averunnable(
378 register int nrun)
379 {
380 register int i;
381 struct loadavg *avg = &averunnable;
382
383 for (i = 0; i < 3; i++)
384 avg->ldavg[i] = (cexp[i] * avg->ldavg[i] +
385 nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
386 }