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