]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_synch.c
xnu-123.5.tar.gz
[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 #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