]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/kern/kern_synch.c
xnu-517.9.4.tar.gz
[apple/xnu.git] / bsd / kern / kern_synch.c
... / ...
CommitLineData
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
57static void
58_sleep_continue(void)
59{
60 register struct proc *p;
61 register thread_t self = current_act();
62 struct uthread * ut;
63 int sig, catch;
64 int error = 0;
65
66 ut = get_bsdthread_info(self);
67 catch = ut->uu_pri & PCATCH;
68 p = current_proc();
69
70 switch (get_thread_waitresult(self)) {
71 case THREAD_TIMED_OUT:
72 error = EWOULDBLOCK;
73 break;
74 case THREAD_AWAKENED:
75 /*
76 * Posix implies any signal should be delivered
77 * first, regardless of whether awakened due
78 * to receiving event.
79 */
80 if (!catch)
81 break;
82 /* else fall through */
83 case THREAD_INTERRUPTED:
84 if (catch) {
85 if (thread_should_abort(self)) {
86 error = EINTR;
87 } else if (SHOULDissignal(p,ut)) {
88 if (sig = CURSIG(p)) {
89 if (p->p_sigacts->ps_sigintr & sigmask(sig))
90 error = EINTR;
91 else
92 error = ERESTART;
93 }
94 if (thread_should_abort(self)) {
95 error = EINTR;
96 }
97 }
98 } else
99 error = EINTR;
100 break;
101 }
102
103 if (error == EINTR || error == ERESTART)
104 act_set_astbsd(self);
105
106 if (ut->uu_timo)
107 thread_cancel_timer();
108
109#if KTRACE
110 if (KTRPOINT(p, KTR_CSW))
111 ktrcsw(p->p_tracep, 0, 0, -1);
112#endif
113
114 unix_syscall_return((*ut->uu_continuation)(error));
115}
116
117/*
118 * Give up the processor till a wakeup occurs
119 * on chan, at which time the process
120 * enters the scheduling queue at priority pri.
121 * The most important effect of pri is that when
122 * pri<=PZERO a signal cannot disturb the sleep;
123 * if pri>PZERO signals will be processed.
124 * If pri&PCATCH is set, signals will cause sleep
125 * to return 1, rather than longjmp.
126 * Callers of this routine must be prepared for
127 * premature return, and check that the reason for
128 * sleeping has gone away.
129 */
130
131static int
132_sleep(
133 caddr_t chan,
134 int pri,
135 char *wmsg,
136 u_int64_t abstime,
137 int (*continuation)(int))
138{
139 register struct proc *p;
140 register thread_t self = current_act();
141 struct uthread * ut;
142 int sig, catch = pri & PCATCH;
143 int sigttblock = pri & PTTYBLOCK;
144 int wait_result;
145 int error = 0;
146 spl_t s;
147
148 s = splhigh();
149
150 ut = get_bsdthread_info(self);
151
152 p = current_proc();
153#if KTRACE
154 if (KTRPOINT(p, KTR_CSW))
155 ktrcsw(p->p_tracep, 1, 0, -1);
156#endif
157 p->p_priority = pri & PRIMASK;
158
159 if (chan != NULL)
160 assert_wait_prim(chan, NULL, abstime,
161 (catch) ? THREAD_ABORTSAFE : THREAD_UNINT);
162 else
163 if (abstime != 0)
164 thread_set_timer_deadline(abstime);
165
166 /*
167 * We start our timeout
168 * before calling CURSIG, as we could stop there, and a wakeup
169 * or a SIGCONT (or both) could occur while we were stopped.
170 * A SIGCONT would cause us to be marked as SSLEEP
171 * without resuming us, thus we must be ready for sleep
172 * when CURSIG is called. If the wakeup happens while we're
173 * stopped, p->p_wchan will be 0 upon return from CURSIG.
174 */
175 if (catch) {
176 if (SHOULDissignal(p,ut)) {
177 if (sig = CURSIG(p)) {
178 if (clear_wait(self, THREAD_INTERRUPTED) == KERN_FAILURE)
179 goto block;
180 /* if SIGTTOU or SIGTTIN then block till SIGCONT */
181 if (sigttblock && ((sig == SIGTTOU) || (sig == SIGTTIN))) {
182 p->p_flag |= P_TTYSLEEP;
183 /* reset signal bits */
184 clear_procsiglist(p, sig);
185 assert_wait(&p->p_siglist, THREAD_ABORTSAFE);
186 /* assert wait can block and SIGCONT should be checked */
187 if (p->p_flag & P_TTYSLEEP)
188 thread_block(THREAD_CONTINUE_NULL);
189 /* return with success */
190 error = 0;
191 goto out;
192 }
193 if (p->p_sigacts->ps_sigintr & sigmask(sig))
194 error = EINTR;
195 else
196 error = ERESTART;
197 goto out;
198 }
199 }
200 if (thread_should_abort(self)) {
201 if (clear_wait(self, THREAD_INTERRUPTED) == KERN_FAILURE)
202 goto block;
203 error = EINTR;
204 goto out;
205 }
206 if (get_thread_waitresult(self) != THREAD_WAITING) {
207 /*already happened */
208 goto out;
209 }
210 }
211
212block:
213
214 splx(s);
215 p->p_stats->p_ru.ru_nvcsw++;
216
217 if ((thread_continue_t)continuation != THREAD_CONTINUE_NULL ) {
218 ut->uu_continuation = continuation;
219 ut->uu_pri = pri;
220 ut->uu_timo = abstime? 1: 0;
221 (void) thread_block(_sleep_continue);
222 /* NOTREACHED */
223 }
224
225 wait_result = thread_block(THREAD_CONTINUE_NULL);
226
227 switch (wait_result) {
228 case THREAD_TIMED_OUT:
229 error = EWOULDBLOCK;
230 break;
231 case THREAD_AWAKENED:
232 /*
233 * Posix implies any signal should be delivered
234 * first, regardless of whether awakened due
235 * to receiving event.
236 */
237 if (!catch)
238 break;
239 /* else fall through */
240 case THREAD_INTERRUPTED:
241 if (catch) {
242 if (thread_should_abort(self)) {
243 error = EINTR;
244 } else if (SHOULDissignal(p,ut)) {
245 if (sig = CURSIG(p)) {
246 if (p->p_sigacts->ps_sigintr & sigmask(sig))
247 error = EINTR;
248 else
249 error = ERESTART;
250 }
251 if (thread_should_abort(self)) {
252 error = EINTR;
253 }
254 }
255 } else
256 error = EINTR;
257 break;
258 }
259out:
260 if (error == EINTR || error == ERESTART)
261 act_set_astbsd(self);
262 if (abstime)
263 thread_cancel_timer();
264 (void) splx(s);
265#if KTRACE
266 if (KTRPOINT(p, KTR_CSW))
267 ktrcsw(p->p_tracep, 0, 0, -1);
268#endif
269 return (error);
270}
271
272int
273sleep(
274 void *chan,
275 int pri)
276{
277 return _sleep((caddr_t)chan, pri, (char *)NULL, 0, (int (*)(int))0);
278}
279
280int
281tsleep(
282 void *chan,
283 int pri,
284 char *wmsg,
285 int timo)
286{
287 u_int64_t abstime = 0;
288
289 if (timo)
290 clock_interval_to_deadline(timo, NSEC_PER_SEC / hz, &abstime);
291 return _sleep((caddr_t)chan, pri, wmsg, abstime, (int (*)(int))0);
292}
293
294int
295tsleep0(
296 void *chan,
297 int pri,
298 char *wmsg,
299 int timo,
300 int (*continuation)(int))
301{
302 u_int64_t abstime = 0;
303
304 if (timo)
305 clock_interval_to_deadline(timo, NSEC_PER_SEC / hz, &abstime);
306 return _sleep((caddr_t)chan, pri, wmsg, abstime, continuation);
307}
308
309int
310tsleep1(
311 void *chan,
312 int pri,
313 char *wmsg,
314 u_int64_t abstime,
315 int (*continuation)(int))
316{
317 return _sleep((caddr_t)chan, pri, wmsg, abstime, continuation);
318}
319
320/*
321 * Wake up all processes sleeping on chan.
322 */
323void
324wakeup(chan)
325 register void *chan;
326{
327 thread_wakeup_prim((caddr_t)chan, FALSE, THREAD_AWAKENED);
328}
329
330/*
331 * Wake up the first process sleeping on chan.
332 *
333 * Be very sure that the first process is really
334 * the right one to wakeup.
335 */
336void
337wakeup_one(chan)
338 register caddr_t chan;
339{
340 thread_wakeup_prim((caddr_t)chan, TRUE, THREAD_AWAKENED);
341}
342
343/*
344 * Compute the priority of a process when running in user mode.
345 * Arrange to reschedule if the resulting priority is better
346 * than that of the current process.
347 */
348void
349resetpriority(p)
350 register struct proc *p;
351{
352 (void)task_importance(p->task, -p->p_nice);
353}
354
355struct loadavg averunnable =
356 { {0, 0, 0}, FSCALE }; /* load average, of runnable procs */
357/*
358 * Constants for averages over 1, 5, and 15 minutes
359 * when sampling at 5 second intervals.
360 */
361static fixpt_t cexp[3] = {
362 (fixpt_t)(0.9200444146293232 * FSCALE), /* exp(-1/12) */
363 (fixpt_t)(0.9834714538216174 * FSCALE), /* exp(-1/60) */
364 (fixpt_t)(0.9944598480048967 * FSCALE), /* exp(-1/180) */
365};
366
367void
368compute_averunnable(
369 register int nrun)
370{
371 register int i;
372 struct loadavg *avg = &averunnable;
373
374 for (i = 0; i < 3; i++)
375 avg->ldavg[i] = (cexp[i] * avg->ldavg[i] +
376 nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
377}