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