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