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