]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_synch.c
xnu-792.6.22.tar.gz
[apple/xnu.git] / bsd / kern / kern_synch.c
CommitLineData
1c79356b 1/*
9bccf70c 2 * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
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.
1c79356b 11 *
e5568f75
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
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.
1c79356b
A
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>
91447636 31#include <sys/proc_internal.h>
1c79356b 32#include <sys/user.h>
91447636 33#include <sys/file_internal.h>
1c79356b
A
34#include <sys/vnode.h>
35#include <sys/kernel.h>
1c79356b
A
36
37#include <machine/spl.h>
38
39#include <kern/queue.h>
40#include <sys/lock.h>
41#include <kern/thread.h>
9bccf70c 42#include <kern/sched_prim.h>
1c79356b
A
43#include <kern/ast.h>
44
45#include <kern/cpu_number.h>
46#include <vm/vm_kern.h>
47
48#include <kern/task.h>
49#include <mach/time_value.h>
91447636
A
50#include <kern/lock.h>
51
1c79356b 52
9bccf70c
A
53#if KTRACE
54#include <sys/uio.h>
55#include <sys/ktrace.h>
56#endif
57
58static void
91447636
A
59_sleep_continue(
60 void *parameter,
61 wait_result_t wresult)
1c79356b 62{
91447636
A
63 register struct proc *p = current_proc();
64 register thread_t self = current_thread();
1c79356b
A
65 struct uthread * ut;
66 int sig, catch;
67 int error = 0;
91447636 68 int dropmutex;
1c79356b 69
55e303ae 70 ut = get_bsdthread_info(self);
91447636
A
71 catch = ut->uu_pri & PCATCH;
72 dropmutex = ut->uu_pri & PDROP;
1c79356b 73
91447636 74 switch (wresult) {
1c79356b
A
75 case THREAD_TIMED_OUT:
76 error = EWOULDBLOCK;
77 break;
78 case THREAD_AWAKENED:
79 /*
80 * Posix implies any signal should be delivered
81 * first, regardless of whether awakened due
82 * to receiving event.
83 */
84 if (!catch)
85 break;
86 /* else fall through */
87 case THREAD_INTERRUPTED:
88 if (catch) {
55e303ae 89 if (thread_should_abort(self)) {
1c79356b
A
90 error = EINTR;
91 } else if (SHOULDissignal(p,ut)) {
92 if (sig = CURSIG(p)) {
93 if (p->p_sigacts->ps_sigintr & sigmask(sig))
94 error = EINTR;
95 else
96 error = ERESTART;
97 }
55e303ae 98 if (thread_should_abort(self)) {
1c79356b
A
99 error = EINTR;
100 }
91447636
A
101 } else if( (ut->uu_flag & ( UT_CANCELDISABLE | UT_CANCEL | UT_CANCELED)) == UT_CANCEL) {
102 /* due to thread cancel */
103 error = EINTR;
104 }
1c79356b
A
105 } else
106 error = EINTR;
107 break;
108 }
109
9bccf70c 110 if (error == EINTR || error == ERESTART)
55e303ae 111 act_set_astbsd(self);
9bccf70c 112
9bccf70c
A
113#if KTRACE
114 if (KTRPOINT(p, KTR_CSW))
91447636 115 ktrcsw(p->p_tracep, 0, 0);
9bccf70c 116#endif
91447636
A
117 if (ut->uu_mtx && !dropmutex)
118 lck_mtx_lock(ut->uu_mtx);
9bccf70c 119
1c79356b
A
120 unix_syscall_return((*ut->uu_continuation)(error));
121}
122
123/*
124 * Give up the processor till a wakeup occurs
125 * on chan, at which time the process
126 * enters the scheduling queue at priority pri.
127 * The most important effect of pri is that when
128 * pri<=PZERO a signal cannot disturb the sleep;
129 * if pri>PZERO signals will be processed.
130 * If pri&PCATCH is set, signals will cause sleep
131 * to return 1, rather than longjmp.
132 * Callers of this routine must be prepared for
133 * premature return, and check that the reason for
134 * sleeping has gone away.
91447636
A
135 *
136 * if msleep was the entry point, than we have a mutex to deal with
137 *
138 * The mutex is unlocked before the caller is blocked, and
139 * relocked before msleep returns unless the priority includes the PDROP
140 * flag... if PDROP is specified, _sleep returns with the mutex unlocked
141 * regardless of whether it actually blocked or not.
1c79356b
A
142 */
143
9bccf70c
A
144static int
145_sleep(
146 caddr_t chan,
91447636
A
147 int pri,
148 const char *wmsg,
9bccf70c 149 u_int64_t abstime,
91447636
A
150 int (*continuation)(int),
151 lck_mtx_t *mtx)
1c79356b
A
152{
153 register struct proc *p;
91447636 154 register thread_t self = current_thread();
1c79356b
A
155 struct uthread * ut;
156 int sig, catch = pri & PCATCH;
91447636 157 int dropmutex = pri & PDROP;
9bccf70c 158 int wait_result;
1c79356b 159 int error = 0;
1c79356b 160
55e303ae 161 ut = get_bsdthread_info(self);
91447636 162
1c79356b
A
163 p = current_proc();
164#if KTRACE
165 if (KTRPOINT(p, KTR_CSW))
91447636 166 ktrcsw(p->p_tracep, 1, 0);
1c79356b
A
167#endif
168 p->p_priority = pri & PRIMASK;
91447636
A
169 p->p_stats->p_ru.ru_nvcsw++;
170
171 if (mtx != NULL && chan != NULL && (thread_continue_t)continuation == THREAD_CONTINUE_NULL) {
172
173 if (abstime)
174 wait_result = lck_mtx_sleep_deadline(mtx, (dropmutex) ? LCK_SLEEP_UNLOCK : 0,
175 chan, (catch) ? THREAD_ABORTSAFE : THREAD_UNINT, abstime);
176 else
177 wait_result = lck_mtx_sleep(mtx, (dropmutex) ? LCK_SLEEP_UNLOCK : 0,
178 chan, (catch) ? THREAD_ABORTSAFE : THREAD_UNINT);
179 }
180 else {
181 if (chan != NULL)
182 assert_wait_deadline(chan, (catch) ? THREAD_ABORTSAFE : THREAD_UNINT, abstime);
183 if (mtx)
184 lck_mtx_unlock(mtx);
185 if (catch) {
186 if (SHOULDissignal(p,ut)) {
187 if (sig = CURSIG(p)) {
188 if (clear_wait(self, THREAD_INTERRUPTED) == KERN_FAILURE)
189 goto block;
190 /* if SIGTTOU or SIGTTIN then block till SIGCONT */
191 if ((pri & PTTYBLOCK) && ((sig == SIGTTOU) || (sig == SIGTTIN))) {
192 p->p_flag |= P_TTYSLEEP;
193 /* reset signal bits */
194 clear_procsiglist(p, sig);
195 assert_wait(&p->p_siglist, THREAD_ABORTSAFE);
196 /* assert wait can block and SIGCONT should be checked */
197 if (p->p_flag & P_TTYSLEEP) {
198 thread_block(THREAD_CONTINUE_NULL);
199
200 if (mtx && !dropmutex)
201 lck_mtx_lock(mtx);
202 }
203
204 /* return with success */
205 error = 0;
206 goto out;
207 }
208 if (p->p_sigacts->ps_sigintr & sigmask(sig))
209 error = EINTR;
210 else
211 error = ERESTART;
212 if (mtx && !dropmutex)
213 lck_mtx_lock(mtx);
1c79356b
A
214 goto out;
215 }
91447636
A
216 }
217 if (thread_should_abort(self)) {
218 if (clear_wait(self, THREAD_INTERRUPTED) == KERN_FAILURE)
219 goto block;
220 error = EINTR;
221
222 if (mtx && !dropmutex)
223 lck_mtx_lock(mtx);
1c79356b
A
224 goto out;
225 }
91447636 226 }
1c79356b 227
55e303ae 228
91447636
A
229block:
230 if ((thread_continue_t)continuation != THREAD_CONTINUE_NULL) {
231 ut->uu_continuation = continuation;
232 ut->uu_pri = pri;
233 ut->uu_timo = abstime? 1: 0;
234 ut->uu_mtx = mtx;
235 (void) thread_block(_sleep_continue);
236 /* NOTREACHED */
237 }
238
239 wait_result = thread_block(THREAD_CONTINUE_NULL);
1c79356b 240
91447636
A
241 if (mtx && !dropmutex)
242 lck_mtx_lock(mtx);
1c79356b
A
243 }
244
9bccf70c 245 switch (wait_result) {
1c79356b
A
246 case THREAD_TIMED_OUT:
247 error = EWOULDBLOCK;
248 break;
249 case THREAD_AWAKENED:
250 /*
251 * Posix implies any signal should be delivered
252 * first, regardless of whether awakened due
253 * to receiving event.
254 */
255 if (!catch)
256 break;
257 /* else fall through */
258 case THREAD_INTERRUPTED:
259 if (catch) {
55e303ae 260 if (thread_should_abort(self)) {
1c79356b 261 error = EINTR;
91447636 262 } else if (SHOULDissignal(p, ut)) {
1c79356b
A
263 if (sig = CURSIG(p)) {
264 if (p->p_sigacts->ps_sigintr & sigmask(sig))
265 error = EINTR;
266 else
267 error = ERESTART;
268 }
55e303ae 269 if (thread_should_abort(self)) {
1c79356b
A
270 error = EINTR;
271 }
272 }
1c79356b
A
273 } else
274 error = EINTR;
275 break;
276 }
277out:
9bccf70c 278 if (error == EINTR || error == ERESTART)
55e303ae 279 act_set_astbsd(self);
91447636 280
9bccf70c
A
281#if KTRACE
282 if (KTRPOINT(p, KTR_CSW))
91447636 283 ktrcsw(p->p_tracep, 0, 0);
9bccf70c 284#endif
1c79356b
A
285 return (error);
286}
287
9bccf70c
A
288int
289sleep(
290 void *chan,
291 int pri)
1c79356b 292{
91447636
A
293 return _sleep((caddr_t)chan, pri, (char *)NULL, 0, (int (*)(int))0, (lck_mtx_t *)0);
294}
295
296int
297msleep0(
298 void *chan,
299 lck_mtx_t *mtx,
300 int pri,
301 const char *wmsg,
302 int timo,
303 int (*continuation)(int))
304{
305 u_int64_t abstime = 0;
306
307 if (timo)
308 clock_interval_to_deadline(timo, NSEC_PER_SEC / hz, &abstime);
309
310 return _sleep((caddr_t)chan, pri, wmsg, abstime, continuation, mtx);
311}
312
313int
314msleep(
315 void *chan,
316 lck_mtx_t *mtx,
317 int pri,
318 const char *wmsg,
319 struct timespec *ts)
320{
321 u_int64_t abstime = 0;
322
323 if (ts && (ts->tv_sec || ts->tv_nsec)) {
324 nanoseconds_to_absolutetime((uint64_t)ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec, &abstime );
325 clock_absolutetime_interval_to_deadline( abstime, &abstime );
326 }
327
328 return _sleep((caddr_t)chan, pri, wmsg, abstime, (int (*)(int))0, mtx);
329}
330
331int
332msleep1(
333 void *chan,
334 lck_mtx_t *mtx,
335 int pri,
336 const char *wmsg,
337 u_int64_t abstime)
338{
339 return _sleep((caddr_t)chan, pri, wmsg, abstime, (int (*)(int))0, mtx);
1c79356b
A
340}
341
9bccf70c
A
342int
343tsleep(
91447636 344 void *chan,
9bccf70c 345 int pri,
91447636 346 const char *wmsg,
9bccf70c
A
347 int timo)
348{
349 u_int64_t abstime = 0;
350
351 if (timo)
352 clock_interval_to_deadline(timo, NSEC_PER_SEC / hz, &abstime);
91447636 353 return _sleep((caddr_t)chan, pri, wmsg, abstime, (int (*)(int))0, (lck_mtx_t *)0);
1c79356b
A
354}
355
9bccf70c
A
356int
357tsleep0(
91447636 358 void *chan,
9bccf70c 359 int pri,
91447636 360 const char *wmsg,
9bccf70c
A
361 int timo,
362 int (*continuation)(int))
1c79356b 363{
9bccf70c
A
364 u_int64_t abstime = 0;
365
366 if (timo)
367 clock_interval_to_deadline(timo, NSEC_PER_SEC / hz, &abstime);
91447636 368 return _sleep((caddr_t)chan, pri, wmsg, abstime, continuation, (lck_mtx_t *)0);
0b4e3aa0
A
369}
370
9bccf70c
A
371int
372tsleep1(
373 void *chan,
91447636
A
374 int pri,
375 const char *wmsg,
9bccf70c 376 u_int64_t abstime,
91447636 377 int (*continuation)(int))
0b4e3aa0 378{
91447636 379 return _sleep((caddr_t)chan, pri, wmsg, abstime, continuation, (lck_mtx_t *)0);
1c79356b
A
380}
381
382/*
383 * Wake up all processes sleeping on chan.
384 */
385void
386wakeup(chan)
387 register void *chan;
388{
9bccf70c 389 thread_wakeup_prim((caddr_t)chan, FALSE, THREAD_AWAKENED);
1c79356b
A
390}
391
392/*
393 * Wake up the first process sleeping on chan.
394 *
395 * Be very sure that the first process is really
396 * the right one to wakeup.
397 */
9bccf70c 398void
1c79356b
A
399wakeup_one(chan)
400 register caddr_t chan;
401{
402 thread_wakeup_prim((caddr_t)chan, TRUE, THREAD_AWAKENED);
403}
404
405/*
406 * Compute the priority of a process when running in user mode.
407 * Arrange to reschedule if the resulting priority is better
408 * than that of the current process.
409 */
410void
411resetpriority(p)
412 register struct proc *p;
413{
0b4e3aa0 414 (void)task_importance(p->task, -p->p_nice);
1c79356b 415}
9bccf70c
A
416
417struct loadavg averunnable =
418 { {0, 0, 0}, FSCALE }; /* load average, of runnable procs */
419/*
420 * Constants for averages over 1, 5, and 15 minutes
421 * when sampling at 5 second intervals.
422 */
423static fixpt_t cexp[3] = {
424 (fixpt_t)(0.9200444146293232 * FSCALE), /* exp(-1/12) */
425 (fixpt_t)(0.9834714538216174 * FSCALE), /* exp(-1/60) */
426 (fixpt_t)(0.9944598480048967 * FSCALE), /* exp(-1/180) */
427};
428
429void
430compute_averunnable(
91447636 431 void *arg)
9bccf70c 432{
91447636 433 unsigned int nrun = *(unsigned int *)arg;
9bccf70c 434 struct loadavg *avg = &averunnable;
91447636 435 register int i;
9bccf70c
A
436
437 for (i = 0; i < 3; i++)
438 avg->ldavg[i] = (cexp[i] * avg->ldavg[i] +
439 nrun * FSCALE * (FSCALE - cexp[i])) >> FSHIFT;
440}