1 /* $NetBSD: mach_thread.c,v 1.38 2006/11/16 01:32:44 christos 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.38 2006/11/16 01:32:44 christos 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(struct lwp *l, void *v,
68 register_t *retval)
69 {
70 struct mach_sys_syscall_thread_switch_args /* {
71 syscallarg(mach_port_name_t) thread_name;
72 syscallarg(int) option;
73 syscallarg(mach_msg_timeout_t) option_time;
74 } */ *uap = v;
75 int timeout;
76 struct mach_emuldata *med;
77
78 med = (struct mach_emuldata *)l->l_proc->p_emuldata;
79 timeout = SCARG(uap, option_time) * hz / 1000;
80
81 /*
82 * The day we will be able to find out the struct proc from
83 * the port number, try to use preempt() to call the right thread.
84 * [- but preempt() is for _involuntary_ context switches.]
85 */
86 switch(SCARG(uap, option)) {
87 case MACH_SWITCH_OPTION_NONE:
88 yield();
89 break;
90
91 case MACH_SWITCH_OPTION_WAIT:
92 med->med_thpri = 1;
93 while (med->med_thpri != 0)
94 (void)tsleep(&med->med_thpri, PZERO|PCATCH,
95 "thread_switch", timeout);
96 break;
97
98 case MACH_SWITCH_OPTION_DEPRESS:
99 case MACH_SWITCH_OPTION_IDLE:
100 /* Use a callout to restore the priority after depression? */
101 med->med_thpri = l->l_priority;
102 l->l_priority = MAXPRI;
103 break;
104
105 default:
106 uprintf("mach_sys_syscall_thread_switch(): unknown option %d\n", SCARG(uap, option));
107 break;
108 }
109 return 0;
110 }
111
112 int
113 mach_sys_swtch_pri(struct lwp *l, void *v, register_t *retval)
114 {
115 #if 0 /* pri is not used yet */
116 struct mach_sys_swtch_pri_args /* {
117 syscallarg(int) pri;
118 } */ *uap = v;
119 #endif
120 int s;
121
122 /*
123 * Copied from preempt(9). We cannot just call preempt
124 * because we want to return mi_switch(9) return value.
125 */
126 SCHED_LOCK(s);
127 l->l_priority = l->l_usrpri;
128 l->l_stat = LSRUN;
129 setrunqueue(l);
130 l->l_proc->p_stats->p_ru.ru_nivcsw++;
131 *retval = mi_switch(l, NULL);
132 SCHED_ASSERT_UNLOCKED();
133 splx(s);
134 if ((l->l_flag & L_SA) != 0 && *retval != 0)
135 sa_preempt(l);
136
137 return 0;
138 }
139
140 int
141 mach_sys_swtch(struct lwp *l, void *v, register_t *retval)
142 {
143 struct mach_sys_swtch_pri_args cup;
144
145 SCARG(&cup, pri) = 0;
146
147 return mach_sys_swtch_pri(l, &cup, retval);
148 }
149
150
151 int
152 mach_thread_policy(args)
153 struct mach_trap_args *args;
154 {
155 mach_thread_policy_request_t *req = args->smsg;
156 mach_thread_policy_reply_t *rep = args->rmsg;
157 size_t *msglen = args->rsize;
158 int end_offset;
159
160 /* Sanity check req_count */
161 end_offset = req->req_count +
162 (sizeof(req->req_setlimit) / sizeof(req->req_base[0]));
163 if (MACH_REQMSG_OVERFLOW(args, req->req_base[end_offset]))
164 return mach_msg_error(args, EINVAL);
165
166 uprintf("Unimplemented mach_thread_policy\n");
167
168 *msglen = sizeof(*rep);
169 mach_set_header(rep, req, *msglen);
170
171 rep->rep_retval = 0;
172
173 mach_set_trailer(rep, *msglen);
174
175 return 0;
176 }
177
178 /* XXX it might be possible to use this on another task */
179 int
180 mach_thread_create_running(args)
181 struct mach_trap_args *args;
182 {
183 mach_thread_create_running_request_t *req = args->smsg;
184 mach_thread_create_running_reply_t *rep = args->rmsg;
185 size_t *msglen = args->rsize;
186 struct lwp *l = args->l;
187 struct proc *p = l->l_proc;
188 struct mach_create_thread_child_args mctc;
189 struct mach_right *child_mr;
190 struct mach_lwp_emuldata *mle;
191 vaddr_t uaddr;
192 int flags;
193 int error;
194 int inmem;
195 int s;
196 int end_offset;
197
198 /* Sanity check req_count */
199 end_offset = req->req_count;
200 if (MACH_REQMSG_OVERFLOW(args, req->req_state[end_offset]))
201 return mach_msg_error(args, EINVAL);
202
203 /*
204 * Prepare the data we want to transmit to the child.
205 */
206 mctc.mctc_flavor = req->req_flavor;
207 mctc.mctc_oldlwp = l;
208 mctc.mctc_child_done = 0;
209 mctc.mctc_state = req->req_state;
210
211 inmem = uvm_uarea_alloc(&uaddr);
212 if (__predict_false(uaddr == 0))
213 return (ENOMEM);
214
215 flags = 0;
216 if ((error = newlwp(l, p, uaddr, inmem, flags, NULL, 0,
217 mach_create_thread_child, (void *)&mctc, &mctc.mctc_lwp)) != 0)
218 return mach_msg_error(args, error);
219
220 /*
221 * Make the child runnable.
222 */
223 SCHED_LOCK(s);
224 mctc.mctc_lwp->l_private = 0;
225 mctc.mctc_lwp->l_stat = LSRUN;
226 setrunqueue(mctc.mctc_lwp);
227 p->p_nrlwps++;
228 SCHED_UNLOCK(s);
229
230 /*
231 * Get the child's kernel port
232 */
233 mle = mctc.mctc_lwp->l_emuldata;
234 child_mr = mach_right_get(mle->mle_kernel, l, MACH_PORT_TYPE_SEND, 0);
235
236 /*
237 * The child relies on some values in mctc, so we should not
238 * exit until it is finished with it. We catch signals so that
239 * the process can be killed with kill -9, but we loop to avoid
240 * spurious wakeups due to other signals.
241 */
242 while(mctc.mctc_child_done == 0)
243 (void)tsleep(&mctc.mctc_child_done,
244 PZERO|PCATCH, "mach_thread", 0);
245
246 *msglen = sizeof(*rep);
247 mach_set_header(rep, req, *msglen);
248 mach_add_port_desc(rep, child_mr->mr_name);
249 mach_set_trailer(rep, *msglen);
250
251 return 0;
252 }
253
254 int
255 mach_thread_info(args)
256 struct mach_trap_args *args;
257 {
258 mach_thread_info_request_t *req = args->smsg;
259 mach_thread_info_reply_t *rep = args->rmsg;
260 size_t *msglen = args->rsize;
261 struct lwp *l = args->l;
262 struct lwp *tl = args->tl;
263 struct proc *tp = tl->l_proc;
264
265 /* Sanity check req->req_count */
266 if (req->req_count > 12)
267 return mach_msg_error(args, EINVAL);
268
269 rep->rep_count = req->req_count;
270
271 *msglen = sizeof(*rep) + ((req->req_count - 12) * sizeof(int));
272 mach_set_header(rep, req, *msglen);
273
274 switch (req->req_flavor) {
275 case MACH_THREAD_BASIC_INFO: {
276 struct mach_thread_basic_info *tbi;
277
278 if (req->req_count != (sizeof(*tbi) / sizeof(int))) /* 10 */
279 return mach_msg_error(args, EINVAL);
280
281 tbi = (struct mach_thread_basic_info *)rep->rep_out;
282 tbi->user_time.seconds = tp->p_uticks * hz / 1000000;
283 tbi->user_time.microseconds =
284 (tp->p_uticks) * hz - tbi->user_time.seconds;
285 tbi->system_time.seconds = tp->p_sticks * hz / 1000000;
286 tbi->system_time.microseconds =
287 (tp->p_sticks) * hz - tbi->system_time.seconds;
288 tbi->cpu_usage = tp->p_pctcpu;
289 tbi->policy = MACH_THREAD_STANDARD_POLICY;
290
291 /* XXX this is not very accurate */
292 tbi->run_state = MACH_TH_STATE_RUNNING;
293 tbi->flags = 0;
294 switch (l->l_stat) {
295 case LSRUN:
296 tbi->run_state = MACH_TH_STATE_RUNNING;
297 break;
298 case LSSTOP:
299 tbi->run_state = MACH_TH_STATE_STOPPED;
300 break;
301 case LSSLEEP:
302 tbi->run_state = MACH_TH_STATE_WAITING;
303 break;
304 case LSIDL:
305 tbi->run_state = MACH_TH_STATE_RUNNING;
306 tbi->flags = MACH_TH_FLAGS_IDLE;
307 break;
308 default:
309 break;
310 }
311
312 tbi->suspend_count = 0;
313 tbi->sleep_time = tl->l_slptime;
314 break;
315 }
316
317 case MACH_THREAD_SCHED_TIMESHARE_INFO: {
318 struct mach_policy_timeshare_info *pti;
319
320 if (req->req_count != (sizeof(*pti) / sizeof(int))) /* 5 */
321 return mach_msg_error(args, EINVAL);
322
323 pti = (struct mach_policy_timeshare_info *)rep->rep_out;
324
325 pti->max_priority = tl->l_usrpri;
326 pti->base_priority = tl->l_usrpri;
327 pti->cur_priority = tl->l_usrpri;
328 pti->depressed = 0;
329 pti->depress_priority = tl->l_usrpri;
330 break;
331 }
332
333 case MACH_THREAD_SCHED_RR_INFO:
334 case MACH_THREAD_SCHED_FIFO_INFO:
335 uprintf("Unimplemented thread_info flavor %d\n",
336 req->req_flavor);
337 default:
338 return mach_msg_error(args, EINVAL);
339 break;
340 }
341
342 mach_set_trailer(rep, *msglen);
343
344 return 0;
345 }
346
347 int
348 mach_thread_get_state(args)
349 struct mach_trap_args *args;
350 {
351 mach_thread_get_state_request_t *req = args->smsg;
352 mach_thread_get_state_reply_t *rep = args->rmsg;
353 size_t *msglen = args->rsize;
354 struct lwp *tl = args->tl;
355 int error;
356 int size;
357
358 /* Sanity check req->req_count */
359 if (req->req_count > 144)
360 return mach_msg_error(args, EINVAL);
361
362 if ((error = mach_thread_get_state_machdep(tl,
363 req->req_flavor, &rep->rep_state, &size)) != 0)
364 return mach_msg_error(args, error);
365
366 rep->rep_count = size / sizeof(int);
367 *msglen = sizeof(*rep) + ((req->req_count - 144) * sizeof(int));
368 mach_set_header(rep, req, *msglen);
369 mach_set_trailer(rep, *msglen);
370
371 return 0;
372 }
373
374 int
375 mach_thread_set_state(args)
376 struct mach_trap_args *args;
377 {
378 mach_thread_set_state_request_t *req = args->smsg;
379 mach_thread_set_state_reply_t *rep = args->rmsg;
380 size_t *msglen = args->rsize;
381 struct lwp *tl = args->tl;
382 int error;
383 int end_offset;
384
385 /* Sanity check req_count */
386 end_offset = req->req_count;
387 if (MACH_REQMSG_OVERFLOW(args, req->req_state[end_offset]))
388 return mach_msg_error(args, EINVAL);
389
390 if ((error = mach_thread_set_state_machdep(tl,
391 req->req_flavor, &req->req_state)) != 0)
392 return mach_msg_error(args, error);
393
394 *msglen = sizeof(*rep);
395 mach_set_header(rep, req, *msglen);
396
397 rep->rep_retval = 0;
398
399 mach_set_trailer(rep, *msglen);
400
401 return 0;
402 }
403
404 int
405 mach_thread_suspend(args)
406 struct mach_trap_args *args;
407 {
408 mach_thread_suspend_request_t *req = args->smsg;
409 mach_thread_suspend_reply_t *rep = args->rmsg;
410 size_t *msglen = args->rsize;
411 struct lwp *l = args->l;
412 struct lwp *tl = args->tl;
413 int error;
414
415 error = lwp_suspend(l, tl);
416
417 *msglen = sizeof(*rep);
418 mach_set_header(rep, req, *msglen);
419 rep->rep_retval = native_to_mach_errno[error];
420 mach_set_trailer(rep, *msglen);
421
422 return 0;
423 }
424
425 int
426 mach_thread_resume(args)
427 struct mach_trap_args *args;
428 {
429 mach_thread_resume_request_t *req = args->smsg;
430 mach_thread_resume_reply_t *rep = args->rmsg;
431 size_t *msglen = args->rsize;
432 struct lwp *tl = args->tl;
433
434 lwp_continue(tl);
435
436 *msglen = sizeof(*rep);
437 mach_set_header(rep, req, *msglen);
438 rep->rep_retval = 0;
439 mach_set_trailer(rep, *msglen);
440
441 return 0;
442 }
443
444 int
445 mach_thread_abort(args)
446 struct mach_trap_args *args;
447 {
448 mach_thread_abort_request_t *req = args->smsg;
449 mach_thread_abort_reply_t *rep = args->rmsg;
450 size_t *msglen = args->rsize;
451 struct lwp *tl = args->tl;
452
453 lwp_exit(tl);
454
455 *msglen = sizeof(*rep);
456 mach_set_header(rep, req, *msglen);
457 rep->rep_retval = 0;
458 mach_set_trailer(rep, *msglen);
459
460 return 0;
461 }
462
463 int
464 mach_thread_set_policy(args)
465 struct mach_trap_args *args;
466 {
467 mach_thread_set_policy_request_t *req = args->smsg;
468 mach_thread_set_policy_reply_t *rep = args->rmsg;
469 size_t *msglen = args->rsize;
470 struct lwp *tl = args->tl;
471 mach_port_t mn;
472 struct mach_right *mr;
473 int limit_count_offset, limit_offset;
474 int limit_count;
475 int *limit;
476
477 limit_count_offset = req->req_base_count;
478 if (MACH_REQMSG_OVERFLOW(args, req->req_base[limit_count_offset]))
479 return mach_msg_error(args, EINVAL);
480
481 limit_count = req->req_base[limit_count_offset];
482 limit_offset = limit_count_offset +
483 (sizeof(req->req_limit_count) / sizeof(req->req_base[0]));
484 limit = &req->req_base[limit_offset];
485 if (MACH_REQMSG_OVERFLOW(args, limit[limit_count]))
486 return mach_msg_error(args, EINVAL);
487
488 mn = req->req_pset.name;
489 if ((mr = mach_right_check(mn, tl, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
490 return mach_msg_error(args, EINVAL);
491
492 *msglen = sizeof(*rep);
493 mach_set_header(rep, req, *msglen);
494 rep->rep_retval = 0;
495 mach_set_trailer(rep, *msglen);
496
497 return 0;
498 }
499
Cache object: 2bf8d1746833d034423d4f4f21dd67fb
|