]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 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/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> | |
50 | ||
51 | _sleep_continue() | |
52 | { | |
53 | register struct proc *p; | |
54 | register thread_t thread = current_thread(); | |
55 | thread_act_t th_act; | |
56 | struct uthread * ut; | |
57 | int sig, catch; | |
58 | int error = 0; | |
59 | ||
60 | th_act = current_act(); | |
61 | ut = get_bsdthread_info(th_act); | |
62 | catch = ut->uu_pri & PCATCH; | |
63 | p = current_proc(); | |
64 | ||
65 | #if FIXME /* [ */ | |
66 | thread->wait_mesg = NULL; | |
67 | #endif /* FIXME ] */ | |
68 | switch (get_thread_waitresult(thread)) { | |
69 | case THREAD_TIMED_OUT: | |
70 | error = EWOULDBLOCK; | |
71 | break; | |
72 | case THREAD_AWAKENED: | |
73 | /* | |
74 | * Posix implies any signal should be delivered | |
75 | * first, regardless of whether awakened due | |
76 | * to receiving event. | |
77 | */ | |
78 | if (!catch) | |
79 | break; | |
80 | /* else fall through */ | |
81 | case THREAD_INTERRUPTED: | |
82 | if (catch) { | |
83 | unix_master(); | |
84 | if (thread_should_abort(current_thread())) { | |
85 | error = EINTR; | |
86 | } else if (SHOULDissignal(p,ut)) { | |
87 | if (sig = CURSIG(p)) { | |
88 | if (p->p_sigacts->ps_sigintr & sigmask(sig)) | |
89 | error = EINTR; | |
90 | else | |
91 | error = ERESTART; | |
92 | } | |
93 | if (thread_should_abort(current_thread())) { | |
94 | error = EINTR; | |
95 | } | |
96 | } | |
97 | unix_release(); | |
98 | } else | |
99 | error = EINTR; | |
100 | break; | |
101 | } | |
102 | ||
103 | if ((error == EINTR) || (error == ERESTART)) { | |
104 | #ifdef BSD_USE_APC | |
105 | thread_apc_set(th_act, bsd_ast); | |
106 | #else | |
107 | thread_ast_set(th_act, AST_BSD); | |
108 | ast_on(AST_BSD); | |
109 | #endif | |
110 | } | |
111 | if (ut->uu_timo) | |
112 | thread_cancel_timer(); | |
113 | ||
114 | #if 0 | |
115 | /* We should never get here without funnel, so we should not grab again */ | |
116 | thread_funnel_set(kernel_flock, TRUE); | |
117 | #endif /* 0 */ | |
118 | unix_syscall_return((*ut->uu_continuation)(error)); | |
119 | } | |
120 | ||
121 | /* | |
122 | * Give up the processor till a wakeup occurs | |
123 | * on chan, at which time the process | |
124 | * enters the scheduling queue at priority pri. | |
125 | * The most important effect of pri is that when | |
126 | * pri<=PZERO a signal cannot disturb the sleep; | |
127 | * if pri>PZERO signals will be processed. | |
128 | * If pri&PCATCH is set, signals will cause sleep | |
129 | * to return 1, rather than longjmp. | |
130 | * Callers of this routine must be prepared for | |
131 | * premature return, and check that the reason for | |
132 | * sleeping has gone away. | |
133 | */ | |
134 | ||
135 | #if FIXME | |
136 | static __inline__ | |
137 | #endif | |
138 | int | |
139 | _sleep(chan, pri, wmsg, timo, continuation) | |
140 | caddr_t chan; | |
141 | int pri; | |
142 | char *wmsg; | |
143 | int timo; | |
144 | int (*continuation)(); | |
145 | { | |
146 | register struct proc *p; | |
147 | register thread_t thread = current_thread(); | |
148 | thread_act_t th_act; | |
149 | struct uthread * ut; | |
150 | int sig, catch = pri & PCATCH; | |
151 | int sigttblock = pri & PTTYBLOCK; | |
152 | int error = 0; | |
153 | spl_t s; | |
154 | ||
155 | s = splhigh(); | |
156 | ||
157 | th_act = current_act(); | |
158 | ut = get_bsdthread_info(th_act); | |
159 | ||
160 | p = current_proc(); | |
161 | #if KTRACE | |
162 | if (KTRPOINT(p, KTR_CSW)) | |
163 | ktrcsw(p->p_tracep, 1, 0); | |
164 | #endif | |
165 | p->p_priority = pri & PRIMASK; | |
166 | ||
167 | if (chan) | |
168 | assert_wait(chan, (catch) ? THREAD_ABORTSAFE : THREAD_UNINT); | |
169 | ||
170 | if (timo) | |
171 | thread_set_timer(timo, NSEC_PER_SEC / hz); | |
172 | /* | |
173 | * We start our timeout | |
174 | * before calling CURSIG, as we could stop there, and a wakeup | |
175 | * or a SIGCONT (or both) could occur while we were stopped. | |
176 | * A SIGCONT would cause us to be marked as SSLEEP | |
177 | * without resuming us, thus we must be ready for sleep | |
178 | * when CURSIG is called. If the wakeup happens while we're | |
179 | * stopped, p->p_wchan will be 0 upon return from CURSIG. | |
180 | */ | |
181 | if (catch) { | |
182 | unix_master(); | |
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 */ | |
190 | clear_sigbits(p, sig); | |
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) | |
194 | thread_block(0); | |
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; | |
203 | unix_release(); | |
204 | goto out; | |
205 | } | |
206 | } | |
207 | if (thread_should_abort(current_thread())) { | |
208 | clear_wait(thread, THREAD_INTERRUPTED); | |
209 | error = EINTR; | |
210 | unix_release(); | |
211 | goto out; | |
212 | } | |
213 | if (get_thread_waitevent(thread) == 0) { /*already happened */ | |
214 | unix_release(); | |
215 | goto out; | |
216 | } | |
217 | unix_release(); | |
218 | } | |
219 | ||
220 | #if FIXME /* [ */ | |
221 | thread->wait_mesg = wmsg; | |
222 | #endif /* FIXME ] */ | |
223 | splx(s); | |
224 | p->p_stats->p_ru.ru_nvcsw++; | |
225 | ||
226 | if (continuation != (int (*)()) 0 ) { | |
227 | ut->uu_continuation = continuation; | |
228 | ut->uu_pri = pri; | |
229 | ut->uu_timo = timo; | |
230 | thread_block(_sleep_continue); | |
231 | /* NOTREACHED */ | |
232 | } | |
233 | ||
234 | thread_block(0); | |
235 | ||
236 | #if FIXME /* [ */ | |
237 | thread->wait_mesg = NULL; | |
238 | #endif /* FIXME ] */ | |
239 | switch (get_thread_waitresult(thread)) { | |
240 | case THREAD_TIMED_OUT: | |
241 | error = EWOULDBLOCK; | |
242 | break; | |
243 | case THREAD_AWAKENED: | |
244 | /* | |
245 | * Posix implies any signal should be delivered | |
246 | * first, regardless of whether awakened due | |
247 | * to receiving event. | |
248 | */ | |
249 | if (!catch) | |
250 | break; | |
251 | /* else fall through */ | |
252 | case THREAD_INTERRUPTED: | |
253 | if (catch) { | |
254 | unix_master(); | |
255 | if (thread_should_abort(current_thread())) { | |
256 | error = EINTR; | |
257 | } else if (SHOULDissignal(p,ut)) { | |
258 | if (sig = CURSIG(p)) { | |
259 | if (p->p_sigacts->ps_sigintr & sigmask(sig)) | |
260 | error = EINTR; | |
261 | else | |
262 | error = ERESTART; | |
263 | } | |
264 | if (thread_should_abort(current_thread())) { | |
265 | error = EINTR; | |
266 | } | |
267 | } | |
268 | unix_release(); | |
269 | } else | |
270 | error = EINTR; | |
271 | break; | |
272 | } | |
273 | out: | |
274 | if ((error == EINTR) || (error == ERESTART)) { | |
275 | #ifdef BSD_USE_APC | |
276 | thread_apc_set(th_act, bsd_ast); | |
277 | #else | |
278 | thread_ast_set(th_act, AST_BSD); | |
279 | ast_on(AST_BSD); | |
280 | #endif | |
281 | } | |
282 | if (timo) | |
283 | thread_cancel_timer(); | |
284 | (void) splx(s); | |
285 | return (error); | |
286 | } | |
287 | ||
288 | int sleep(chan, pri) | |
289 | void *chan; | |
290 | int pri; | |
291 | { | |
292 | ||
293 | return (_sleep((caddr_t)chan, pri, (char *)NULL, 0, (void (*)())0 )); | |
294 | ||
295 | } | |
296 | ||
297 | int tsleep(chan, pri, wmsg, timo) | |
298 | void *chan; | |
299 | int pri; | |
300 | char * wmsg; | |
301 | int timo; | |
302 | { | |
303 | return(_sleep((caddr_t)chan, pri, wmsg, timo, (void (*)())0 )); | |
304 | } | |
305 | ||
306 | int tsleep0(chan, pri, wmsg, timo, continuation) | |
307 | void *chan; | |
308 | int pri; | |
309 | char * wmsg; | |
310 | int timo; | |
311 | int (*continuation)(); | |
312 | { | |
313 | #if defined (__i386__) | |
314 | return(_sleep((caddr_t)chan, pri, wmsg, timo, (void (*)())0 )); | |
315 | #else | |
316 | return(_sleep((caddr_t)chan, pri, wmsg, timo, continuation)); | |
317 | #endif | |
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 | wakeup_one(chan) | |
337 | register caddr_t chan; | |
338 | { | |
339 | thread_wakeup_prim((caddr_t)chan, TRUE, THREAD_AWAKENED); | |
340 | } | |
341 | ||
342 | /* | |
343 | * Compute the priority of a process when running in user mode. | |
344 | * Arrange to reschedule if the resulting priority is better | |
345 | * than that of the current process. | |
346 | */ | |
347 | void | |
348 | resetpriority(p) | |
349 | register struct proc *p; | |
350 | { | |
351 | int newpri; | |
352 | #if FIXME | |
353 | if (p->p_nice < 0) | |
354 | newpri = BASEPRI_USER + | |
355 | (p->p_nice * (MAXPRI_USER - BASEPRI_USER)) / PRIO_MIN; | |
356 | else | |
357 | newpri = BASEPRI_USER - | |
358 | (p->p_nice * BASEPRI_USER) / PRIO_MAX; | |
359 | ||
360 | (void)task_priority(p->task, newpri, TRUE); | |
361 | #endif /* FIXME */ | |
362 | } | |
363 |