]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_synch.c
65765749022af01d67142d7545ac76ea6016e879
[apple/xnu.git] / bsd / kern / kern_synch.c
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 thread_ast_set(th_act, AST_BSD);
105 ast_on(AST_BSD);
106 }
107 if (ut->uu_timo)
108 thread_cancel_timer();
109
110 unix_syscall_return((*ut->uu_continuation)(error));
111 }
112
113 /*
114 * Give up the processor till a wakeup occurs
115 * on chan, at which time the process
116 * enters the scheduling queue at priority pri.
117 * The most important effect of pri is that when
118 * pri<=PZERO a signal cannot disturb the sleep;
119 * if pri>PZERO signals will be processed.
120 * If pri&PCATCH is set, signals will cause sleep
121 * to return 1, rather than longjmp.
122 * Callers of this routine must be prepared for
123 * premature return, and check that the reason for
124 * sleeping has gone away.
125 */
126
127 #if FIXME
128 static __inline__
129 #endif
130 int
131 _sleep(chan, pri, wmsg, timo, continuation, preassert)
132 caddr_t chan;
133 int pri;
134 char *wmsg;
135 int timo;
136 int (*continuation)();
137 int preassert;
138 {
139 register struct proc *p;
140 register thread_t thread = current_thread();
141 thread_act_t th_act;
142 struct uthread * ut;
143 int sig, catch = pri & PCATCH;
144 int sigttblock = pri & PTTYBLOCK;
145 int error = 0;
146 spl_t s;
147
148 s = splhigh();
149
150 th_act = current_act();
151 ut = get_bsdthread_info(th_act);
152
153 p = current_proc();
154 #if KTRACE
155 if (KTRPOINT(p, KTR_CSW))
156 ktrcsw(p->p_tracep, 1, 0);
157 #endif
158 p->p_priority = pri & PRIMASK;
159
160 if (!preassert) {
161 /* it is already pre asserted */
162 if (chan)
163 assert_wait(chan, (catch) ? THREAD_ABORTSAFE : THREAD_UNINT);
164
165 }
166 if (timo)
167 thread_set_timer(timo, NSEC_PER_SEC / hz);
168
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) {
179 unix_master();
180 if (SHOULDissignal(p,ut)) {
181 if (sig = CURSIG(p)) {
182 clear_wait(thread, THREAD_INTERRUPTED);
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 */
187 clear_sigbits(p, sig);
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)
191 thread_block(0);
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;
200 unix_release();
201 goto out;
202 }
203 }
204 if (thread_should_abort(current_thread())) {
205 clear_wait(thread, THREAD_INTERRUPTED);
206 error = EINTR;
207 unix_release();
208 goto out;
209 }
210 if (get_thread_waitevent(thread) == 0) { /*already happened */
211 unix_release();
212 goto out;
213 }
214 unix_release();
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
223 if (continuation != (int (*)()) 0 ) {
224 ut->uu_continuation = continuation;
225 ut->uu_pri = pri;
226 ut->uu_timo = timo;
227 thread_block(_sleep_continue);
228 /* NOTREACHED */
229 }
230
231 thread_block(0);
232
233 #if FIXME /* [ */
234 thread->wait_mesg = NULL;
235 #endif /* FIXME ] */
236 switch (get_thread_waitresult(thread)) {
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) {
251 unix_master();
252 if (thread_should_abort(current_thread())) {
253 error = EINTR;
254 } else if (SHOULDissignal(p,ut)) {
255 if (sig = CURSIG(p)) {
256 if (p->p_sigacts->ps_sigintr & sigmask(sig))
257 error = EINTR;
258 else
259 error = ERESTART;
260 }
261 if (thread_should_abort(current_thread())) {
262 error = EINTR;
263 }
264 }
265 unix_release();
266 } else
267 error = EINTR;
268 break;
269 }
270 out:
271 if ((error == EINTR) || (error == ERESTART)) {
272 thread_ast_set(th_act, AST_BSD);
273 ast_on(AST_BSD);
274 }
275 if (timo)
276 thread_cancel_timer();
277 (void) splx(s);
278 return (error);
279 }
280
281 int sleep(chan, pri)
282 void *chan;
283 int pri;
284 {
285
286 return (_sleep((caddr_t)chan, pri, (char *)NULL, 0, (void (*)())0, 0));
287
288 }
289
290 int tsleep(chan, pri, wmsg, timo)
291 void *chan;
292 int pri;
293 char * wmsg;
294 int timo;
295 {
296 return(_sleep((caddr_t)chan, pri, wmsg, timo, (void (*)())0, 0));
297 }
298
299 int tsleep0(chan, pri, wmsg, timo, continuation)
300 void *chan;
301 int pri;
302 char * wmsg;
303 int timo;
304 int (*continuation)();
305 {
306 #if defined (__i386__)
307 return(_sleep((caddr_t)chan, pri, wmsg, timo, (void (*)())0, 0));
308 #else
309 return(_sleep((caddr_t)chan, pri, wmsg, timo, continuation, 0));
310 #endif
311 }
312
313 /* tsleeps without assertwait or thread block */
314 int tsleep1(chan, pri, wmsg, timo, continuation)
315 void *chan;
316 int pri;
317 char * wmsg;
318 int timo;
319 int (*continuation)();
320 {
321 #if defined (__i386__)
322 return(_sleep((caddr_t)chan, pri, wmsg, timo, (void (*)())0, 1));
323 #else
324 return(_sleep((caddr_t)chan, pri, wmsg, timo, continuation, 1));
325 #endif
326 }
327
328 /*
329 * Wake up all processes sleeping on chan.
330 */
331 void
332 wakeup(chan)
333 register void *chan;
334 {
335 thread_wakeup_prim((caddr_t)chan,FALSE, THREAD_AWAKENED);
336 }
337
338 /*
339 * Wake up the first process sleeping on chan.
340 *
341 * Be very sure that the first process is really
342 * the right one to wakeup.
343 */
344 wakeup_one(chan)
345 register caddr_t chan;
346 {
347 thread_wakeup_prim((caddr_t)chan, TRUE, THREAD_AWAKENED);
348 }
349
350 /*
351 * Compute the priority of a process when running in user mode.
352 * Arrange to reschedule if the resulting priority is better
353 * than that of the current process.
354 */
355 void
356 resetpriority(p)
357 register struct proc *p;
358 {
359 (void)task_importance(p->task, -p->p_nice);
360 }