]>
Commit | Line | Data |
---|---|---|
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 | ||
57 | static 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 | ||
131 | static 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 | ||
212 | block: | |
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 | } | |
259 | out: | |
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 | ||
272 | int | |
273 | sleep( | |
274 | void *chan, | |
275 | int pri) | |
276 | { | |
277 | return _sleep((caddr_t)chan, pri, (char *)NULL, 0, (int (*)(int))0); | |
278 | } | |
279 | ||
280 | int | |
281 | tsleep( | |
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 | ||
294 | int | |
295 | tsleep0( | |
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 | ||
309 | int | |
310 | tsleep1( | |
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 | */ | |
323 | void | |
324 | wakeup(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 | */ | |
336 | void | |
337 | wakeup_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 | */ | |
348 | void | |
349 | resetpriority(p) | |
350 | register struct proc *p; | |
351 | { | |
352 | (void)task_importance(p->task, -p->p_nice); | |
353 | } | |
354 | ||
355 | struct 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 | */ | |
361 | static 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 | ||
367 | void | |
368 | compute_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 | } |