1 /* $NetBSD: mach_thread.c,v 1.48 2008/10/15 06:51:19 wrstuden Exp $ */
4 * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mach_thread.c,v 1.48 2008/10/15 06:51:19 wrstuden Exp $");
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/systm.h>
39 #include <sys/signal.h>
40 #include <sys/rwlock.h>
41 #include <sys/queue.h>
43 #include <sys/resource.h>
44 #include <sys/resourcevar.h>
46 #include <sys/savar.h>
48 #include <compat/mach/mach_types.h>
49 #include <compat/mach/mach_message.h>
50 #include <compat/mach/mach_exec.h>
51 #include <compat/mach/mach_clock.h>
52 #include <compat/mach/mach_port.h>
53 #include <compat/mach/mach_task.h>
54 #include <compat/mach/mach_thread.h>
55 #include <compat/mach/mach_errno.h>
56 #include <compat/mach/mach_services.h>
57 #include <compat/mach/mach_syscallargs.h>
60 mach_sys_syscall_thread_switch(struct lwp
*l
, const struct mach_sys_syscall_thread_switch_args
*uap
, register_t
*retval
)
63 syscallarg(mach_port_name_t) thread_name;
64 syscallarg(int) option;
65 syscallarg(mach_msg_timeout_t) option_time;
68 struct mach_emuldata
*med
;
70 med
= (struct mach_emuldata
*)l
->l_proc
->p_emuldata
;
71 timeout
= SCARG(uap
, option_time
) * hz
/ 1000;
74 * The day we will be able to find out the struct proc from
75 * the port number, try to use preempt() to call the right thread.
76 * [- but preempt() is for _involuntary_ context switches.]
78 switch(SCARG(uap
, option
)) {
79 case MACH_SWITCH_OPTION_NONE
:
83 case MACH_SWITCH_OPTION_WAIT
:
85 while (med
->med_thpri
!= 0)
86 (void)tsleep(&med
->med_thpri
, PZERO
|PCATCH
,
87 "thread_switch", timeout
);
90 case MACH_SWITCH_OPTION_DEPRESS
:
91 case MACH_SWITCH_OPTION_IDLE
:
92 /* Use a callout to restore the priority after depression? */
93 med
->med_thpri
= l
->l_priority
;
94 l
->l_priority
= MAXPRI
;
98 uprintf("mach_sys_syscall_thread_switch(): unknown option %d\n", SCARG(uap
, option
));
105 mach_sys_swtch_pri(struct lwp
*l
, const struct mach_sys_swtch_pri_args
*uap
, register_t
*retval
)
112 * Copied from preempt(9). We cannot just call preempt
113 * because we want to return mi_switch(9) return value.
115 KERNEL_UNLOCK_ALL(l
, &l
->l_biglocks
);
117 if (l
->l_stat
== LSONPROC
)
118 l
->l_proc
->p_stats
->p_ru
.ru_nivcsw
++; /* XXXSMP */
119 *retval
= mi_switch(l
);
120 KERNEL_LOCK(l
->l_biglocks
, l
);
126 mach_sys_swtch(struct lwp
*l
, const void *v
, register_t
*retval
)
128 struct mach_sys_swtch_pri_args cup
;
130 SCARG(&cup
, pri
) = 0;
132 return mach_sys_swtch_pri(l
, &cup
, retval
);
137 mach_thread_policy(struct mach_trap_args
*args
)
139 mach_thread_policy_request_t
*req
= args
->smsg
;
140 mach_thread_policy_reply_t
*rep
= args
->rmsg
;
141 size_t *msglen
= args
->rsize
;
144 /* Sanity check req_count */
145 end_offset
= req
->req_count
+
146 (sizeof(req
->req_setlimit
) / sizeof(req
->req_base
[0]));
147 if (MACH_REQMSG_OVERFLOW(args
, req
->req_base
[end_offset
]))
148 return mach_msg_error(args
, EINVAL
);
150 uprintf("Unimplemented mach_thread_policy\n");
152 *msglen
= sizeof(*rep
);
153 mach_set_header(rep
, req
, *msglen
);
157 mach_set_trailer(rep
, *msglen
);
162 /* XXX it might be possible to use this on another task */
164 mach_thread_create_running(struct mach_trap_args
*args
)
166 mach_thread_create_running_request_t
*req
= args
->smsg
;
167 mach_thread_create_running_reply_t
*rep
= args
->rmsg
;
168 size_t *msglen
= args
->rsize
;
169 struct lwp
*l
= args
->l
;
170 struct proc
*p
= l
->l_proc
;
171 struct mach_create_thread_child_args mctc
;
172 struct mach_right
*child_mr
;
173 struct mach_lwp_emuldata
*mle
;
179 /* Sanity check req_count */
180 end_offset
= req
->req_count
;
181 if (MACH_REQMSG_OVERFLOW(args
, req
->req_state
[end_offset
]))
182 return mach_msg_error(args
, EINVAL
);
185 * Prepare the data we want to transmit to the child.
187 mctc
.mctc_flavor
= req
->req_flavor
;
188 mctc
.mctc_oldlwp
= l
;
189 mctc
.mctc_child_done
= 0;
190 mctc
.mctc_state
= req
->req_state
;
192 uaddr
= uvm_uarea_alloc();
193 if (__predict_false(uaddr
== 0))
197 if ((error
= lwp_create(l
, p
, uaddr
, flags
, NULL
, 0,
198 mach_create_thread_child
, (void *)&mctc
, &mctc
.mctc_lwp
,
201 uvm_uarea_free(uaddr
);
202 return mach_msg_error(args
, error
);
206 * Make the child runnable.
208 mutex_enter(p
->p_lock
);
209 lwp_lock(mctc
.mctc_lwp
);
210 mctc
.mctc_lwp
->l_private
= 0;
211 mctc
.mctc_lwp
->l_stat
= LSRUN
;
212 sched_enqueue(mctc
.mctc_lwp
, false);
214 lwp_unlock(mctc
.mctc_lwp
);
215 mutex_exit(p
->p_lock
);
218 * Get the child's kernel port
220 mle
= mctc
.mctc_lwp
->l_emuldata
;
221 child_mr
= mach_right_get(mle
->mle_kernel
, l
, MACH_PORT_TYPE_SEND
, 0);
224 * The child relies on some values in mctc, so we should not
225 * exit until it is finished with it. We catch signals so that
226 * the process can be killed with kill -9, but we loop to avoid
227 * spurious wakeups due to other signals.
229 while(mctc
.mctc_child_done
== 0)
230 (void)tsleep(&mctc
.mctc_child_done
,
231 PZERO
|PCATCH
, "mach_thread", 0);
233 *msglen
= sizeof(*rep
);
234 mach_set_header(rep
, req
, *msglen
);
235 mach_add_port_desc(rep
, child_mr
->mr_name
);
236 mach_set_trailer(rep
, *msglen
);
242 mach_thread_info(struct mach_trap_args
*args
)
244 mach_thread_info_request_t
*req
= args
->smsg
;
245 mach_thread_info_reply_t
*rep
= args
->rmsg
;
246 size_t *msglen
= args
->rsize
;
247 struct lwp
*l
= args
->l
;
248 struct lwp
*tl
= args
->tl
;
249 struct proc
*tp
= tl
->l_proc
;
251 /* Sanity check req->req_count */
252 if (req
->req_count
> 12)
253 return mach_msg_error(args
, EINVAL
);
255 rep
->rep_count
= req
->req_count
;
257 *msglen
= sizeof(*rep
) + ((req
->req_count
- 12) * sizeof(int));
258 mach_set_header(rep
, req
, *msglen
);
260 switch (req
->req_flavor
) {
261 case MACH_THREAD_BASIC_INFO
: {
262 struct mach_thread_basic_info
*tbi
;
264 if (req
->req_count
!= (sizeof(*tbi
) / sizeof(int))) /* 10 */
265 return mach_msg_error(args
, EINVAL
);
267 tbi
= (struct mach_thread_basic_info
*)rep
->rep_out
;
268 tbi
->user_time
.seconds
= tp
->p_uticks
* hz
/ 1000000;
269 tbi
->user_time
.microseconds
=
270 (tp
->p_uticks
) * hz
- tbi
->user_time
.seconds
;
271 tbi
->system_time
.seconds
= tp
->p_sticks
* hz
/ 1000000;
272 tbi
->system_time
.microseconds
=
273 (tp
->p_sticks
) * hz
- tbi
->system_time
.seconds
;
274 tbi
->cpu_usage
= tp
->p_pctcpu
;
275 tbi
->policy
= MACH_THREAD_STANDARD_POLICY
;
277 /* XXX this is not very accurate */
278 tbi
->run_state
= MACH_TH_STATE_RUNNING
;
282 tbi
->run_state
= MACH_TH_STATE_RUNNING
;
285 tbi
->run_state
= MACH_TH_STATE_STOPPED
;
288 tbi
->run_state
= MACH_TH_STATE_WAITING
;
291 tbi
->run_state
= MACH_TH_STATE_RUNNING
;
292 tbi
->flags
= MACH_TH_FLAGS_IDLE
;
298 tbi
->suspend_count
= 0;
299 tbi
->sleep_time
= tl
->l_slptime
;
303 case MACH_THREAD_SCHED_TIMESHARE_INFO
: {
304 struct mach_policy_timeshare_info
*pti
;
306 if (req
->req_count
!= (sizeof(*pti
) / sizeof(int))) /* 5 */
307 return mach_msg_error(args
, EINVAL
);
309 pti
= (struct mach_policy_timeshare_info
*)rep
->rep_out
;
311 pti
->max_priority
= tl
->l_priority
;
312 pti
->base_priority
= tl
->l_priority
;
313 pti
->cur_priority
= tl
->l_priority
;
315 pti
->depress_priority
= tl
->l_priority
;
319 case MACH_THREAD_SCHED_RR_INFO
:
320 case MACH_THREAD_SCHED_FIFO_INFO
:
321 uprintf("Unimplemented thread_info flavor %d\n",
324 return mach_msg_error(args
, EINVAL
);
328 mach_set_trailer(rep
, *msglen
);
334 mach_thread_get_state(struct mach_trap_args
*args
)
336 mach_thread_get_state_request_t
*req
= args
->smsg
;
337 mach_thread_get_state_reply_t
*rep
= args
->rmsg
;
338 size_t *msglen
= args
->rsize
;
339 struct lwp
*tl
= args
->tl
;
343 /* Sanity check req->req_count */
344 if (req
->req_count
> 144)
345 return mach_msg_error(args
, EINVAL
);
347 if ((error
= mach_thread_get_state_machdep(tl
,
348 req
->req_flavor
, &rep
->rep_state
, &size
)) != 0)
349 return mach_msg_error(args
, error
);
351 rep
->rep_count
= size
/ sizeof(int);
352 *msglen
= sizeof(*rep
) + ((req
->req_count
- 144) * sizeof(int));
353 mach_set_header(rep
, req
, *msglen
);
354 mach_set_trailer(rep
, *msglen
);
360 mach_thread_set_state(struct mach_trap_args
*args
)
362 mach_thread_set_state_request_t
*req
= args
->smsg
;
363 mach_thread_set_state_reply_t
*rep
= args
->rmsg
;
364 size_t *msglen
= args
->rsize
;
365 struct lwp
*tl
= args
->tl
;
369 /* Sanity check req_count */
370 end_offset
= req
->req_count
;
371 if (MACH_REQMSG_OVERFLOW(args
, req
->req_state
[end_offset
]))
372 return mach_msg_error(args
, EINVAL
);
374 if ((error
= mach_thread_set_state_machdep(tl
,
375 req
->req_flavor
, &req
->req_state
)) != 0)
376 return mach_msg_error(args
, error
);
378 *msglen
= sizeof(*rep
);
379 mach_set_header(rep
, req
, *msglen
);
383 mach_set_trailer(rep
, *msglen
);
389 mach_thread_suspend(struct mach_trap_args
*args
)
391 mach_thread_suspend_request_t
*req
= args
->smsg
;
392 mach_thread_suspend_reply_t
*rep
= args
->rmsg
;
393 size_t *msglen
= args
->rsize
;
394 struct lwp
*l
= args
->l
;
395 struct lwp
*tl
= args
->tl
;
396 struct proc
*p
= tl
->l_proc
;
399 mutex_enter(p
->p_lock
);
401 error
= lwp_suspend(l
, tl
);
402 mutex_exit(p
->p_lock
);
404 *msglen
= sizeof(*rep
);
405 mach_set_header(rep
, req
, *msglen
);
406 rep
->rep_retval
= native_to_mach_errno
[error
];
407 mach_set_trailer(rep
, *msglen
);
413 mach_thread_resume(struct mach_trap_args
*args
)
415 mach_thread_resume_request_t
*req
= args
->smsg
;
416 mach_thread_resume_reply_t
*rep
= args
->rmsg
;
417 size_t *msglen
= args
->rsize
;
418 struct lwp
*tl
= args
->tl
;
419 struct proc
*p
= tl
->l_proc
;
421 mutex_enter(p
->p_lock
);
424 mutex_exit(p
->p_lock
);
426 *msglen
= sizeof(*rep
);
427 mach_set_header(rep
, req
, *msglen
);
429 mach_set_trailer(rep
, *msglen
);
435 mach_thread_abort(struct mach_trap_args
*args
)
437 mach_thread_abort_request_t
*req
= args
->smsg
;
438 mach_thread_abort_reply_t
*rep
= args
->rmsg
;
439 size_t *msglen
= args
->rsize
;
440 struct lwp
*tl
= args
->tl
;
444 *msglen
= sizeof(*rep
);
445 mach_set_header(rep
, req
, *msglen
);
447 mach_set_trailer(rep
, *msglen
);
453 mach_thread_set_policy(struct mach_trap_args
*args
)
455 mach_thread_set_policy_request_t
*req
= args
->smsg
;
456 mach_thread_set_policy_reply_t
*rep
= args
->rmsg
;
457 size_t *msglen
= args
->rsize
;
458 struct lwp
*tl
= args
->tl
;
460 struct mach_right
*mr
;
461 int limit_count_offset
, limit_offset
;
465 limit_count_offset
= req
->req_base_count
;
466 if (MACH_REQMSG_OVERFLOW(args
, req
->req_base
[limit_count_offset
]))
467 return mach_msg_error(args
, EINVAL
);
469 limit_count
= req
->req_base
[limit_count_offset
];
470 limit_offset
= limit_count_offset
+
471 (sizeof(req
->req_limit_count
) / sizeof(req
->req_base
[0]));
472 limit
= &req
->req_base
[limit_offset
];
473 if (MACH_REQMSG_OVERFLOW(args
, limit
[limit_count
]))
474 return mach_msg_error(args
, EINVAL
);
476 mn
= req
->req_pset
.name
;
477 if ((mr
= mach_right_check(mn
, tl
, MACH_PORT_TYPE_ALL_RIGHTS
)) == NULL
)
478 return mach_msg_error(args
, EINVAL
);
480 *msglen
= sizeof(*rep
);
481 mach_set_header(rep
, req
, *msglen
);
483 mach_set_trailer(rep
, *msglen
);