1 /* $NetBSD: mach_thread.c,v 1.34.2.1 2005/10/04 22:08:11 tron Exp $ */
2
3 /*-
4 * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: mach_thread.c,v 1.34.2.1 2005/10/04 22:08:11 tron Exp $");
41
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/kernel.h>
45 #include <sys/systm.h>
46 #include <sys/signal.h>
47 #include <sys/lock.h>
48 #include <sys/queue.h>
49 #include <sys/proc.h>
50 #include <sys/resource.h>
51 #include <sys/resourcevar.h>
52 #include <sys/sa.h>
53 #include <sys/savar.h>
54
55 #include <compat/mach/mach_types.h>
56 #include <compat/mach/mach_message.h>
57 #include <compat/mach/mach_exec.h>
58 #include <compat/mach/mach_clock.h>
59 #include <compat/mach/mach_port.h>
60 #include <compat/mach/mach_task.h>
61 #include <compat/mach/mach_thread.h>
62 #include <compat/mach/mach_errno.h>
63 #include <compat/mach/mach_services.h>
64 #include <compat/mach/mach_syscallargs.h>
65
66 int
67 mach_sys_syscall_thread_switch(l, v, retval)
68 struct lwp *l;
69 void *v;
70 register_t *retval;
71 {
72 struct mach_sys_syscall_thread_switch_args /* {
73 syscallarg(mach_port_name_t) thread_name;
74 syscallarg(int) option;
75 syscallarg(mach_msg_timeout_t) option_time;
76 } */ *uap = v;
77 int timeout;
78 struct mach_emuldata *med;
79
80 med = (struct mach_emuldata *)l->l_proc->p_emuldata;
81 timeout = SCARG(uap, option_time) * hz / 1000;
82
83 /*
84 * The day we will be able to find out the struct proc from
85 * the port number, try to use preempt() to call the right thread.
86 * [- but preempt() is for _involuntary_ context switches.]
87 */
88 switch(SCARG(uap, option)) {
89 case MACH_SWITCH_OPTION_NONE:
90 yield();
91 break;
92
93 case MACH_SWITCH_OPTION_WAIT:
94 med->med_thpri = 1;
95 while (med->med_thpri != 0)
96 (void)tsleep(&med->med_thpri, PZERO|PCATCH,
97 "thread_switch", timeout);
98 break;
99
100 case MACH_SWITCH_OPTION_DEPRESS:
101 case MACH_SWITCH_OPTION_IDLE:
102 /* Use a callout to restore the priority after depression? */
103 med->med_thpri = l->l_priority;
104 l->l_priority = MAXPRI;
105 break;
106
107 default:
108 uprintf("mach_sys_syscall_thread_switch(): unknown option %d\n", SCARG(uap, option));
109 break;
110 }
111 return 0;
112 }
113
114 int
115 mach_sys_swtch_pri(l, v, retval)
116 struct lwp *l;
117 void *v;
118 register_t *retval;
119 {
120 #if 0 /* pri is not used yet */
121 struct mach_sys_swtch_pri_args /* {
122 syscallarg(int) pri;
123 } */ *uap = v;
124 #endif
125 int s;
126
127 /*
128 * Copied from preempt(9). We cannot just call preempt
129 * because we want to return mi_switch(9) return value.
130 */
131 SCHED_LOCK(s);
132 l->l_priority = l->l_usrpri;
133 l->l_stat = LSRUN;
134 setrunqueue(l);
135 l->l_proc->p_stats->p_ru.ru_nivcsw++;
136 *retval = mi_switch(l, NULL);
137 SCHED_ASSERT_UNLOCKED();
138 splx(s);
139 if ((l->l_flag & L_SA) != 0 && *retval != 0)
140 sa_preempt(l);
141
142 return 0;
143 }
144
145 int
146 mach_sys_swtch(l, v, retval)
147 struct lwp *l;
148 void *v;
149 register_t *retval;
150 {
151 struct mach_sys_swtch_pri_args cup;
152
153 SCARG(&cup, pri) = 0;
154
155 return mach_sys_swtch_pri(l, &cup, retval);
156 }
157
158
159 int
160 mach_thread_policy(args)
161 struct mach_trap_args *args;
162 {
163 mach_thread_policy_request_t *req = args->smsg;
164 mach_thread_policy_reply_t *rep = args->rmsg;
165 size_t *msglen = args->rsize;
166 int end_offset;
167
168 /* Sanity check req_count */
169 end_offset = req->req_count +
170 (sizeof(req->req_setlimit) / sizeof(req->req_base[0]));
171 if (MACH_REQMSG_OVERFLOW(args, req->req_base[end_offset]))
172 return mach_msg_error(args, EINVAL);
173
174 uprintf("Unimplemented mach_thread_policy\n");
175
176 *msglen = sizeof(*rep);
177 mach_set_header(rep, req, *msglen);
178
179 rep->rep_retval = 0;
180
181 mach_set_trailer(rep, *msglen);
182
183 return 0;
184 }
185
186 /* XXX it might be possible to use this on another task */
187 int
188 mach_thread_create_running(args)
189 struct mach_trap_args *args;
190 {
191 mach_thread_create_running_request_t *req = args->smsg;
192 mach_thread_create_running_reply_t *rep = args->rmsg;
193 size_t *msglen = args->rsize;
194 struct lwp *l = args->l;
195 struct proc *p = l->l_proc;
196 struct mach_create_thread_child_args mctc;
197 struct mach_right *child_mr;
198 struct mach_lwp_emuldata *mle;
199 vaddr_t uaddr;
200 int flags;
201 int error;
202 int inmem;
203 int s;
204 int end_offset;
205
206 /* Sanity check req_count */
207 end_offset = req->req_count;
208 if (MACH_REQMSG_OVERFLOW(args, req->req_state[end_offset]))
209 return mach_msg_error(args, EINVAL);
210
211 /*
212 * Prepare the data we want to transmit to the child.
213 */
214 mctc.mctc_flavor = req->req_flavor;
215 mctc.mctc_oldlwp = l;
216 mctc.mctc_child_done = 0;
217 mctc.mctc_state = req->req_state;
218
219 inmem = uvm_uarea_alloc(&uaddr);
220 if (__predict_false(uaddr == 0))
221 return (ENOMEM);
222
223 flags = 0;
224 if ((error = newlwp(l, p, uaddr, inmem, flags, NULL, 0,
225 mach_create_thread_child, (void *)&mctc, &mctc.mctc_lwp)) != 0)
226 return mach_msg_error(args, error);
227
228 /*
229 * Make the child runnable.
230 */
231 SCHED_LOCK(s);
232 mctc.mctc_lwp->l_private = 0;
233 mctc.mctc_lwp->l_stat = LSRUN;
234 setrunqueue(mctc.mctc_lwp);
235 p->p_nrlwps++;
236 SCHED_UNLOCK(s);
237
238 /*
239 * Get the child's kernel port
240 */
241 mle = mctc.mctc_lwp->l_emuldata;
242 child_mr = mach_right_get(mle->mle_kernel, l, MACH_PORT_TYPE_SEND, 0);
243
244 /*
245 * The child relies on some values in mctc, so we should not
246 * exit until it is finished with it. We catch signals so that
247 * the process can be killed with kill -9, but we loop to avoid
248 * spurious wakeups due to other signals.
249 */
250 while(mctc.mctc_child_done == 0)
251 (void)tsleep(&mctc.mctc_child_done,
252 PZERO|PCATCH, "mach_thread", 0);
253
254 *msglen = sizeof(*rep);
255 mach_set_header(rep, req, *msglen);
256 mach_add_port_desc(rep, child_mr->mr_name);
257 mach_set_trailer(rep, *msglen);
258
259 return 0;
260 }
261
262 int
263 mach_thread_info(args)
264 struct mach_trap_args *args;
265 {
266 mach_thread_info_request_t *req = args->smsg;
267 mach_thread_info_reply_t *rep = args->rmsg;
268 size_t *msglen = args->rsize;
269 struct lwp *l = args->l;
270 struct lwp *tl = args->tl;
271 struct proc *tp = tl->l_proc;
272
273 /* Sanity check req->req_count */
274 if (req->req_count > 12)
275 return mach_msg_error(args, EINVAL);
276
277 rep->rep_count = req->req_count;
278
279 *msglen = sizeof(*rep) + ((req->req_count - 12) * sizeof(int));
280 mach_set_header(rep, req, *msglen);
281
282 switch (req->req_flavor) {
283 case MACH_THREAD_BASIC_INFO: {
284 struct mach_thread_basic_info *tbi;
285
286 if (req->req_count != (sizeof(*tbi) / sizeof(int))) /* 10 */
287 return mach_msg_error(args, EINVAL);
288
289 tbi = (struct mach_thread_basic_info *)rep->rep_out;
290 tbi->user_time.seconds = tp->p_uticks * hz / 1000000;
291 tbi->user_time.microseconds =
292 (tp->p_uticks) * hz - tbi->user_time.seconds;
293 tbi->system_time.seconds = tp->p_sticks * hz / 1000000;
294 tbi->system_time.microseconds =
295 (tp->p_sticks) * hz - tbi->system_time.seconds;
296 tbi->cpu_usage = tp->p_pctcpu;
297 tbi->policy = MACH_THREAD_STANDARD_POLICY;
298
299 /* XXX this is not very accurate */
300 tbi->run_state = MACH_TH_STATE_RUNNING;
301 tbi->flags = 0;
302 switch (l->l_stat) {
303 case LSRUN:
304 tbi->run_state = MACH_TH_STATE_RUNNING;
305 break;
306 case LSSTOP:
307 tbi->run_state = MACH_TH_STATE_STOPPED;
308 break;
309 case LSSLEEP:
310 tbi->run_state = MACH_TH_STATE_WAITING;
311 break;
312 case LSIDL:
313 tbi->run_state = MACH_TH_STATE_RUNNING;
314 tbi->flags = MACH_TH_FLAGS_IDLE;
315 break;
316 default:
317 break;
318 }
319
320 tbi->suspend_count = 0;
321 tbi->sleep_time = tl->l_slptime;
322 break;
323 }
324
325 case MACH_THREAD_SCHED_TIMESHARE_INFO: {
326 struct mach_policy_timeshare_info *pti;
327
328 if (req->req_count != (sizeof(*pti) / sizeof(int))) /* 5 */
329 return mach_msg_error(args, EINVAL);
330
331 pti = (struct mach_policy_timeshare_info *)rep->rep_out;
332
333 pti->max_priority = tl->l_usrpri;
334 pti->base_priority = tl->l_usrpri;
335 pti->cur_priority = tl->l_usrpri;
336 pti->depressed = 0;
337 pti->depress_priority = tl->l_usrpri;
338 break;
339 }
340
341 case MACH_THREAD_SCHED_RR_INFO:
342 case MACH_THREAD_SCHED_FIFO_INFO:
343 uprintf("Unimplemented thread_info flavor %d\n",
344 req->req_flavor);
345 default:
346 return mach_msg_error(args, EINVAL);
347 break;
348 }
349
350 mach_set_trailer(rep, *msglen);
351
352 return 0;
353 }
354
355 int
356 mach_thread_get_state(args)
357 struct mach_trap_args *args;
358 {
359 mach_thread_get_state_request_t *req = args->smsg;
360 mach_thread_get_state_reply_t *rep = args->rmsg;
361 size_t *msglen = args->rsize;
362 struct lwp *tl = args->tl;
363 int error;
364 int size;
365
366 /* Sanity check req->req_count */
367 if (req->req_count > 144)
368 return mach_msg_error(args, EINVAL);
369
370 if ((error = mach_thread_get_state_machdep(tl,
371 req->req_flavor, &rep->rep_state, &size)) != 0)
372 return mach_msg_error(args, error);
373
374 rep->rep_count = size / sizeof(int);
375 *msglen = sizeof(*rep) + ((req->req_count - 144) * sizeof(int));
376 mach_set_header(rep, req, *msglen);
377 mach_set_trailer(rep, *msglen);
378
379 return 0;
380 }
381
382 int
383 mach_thread_set_state(args)
384 struct mach_trap_args *args;
385 {
386 mach_thread_set_state_request_t *req = args->smsg;
387 mach_thread_set_state_reply_t *rep = args->rmsg;
388 size_t *msglen = args->rsize;
389 struct lwp *tl = args->tl;
390 int error;
391 int end_offset;
392
393 /* Sanity check req_count */
394 end_offset = req->req_count;
395 if (MACH_REQMSG_OVERFLOW(args, req->req_state[end_offset]))
396 return mach_msg_error(args, EINVAL);
397
398 if ((error = mach_thread_set_state_machdep(tl,
399 req->req_flavor, &req->req_state)) != 0)
400 return mach_msg_error(args, error);
401
402 *msglen = sizeof(*rep);
403 mach_set_header(rep, req, *msglen);
404
405 rep->rep_retval = 0;
406
407 mach_set_trailer(rep, *msglen);
408
409 return 0;
410 }
411
412 int
413 mach_thread_suspend(args)
414 struct mach_trap_args *args;
415 {
416 mach_thread_suspend_request_t *req = args->smsg;
417 mach_thread_suspend_reply_t *rep = args->rmsg;
418 size_t *msglen = args->rsize;
419 struct lwp *l = args->l;
420 struct lwp *tl = args->tl;
421 int error;
422
423 error = lwp_suspend(l, tl);
424
425 *msglen = sizeof(*rep);
426 mach_set_header(rep, req, *msglen);
427 rep->rep_retval = native_to_mach_errno[error];
428 mach_set_trailer(rep, *msglen);
429
430 return 0;
431 }
432
433 int
434 mach_thread_resume(args)
435 struct mach_trap_args *args;
436 {
437 mach_thread_resume_request_t *req = args->smsg;
438 mach_thread_resume_reply_t *rep = args->rmsg;
439 size_t *msglen = args->rsize;
440 struct lwp *tl = args->tl;
441
442 lwp_continue(tl);
443
444 *msglen = sizeof(*rep);
445 mach_set_header(rep, req, *msglen);
446 rep->rep_retval = 0;
447 mach_set_trailer(rep, *msglen);
448
449 return 0;
450 }
451
452 int
453 mach_thread_abort(args)
454 struct mach_trap_args *args;
455 {
456 mach_thread_abort_request_t *req = args->smsg;
457 mach_thread_abort_reply_t *rep = args->rmsg;
458 size_t *msglen = args->rsize;
459 struct lwp *tl = args->tl;
460
461 lwp_exit(tl);
462
463 *msglen = sizeof(*rep);
464 mach_set_header(rep, req, *msglen);
465 rep->rep_retval = 0;
466 mach_set_trailer(rep, *msglen);
467
468 return 0;
469 }
470
471 int
472 mach_thread_set_policy(args)
473 struct mach_trap_args *args;
474 {
475 mach_thread_set_policy_request_t *req = args->smsg;
476 mach_thread_set_policy_reply_t *rep = args->rmsg;
477 size_t *msglen = args->rsize;
478 struct lwp *tl = args->tl;
479 mach_port_t mn;
480 struct mach_right *mr;
481 int limit_count_offset, limit_offset;
482 int limit_count;
483 int *limit;
484
485 limit_count_offset = req->req_base_count;
486 if (MACH_REQMSG_OVERFLOW(args, req->req_base[limit_count_offset]))
487 return mach_msg_error(args, EINVAL);
488
489 limit_count = req->req_base[limit_count_offset];
490 limit_offset = limit_count_offset +
491 (sizeof(req->req_limit_count) / sizeof(req->req_base[0]));
492 limit = &req->req_base[limit_offset];
493 if (MACH_REQMSG_OVERFLOW(args, limit[limit_count]))
494 return mach_msg_error(args, EINVAL);
495
496 mn = req->req_pset.name;
497 if ((mr = mach_right_check(mn, tl, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
498 return mach_msg_error(args, EINVAL);
499
500 *msglen = sizeof(*rep);
501 mach_set_header(rep, req, *msglen);
502 rep->rep_retval = 0;
503 mach_set_trailer(rep, *msglen);
504
505 return 0;
506 }
507
Cache object: 902c0e716af64e41673ade03c0c4d2f4
|