2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
29 * Mach Operating System
30 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
31 * All Rights Reserved.
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 * Carnegie Mellon requests users of this software to return to
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
59 * Task and thread related IPC functions.
62 #include <mach/mach_types.h>
63 #include <mach/boolean.h>
65 #include <mach/kern_return.h>
66 #include <mach/mach_param.h>
67 #include <mach/task_special_ports.h>
68 #include <mach/thread_special_ports.h>
69 #include <mach/thread_status.h>
70 #include <mach/exception_types.h>
71 #include <mach/mach_traps.h>
72 #include <mach/task_server.h>
73 #include <mach/thread_act_server.h>
74 #include <mach/mach_host_server.h>
75 #include <mach/vm_map_server.h>
76 #include <kern/host.h>
77 #include <kern/ipc_tt.h>
78 #include <kern/thread_act.h>
79 #include <kern/misc_protos.h>
80 #include <vm/vm_pageout.h>
83 * Routine: ipc_task_init
85 * Initialize a task's IPC state.
87 * If non-null, some state will be inherited from the parent.
88 * The parent must be appropriately initialized.
104 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
105 if (kr
!= KERN_SUCCESS
)
106 panic("ipc_task_init");
109 kport
= ipc_port_alloc_kernel();
110 if (kport
== IP_NULL
)
111 panic("ipc_task_init");
114 task
->itk_self
= kport
;
115 task
->itk_sself
= ipc_port_make_send(kport
);
116 task
->itk_space
= space
;
117 space
->is_fast
= FALSE
;
119 if (parent
== TASK_NULL
) {
122 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
123 task
->exc_actions
[i
].port
= IP_NULL
;
126 kr
= host_get_host_port(host_priv_self(), &port
);
127 assert(kr
== KERN_SUCCESS
);
128 task
->itk_host
= port
;
130 task
->itk_bootstrap
= IP_NULL
;
132 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
133 task
->itk_registered
[i
] = IP_NULL
;
136 assert(parent
->itk_self
!= IP_NULL
);
138 /* inherit registered ports */
140 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
141 task
->itk_registered
[i
] =
142 ipc_port_copy_send(parent
->itk_registered
[i
]);
144 /* inherit exception and bootstrap ports */
146 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
147 task
->exc_actions
[i
].port
=
148 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
149 task
->exc_actions
[i
].flavor
=
150 parent
->exc_actions
[i
].flavor
;
151 task
->exc_actions
[i
].behavior
=
152 parent
->exc_actions
[i
].behavior
;
155 ipc_port_copy_send(parent
->itk_host
);
157 task
->itk_bootstrap
=
158 ipc_port_copy_send(parent
->itk_bootstrap
);
165 * Routine: ipc_task_enable
167 * Enable a task for IPC access.
179 kport
= task
->itk_self
;
180 if (kport
!= IP_NULL
)
181 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
186 * Routine: ipc_task_disable
188 * Disable IPC access to a task.
200 kport
= task
->itk_self
;
201 if (kport
!= IP_NULL
)
202 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
207 * Routine: ipc_task_terminate
209 * Clean up and destroy a task's IPC state.
211 * Nothing locked. The task must be suspended.
212 * (Or the current thread must be in the task.)
223 kport
= task
->itk_self
;
225 if (kport
== IP_NULL
) {
226 /* the task is already terminated (can this happen?) */
231 task
->itk_self
= IP_NULL
;
234 /* release the naked send rights */
236 if (IP_VALID(task
->itk_sself
))
237 ipc_port_release_send(task
->itk_sself
);
239 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
240 if (IP_VALID(task
->exc_actions
[i
].port
)) {
241 ipc_port_release_send(task
->exc_actions
[i
].port
);
244 if (IP_VALID(task
->itk_host
))
245 ipc_port_release_send(task
->itk_host
);
247 if (IP_VALID(task
->itk_bootstrap
))
248 ipc_port_release_send(task
->itk_bootstrap
);
250 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
251 if (IP_VALID(task
->itk_registered
[i
]))
252 ipc_port_release_send(task
->itk_registered
[i
]);
254 ipc_port_release_send(task
->wired_ledger_port
);
255 ipc_port_release_send(task
->paged_ledger_port
);
257 /* destroy the kernel port */
258 ipc_port_dealloc_kernel(kport
);
262 * Routine: ipc_task_reset
264 * Reset a task's IPC state to protect it when
265 * it enters an elevated security context.
267 * Nothing locked. The task must be suspended.
268 * (Or the current thread must be in the task.)
275 ipc_port_t old_kport
, new_kport
;
276 ipc_port_t old_sself
;
278 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
282 new_kport
= ipc_port_alloc_kernel();
283 if (new_kport
== IP_NULL
)
284 panic("ipc_task_reset");
288 old_kport
= task
->itk_self
;
290 if (old_kport
== IP_NULL
) {
291 /* the task is already terminated (can this happen?) */
293 ipc_port_dealloc_kernel(new_kport
);
297 task
->itk_self
= new_kport
;
298 old_sself
= task
->itk_sself
;
299 task
->itk_sself
= ipc_port_make_send(new_kport
);
300 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
301 ipc_kobject_set(new_kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
304 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
305 old_exc_actions
[i
] = task
->exc_action
[i
].port
;
306 task
->exc_actions
[i
].port
= IP_NULL
;
312 /* release the naked send rights */
314 if (IP_VALID(old_sself
))
315 ipc_port_release_send(old_sself
);
318 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
319 if (IP_VALID(old_exc_actions
[i
])) {
320 ipc_port_release_send(old_exc_actions
[i
]);
325 /* destroy the kernel port */
326 ipc_port_dealloc_kernel(old_kport
);
330 * Routine: ipc_thread_init
332 * Initialize a thread's IPC state.
341 ipc_kmsg_queue_init(&thread
->ith_messages
);
342 thread
->ith_mig_reply
= MACH_PORT_NULL
;
343 thread
->ith_rpc_reply
= IP_NULL
;
347 * Routine: ipc_thread_terminate
349 * Clean up and destroy a thread's IPC state.
351 * Nothing locked. The thread must be suspended.
352 * (Or be the current thread.)
356 ipc_thread_terminate(
359 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
361 if (thread
->ith_rpc_reply
!= IP_NULL
)
362 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
363 thread
->ith_rpc_reply
= IP_NULL
;
367 * Routine: ipc_thr_act_init
369 * Initialize an thr_act's IPC state.
375 ipc_thr_act_init(task_t task
, thread_act_t thr_act
)
377 ipc_port_t kport
; int i
;
379 kport
= ipc_port_alloc_kernel();
380 if (kport
== IP_NULL
)
381 panic("ipc_thr_act_init");
383 thr_act
->ith_self
= kport
;
384 thr_act
->ith_sself
= ipc_port_make_send(kport
);
386 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
387 thr_act
->exc_actions
[i
].port
= IP_NULL
;
389 ipc_kobject_set(kport
, (ipc_kobject_t
) thr_act
, IKOT_ACT
);
393 ipc_thr_act_disable(thread_act_t thr_act
)
398 kport
= thr_act
->ith_self
;
400 if (kport
!= IP_NULL
)
401 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
405 ipc_thr_act_terminate(thread_act_t thr_act
)
407 ipc_port_t kport
; int i
;
409 kport
= thr_act
->ith_self
;
411 if (kport
== IP_NULL
) {
412 /* the thread is already terminated (can this happen?) */
416 thr_act
->ith_self
= IP_NULL
;
418 /* release the naked send rights */
420 if (IP_VALID(thr_act
->ith_sself
))
421 ipc_port_release_send(thr_act
->ith_sself
);
422 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
423 if (IP_VALID(thr_act
->exc_actions
[i
].port
))
424 ipc_port_release_send(thr_act
->exc_actions
[i
].port
);
427 /* destroy the kernel port */
428 ipc_port_dealloc_kernel(kport
);
432 * Routine: retrieve_task_self_fast
434 * Optimized version of retrieve_task_self,
435 * that only works for the current task.
437 * Return a send right (possibly null/dead)
438 * for the task's user-visible self port.
444 retrieve_task_self_fast(
445 register task_t task
)
447 register ipc_port_t port
;
449 assert(task
== current_task());
452 assert(task
->itk_self
!= IP_NULL
);
454 if ((port
= task
->itk_sself
) == task
->itk_self
) {
458 assert(ip_active(port
));
463 port
= ipc_port_copy_send(port
);
470 * Routine: retrieve_act_self_fast
472 * Optimized version of retrieve_thread_self,
473 * that only works for the current thread.
475 * Return a send right (possibly null/dead)
476 * for the thread's user-visible self port.
482 retrieve_act_self_fast(thread_act_t thr_act
)
484 register ipc_port_t port
;
486 assert(thr_act
== current_act());
488 assert(thr_act
->ith_self
!= IP_NULL
);
490 if ((port
= thr_act
->ith_sself
) == thr_act
->ith_self
) {
494 assert(ip_active(port
));
499 port
= ipc_port_copy_send(port
);
506 * Routine: task_self_trap [mach trap]
508 * Give the caller send rights for his own task port.
512 * MACH_PORT_NULL if there are any resource failures
519 task_t task
= current_task();
522 sright
= retrieve_task_self_fast(task
);
523 return ipc_port_copyout_send(sright
, task
->itk_space
);
527 * Routine: thread_self_trap [mach trap]
529 * Give the caller send rights for his own thread port.
533 * MACH_PORT_NULL if there are any resource failures
538 thread_self_trap(void)
540 thread_act_t thr_act
= current_act();
541 task_t task
= thr_act
->task
;
544 sright
= retrieve_act_self_fast(thr_act
);
545 return ipc_port_copyout_send(sright
, task
->itk_space
);
549 * Routine: mach_reply_port [mach trap]
551 * Allocate a port for the caller.
555 * MACH_PORT_NULL if there are any resource failures
560 mach_reply_port(void)
563 mach_port_name_t name
;
566 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
567 if (kr
== KERN_SUCCESS
)
570 name
= MACH_PORT_NULL
;
576 * Routine: task_get_special_port [kernel call]
578 * Clones a send right for one of the task's
583 * KERN_SUCCESS Extracted a send right.
584 * KERN_INVALID_ARGUMENT The task is null.
585 * KERN_FAILURE The task/space is dead.
586 * KERN_INVALID_ARGUMENT Invalid special port.
590 task_get_special_port(
598 if (task
== TASK_NULL
)
599 return KERN_INVALID_ARGUMENT
;
602 case TASK_KERNEL_PORT
:
603 whichp
= &task
->itk_sself
;
607 whichp
= &task
->itk_host
;
610 case TASK_BOOTSTRAP_PORT
:
611 whichp
= &task
->itk_bootstrap
;
614 case TASK_WIRED_LEDGER_PORT
:
615 whichp
= &task
->wired_ledger_port
;
618 case TASK_PAGED_LEDGER_PORT
:
619 whichp
= &task
->paged_ledger_port
;
623 return KERN_INVALID_ARGUMENT
;
627 if (task
->itk_self
== IP_NULL
) {
632 port
= ipc_port_copy_send(*whichp
);
640 * Routine: task_set_special_port [kernel call]
642 * Changes one of the task's special ports,
643 * setting it to the supplied send right.
645 * Nothing locked. If successful, consumes
646 * the supplied send right.
648 * KERN_SUCCESS Changed the special port.
649 * KERN_INVALID_ARGUMENT The task is null.
650 * KERN_FAILURE The task/space is dead.
651 * KERN_INVALID_ARGUMENT Invalid special port.
655 task_set_special_port(
663 if (task
== TASK_NULL
)
664 return KERN_INVALID_ARGUMENT
;
667 case TASK_KERNEL_PORT
:
668 whichp
= &task
->itk_sself
;
672 whichp
= &task
->itk_host
;
675 case TASK_BOOTSTRAP_PORT
:
676 whichp
= &task
->itk_bootstrap
;
679 case TASK_WIRED_LEDGER_PORT
:
680 whichp
= &task
->wired_ledger_port
;
683 case TASK_PAGED_LEDGER_PORT
:
684 whichp
= &task
->paged_ledger_port
;
688 return KERN_INVALID_ARGUMENT
;
692 if (task
->itk_self
== IP_NULL
) {
702 ipc_port_release_send(old
);
708 * Routine: mach_ports_register [kernel call]
710 * Stash a handful of port send rights in the task.
711 * Child tasks will inherit these rights, but they
712 * must use mach_ports_lookup to acquire them.
714 * The rights are supplied in a (wired) kalloc'd segment.
715 * Rights which aren't supplied are assumed to be null.
717 * Nothing locked. If successful, consumes
718 * the supplied rights and memory.
720 * KERN_SUCCESS Stashed the port rights.
721 * KERN_INVALID_ARGUMENT The task is null.
722 * KERN_INVALID_ARGUMENT The task is dead.
723 * KERN_INVALID_ARGUMENT Too many port rights supplied.
729 mach_port_array_t memory
,
730 mach_msg_type_number_t portsCnt
)
732 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
735 if ((task
== TASK_NULL
) ||
736 (portsCnt
> TASK_PORT_REGISTER_MAX
))
737 return KERN_INVALID_ARGUMENT
;
740 * Pad the port rights with nulls.
743 for (i
= 0; i
< portsCnt
; i
++)
744 ports
[i
] = memory
[i
];
745 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
749 if (task
->itk_self
== IP_NULL
) {
751 return KERN_INVALID_ARGUMENT
;
755 * Replace the old send rights with the new.
756 * Release the old rights after unlocking.
759 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
762 old
= task
->itk_registered
[i
];
763 task
->itk_registered
[i
] = ports
[i
];
769 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
770 if (IP_VALID(ports
[i
]))
771 ipc_port_release_send(ports
[i
]);
774 * Now that the operation is known to be successful,
775 * we can free the memory.
779 kfree((vm_offset_t
) memory
,
780 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
786 * Routine: mach_ports_lookup [kernel call]
788 * Retrieves (clones) the stashed port send rights.
790 * Nothing locked. If successful, the caller gets
793 * KERN_SUCCESS Retrieved the send rights.
794 * KERN_INVALID_ARGUMENT The task is null.
795 * KERN_INVALID_ARGUMENT The task is dead.
796 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
802 mach_port_array_t
*portsp
,
803 mach_msg_type_number_t
*portsCnt
)
812 if (task
== TASK_NULL
)
813 return KERN_INVALID_ARGUMENT
;
815 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
817 memory
= kalloc(size
);
819 return KERN_RESOURCE_SHORTAGE
;
822 if (task
->itk_self
== IP_NULL
) {
826 return KERN_INVALID_ARGUMENT
;
829 ports
= (ipc_port_t
*) memory
;
832 * Clone port rights. Because kalloc'd memory
833 * is wired, we won't fault while holding the task lock.
836 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
837 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
841 *portsp
= (mach_port_array_t
) ports
;
842 *portsCnt
= TASK_PORT_REGISTER_MAX
;
847 * Routine: convert_port_to_locked_task
849 * Internal helper routine to convert from a port to a locked
850 * task. Used by several routines that try to convert from a
851 * task port to a reference on some task related object.
853 * Nothing locked, blocking OK.
856 convert_port_to_locked_task(ipc_port_t port
)
858 while (IP_VALID(port
)) {
862 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
866 task
= (task_t
) port
->ip_kobject
;
867 assert(task
!= TASK_NULL
);
870 * Normal lock ordering puts task_lock() before ip_lock().
871 * Attempt out-of-order locking here.
873 if (task_lock_try(task
)) {
885 * Routine: convert_port_to_task
887 * Convert from a port to a task.
888 * Doesn't consume the port ref; produces a task ref,
894 convert_port_to_task(
899 task
= convert_port_to_locked_task(port
);
908 * Routine: convert_port_to_space
910 * Convert from a port to a space.
911 * Doesn't consume the port ref; produces a space ref,
917 convert_port_to_space(
923 task
= convert_port_to_locked_task(port
);
925 if (task
== TASK_NULL
)
926 return IPC_SPACE_NULL
;
930 return IPC_SPACE_NULL
;
933 space
= task
->itk_space
;
946 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_UPL
)) {
950 upl
= (upl_t
) port
->ip_kobject
;
962 return MACH_PORT_NULL
;
965 __private_extern__
void
968 mach_port_mscount_t mscount
)
974 * Routine: convert_port_entry_to_map
976 * Convert from a port specifying an entry or a task
977 * to a map. Doesn't consume the port ref; produces a map ref,
978 * which may be null. Unlike convert_port_to_map, the
979 * port may be task or a named entry backed.
986 convert_port_entry_to_map(
991 vm_named_entry_t named_entry
;
993 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
996 if(ip_active(port
) && (ip_kotype(port
)
997 == IKOT_NAMED_ENTRY
)) {
999 (vm_named_entry_t
)port
->ip_kobject
;
1000 if (!(mutex_try(&(named_entry
)->Lock
))) {
1005 named_entry
->ref_count
++;
1006 mutex_unlock(&(named_entry
)->Lock
);
1008 if ((named_entry
->is_sub_map
) &&
1009 (named_entry
->protection
1011 map
= named_entry
->backing
.map
;
1013 mach_destroy_memory_entry(port
);
1016 vm_map_reference_swap(map
);
1017 mach_destroy_memory_entry(port
);
1026 task
= convert_port_to_locked_task(port
);
1028 if (task
== TASK_NULL
)
1031 if (!task
->active
) {
1037 vm_map_reference_swap(map
);
1045 * Routine: convert_port_entry_to_object
1047 * Convert from a port specifying a named entry to an
1048 * object. Doesn't consume the port ref; produces a map ref,
1049 * which may be null.
1056 convert_port_entry_to_object(
1060 vm_named_entry_t named_entry
;
1062 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
1065 if(ip_active(port
) && (ip_kotype(port
)
1066 == IKOT_NAMED_ENTRY
)) {
1068 (vm_named_entry_t
)port
->ip_kobject
;
1069 if (!(mutex_try(&(named_entry
)->Lock
))) {
1074 named_entry
->ref_count
++;
1075 mutex_unlock(&(named_entry
)->Lock
);
1077 if ((!named_entry
->is_sub_map
) &&
1078 (named_entry
->protection
1080 object
= named_entry
->object
;
1082 mach_destroy_memory_entry(port
);
1083 return (vm_object_t
)NULL
;
1085 vm_object_reference(named_entry
->object
);
1086 mach_destroy_memory_entry(port
);
1090 return (vm_object_t
)NULL
;
1093 return (vm_object_t
)NULL
;
1100 * Routine: convert_port_to_map
1102 * Convert from a port to a map.
1103 * Doesn't consume the port ref; produces a map ref,
1104 * which may be null.
1110 convert_port_to_map(
1116 task
= convert_port_to_locked_task(port
);
1118 if (task
== TASK_NULL
)
1121 if (!task
->active
) {
1127 vm_map_reference_swap(map
);
1134 * Routine: convert_port_to_act
1136 * Convert from a port to a thr_act.
1137 * Doesn't consume the port ref; produces an thr_act ref,
1138 * which may be null.
1144 convert_port_to_act( ipc_port_t port
)
1147 thread_act_t thr_act
= 0;
1150 while (!r
&& IP_VALID(port
)) {
1152 r
= ref_act_port_locked(port
, &thr_act
);
1159 ref_act_port_locked( ipc_port_t port
, thread_act_t
*pthr_act
)
1161 thread_act_t thr_act
;
1164 if (ip_active(port
) &&
1165 (ip_kotype(port
) == IKOT_ACT
)) {
1166 thr_act
= (thread_act_t
) port
->ip_kobject
;
1167 assert(thr_act
!= THR_ACT_NULL
);
1170 * Out of order locking here, normal
1171 * ordering is act_lock(), then ip_lock().
1173 if (!act_lock_try(thr_act
)) {
1178 act_reference_locked(thr_act
);
1179 act_unlock(thr_act
);
1181 *pthr_act
= thr_act
;
1187 * Routine: port_name_to_act
1189 * Convert from a port name to an act reference
1190 * A name of MACH_PORT_NULL is valid for the null act
1196 mach_port_name_t name
)
1198 thread_act_t thr_act
= THR_ACT_NULL
;
1199 ipc_port_t kern_port
;
1202 if (MACH_PORT_VALID(name
)) {
1203 kr
= ipc_object_copyin(current_space(), name
,
1204 MACH_MSG_TYPE_COPY_SEND
,
1205 (ipc_object_t
*) &kern_port
);
1206 if (kr
!= KERN_SUCCESS
)
1207 return THR_ACT_NULL
;
1209 thr_act
= convert_port_to_act(kern_port
);
1211 if (IP_VALID(kern_port
))
1212 ipc_port_release_send(kern_port
);
1219 mach_port_name_t name
)
1221 ipc_port_t kern_port
;
1223 task_t task
= TASK_NULL
;
1225 if (MACH_PORT_VALID(name
)) {
1226 kr
= ipc_object_copyin(current_space(), name
,
1227 MACH_MSG_TYPE_COPY_SEND
,
1228 (ipc_object_t
*) &kern_port
);
1229 if (kr
!= KERN_SUCCESS
)
1232 task
= convert_port_to_task(kern_port
);
1234 if (IP_VALID(kern_port
))
1235 ipc_port_release_send(kern_port
);
1241 * Routine: convert_task_to_port
1243 * Convert from a task to a port.
1244 * Consumes a task ref; produces a naked send right
1245 * which may be invalid.
1251 convert_task_to_port(
1257 if (task
->itk_self
!= IP_NULL
)
1259 if (task
->map
== VM_MAP_NULL
)
1260 /* norma placeholder task */
1261 port
= ipc_port_copy_send(task
->itk_self
);
1263 #endif /* NORMA_TASK */
1264 port
= ipc_port_make_send(task
->itk_self
);
1269 task_deallocate(task
);
1274 * Routine: convert_act_to_port
1276 * Convert from a thr_act to a port.
1277 * Consumes an thr_act ref; produces a naked send right
1278 * which may be invalid.
1284 convert_act_to_port(thr_act
)
1285 thread_act_t thr_act
;
1290 if (thr_act
->ith_self
!= IP_NULL
)
1291 port
= ipc_port_make_send(thr_act
->ith_self
);
1294 act_unlock(thr_act
);
1296 act_deallocate(thr_act
);
1301 * Routine: space_deallocate
1303 * Deallocate a space ref produced by convert_port_to_space.
1312 if (space
!= IS_NULL
)
1317 * Routine: thread/task_set_exception_ports [kernel call]
1319 * Sets the thread/task exception port, flavor and
1320 * behavior for the exception types specified by the mask.
1321 * There will be one send right per exception per valid
1324 * Nothing locked. If successful, consumes
1325 * the supplied send right.
1327 * KERN_SUCCESS Changed the special port.
1328 * KERN_INVALID_ARGUMENT The thread is null,
1329 * Illegal mask bit set.
1330 * Illegal exception behavior
1331 * KERN_FAILURE The thread is dead.
1335 thread_set_exception_ports(
1336 thread_act_t thr_act
,
1337 exception_mask_t exception_mask
,
1338 ipc_port_t new_port
,
1339 exception_behavior_t new_behavior
,
1340 thread_state_flavor_t new_flavor
)
1343 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1346 return KERN_INVALID_ARGUMENT
;
1348 if (exception_mask
& ~EXC_MASK_ALL
)
1349 return KERN_INVALID_ARGUMENT
;
1351 if (IP_VALID(new_port
)) {
1352 switch (new_behavior
) {
1353 case EXCEPTION_DEFAULT
:
1354 case EXCEPTION_STATE
:
1355 case EXCEPTION_STATE_IDENTITY
:
1358 return KERN_INVALID_ARGUMENT
;
1363 * Check the validity of the thread_state_flavor by calling the
1364 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1365 * osfmk/mach/ARCHITECTURE/thread_status.h
1367 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
1368 return KERN_INVALID_ARGUMENT
;
1372 if (!thr_act
->active
) {
1373 act_unlock(thr_act
);
1374 return KERN_FAILURE
;
1377 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1378 if (exception_mask
& (1 << i
)) {
1379 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1380 thr_act
->exc_actions
[i
].port
=
1381 ipc_port_copy_send(new_port
);
1382 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1383 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1385 old_port
[i
] = IP_NULL
;
1388 * Consume send rights without any lock held.
1390 act_unlock(thr_act
);
1391 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1392 if (IP_VALID(old_port
[i
]))
1393 ipc_port_release_send(old_port
[i
]);
1394 if (IP_VALID(new_port
)) /* consume send right */
1395 ipc_port_release_send(new_port
);
1397 return KERN_SUCCESS
;
1398 }/* thread_set_exception_port */
1401 task_set_exception_ports(
1403 exception_mask_t exception_mask
,
1404 ipc_port_t new_port
,
1405 exception_behavior_t new_behavior
,
1406 thread_state_flavor_t new_flavor
)
1409 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1411 if (task
== TASK_NULL
) {
1412 return KERN_INVALID_ARGUMENT
;
1415 if (exception_mask
& ~EXC_MASK_ALL
) {
1416 return KERN_INVALID_ARGUMENT
;
1419 if (IP_VALID(new_port
)) {
1420 switch (new_behavior
) {
1421 case EXCEPTION_DEFAULT
:
1422 case EXCEPTION_STATE
:
1423 case EXCEPTION_STATE_IDENTITY
:
1426 return KERN_INVALID_ARGUMENT
;
1429 /* Cannot easily check "new_flavor", but that just means that
1430 * the flavor in the generated exception message might be garbage:
1434 if (task
->itk_self
== IP_NULL
) {
1436 return KERN_FAILURE
;
1439 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1440 if (exception_mask
& (1 << i
)) {
1441 old_port
[i
] = task
->exc_actions
[i
].port
;
1442 task
->exc_actions
[i
].port
=
1443 ipc_port_copy_send(new_port
);
1444 task
->exc_actions
[i
].behavior
= new_behavior
;
1445 task
->exc_actions
[i
].flavor
= new_flavor
;
1447 old_port
[i
] = IP_NULL
;
1451 * Consume send rights without any lock held.
1454 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1455 if (IP_VALID(old_port
[i
]))
1456 ipc_port_release_send(old_port
[i
]);
1457 if (IP_VALID(new_port
)) /* consume send right */
1458 ipc_port_release_send(new_port
);
1460 return KERN_SUCCESS
;
1461 }/* task_set_exception_port */
1464 * Routine: thread/task_swap_exception_ports [kernel call]
1466 * Sets the thread/task exception port, flavor and
1467 * behavior for the exception types specified by the
1470 * The old ports, behavior and flavors are returned
1471 * Count specifies the array sizes on input and
1472 * the number of returned ports etc. on output. The
1473 * arrays must be large enough to hold all the returned
1474 * data, MIG returnes an error otherwise. The masks
1475 * array specifies the corresponding exception type(s).
1478 * Nothing locked. If successful, consumes
1479 * the supplied send right.
1481 * Returns upto [in} CountCnt elements.
1483 * KERN_SUCCESS Changed the special port.
1484 * KERN_INVALID_ARGUMENT The thread is null,
1485 * Illegal mask bit set.
1486 * Illegal exception behavior
1487 * KERN_FAILURE The thread is dead.
1491 thread_swap_exception_ports(
1492 thread_act_t thr_act
,
1493 exception_mask_t exception_mask
,
1494 ipc_port_t new_port
,
1495 exception_behavior_t new_behavior
,
1496 thread_state_flavor_t new_flavor
,
1497 exception_mask_array_t masks
,
1498 mach_msg_type_number_t
* CountCnt
,
1499 exception_port_array_t ports
,
1500 exception_behavior_array_t behaviors
,
1501 thread_state_flavor_array_t flavors
)
1506 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1509 return KERN_INVALID_ARGUMENT
;
1511 if (exception_mask
& ~EXC_MASK_ALL
) {
1512 return KERN_INVALID_ARGUMENT
;
1515 if (IP_VALID(new_port
)) {
1516 switch (new_behavior
) {
1517 case EXCEPTION_DEFAULT
:
1518 case EXCEPTION_STATE
:
1519 case EXCEPTION_STATE_IDENTITY
:
1522 return KERN_INVALID_ARGUMENT
;
1525 /* Cannot easily check "new_flavor", but that just means that
1526 * the flavor in the generated exception message might be garbage:
1530 if (!thr_act
->active
) {
1531 act_unlock(thr_act
);
1532 return KERN_FAILURE
;
1537 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1538 if (exception_mask
& (1 << i
)) {
1539 for (j
= 0; j
< count
; j
++) {
1541 * search for an identical entry, if found
1542 * set corresponding mask for this exception.
1544 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1545 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1546 && thr_act
->exc_actions
[i
].flavor
==flavors
[j
])
1548 masks
[j
] |= (1 << i
);
1553 masks
[j
] = (1 << i
);
1555 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1557 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1558 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1562 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1563 thr_act
->exc_actions
[i
].port
=
1564 ipc_port_copy_send(new_port
);
1565 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1566 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1567 if (count
> *CountCnt
) {
1571 old_port
[i
] = IP_NULL
;
1575 * Consume send rights without any lock held.
1577 act_unlock(thr_act
);
1578 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1579 if (IP_VALID(old_port
[i
]))
1580 ipc_port_release_send(old_port
[i
]);
1581 if (IP_VALID(new_port
)) /* consume send right */
1582 ipc_port_release_send(new_port
);
1584 return KERN_SUCCESS
;
1585 }/* thread_swap_exception_ports */
1588 task_swap_exception_ports(
1590 exception_mask_t exception_mask
,
1591 ipc_port_t new_port
,
1592 exception_behavior_t new_behavior
,
1593 thread_state_flavor_t new_flavor
,
1594 exception_mask_array_t masks
,
1595 mach_msg_type_number_t
* CountCnt
,
1596 exception_port_array_t ports
,
1597 exception_behavior_array_t behaviors
,
1598 thread_state_flavor_array_t flavors
)
1603 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1605 if (task
== TASK_NULL
)
1606 return KERN_INVALID_ARGUMENT
;
1608 if (exception_mask
& ~EXC_MASK_ALL
) {
1609 return KERN_INVALID_ARGUMENT
;
1612 if (IP_VALID(new_port
)) {
1613 switch (new_behavior
) {
1614 case EXCEPTION_DEFAULT
:
1615 case EXCEPTION_STATE
:
1616 case EXCEPTION_STATE_IDENTITY
:
1619 return KERN_INVALID_ARGUMENT
;
1622 /* Cannot easily check "new_flavor", but that just means that
1623 * the flavor in the generated exception message might be garbage:
1627 if (task
->itk_self
== IP_NULL
) {
1629 return KERN_FAILURE
;
1634 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1635 if (exception_mask
& (1 << i
)) {
1636 for (j
= 0; j
< count
; j
++) {
1638 * search for an identical entry, if found
1639 * set corresponding mask for this exception.
1641 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1642 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1643 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1645 masks
[j
] |= (1 << i
);
1650 masks
[j
] = (1 << i
);
1652 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1653 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1654 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1657 old_port
[i
] = task
->exc_actions
[i
].port
;
1658 task
->exc_actions
[i
].port
=
1659 ipc_port_copy_send(new_port
);
1660 task
->exc_actions
[i
].behavior
= new_behavior
;
1661 task
->exc_actions
[i
].flavor
= new_flavor
;
1662 if (count
> *CountCnt
) {
1666 old_port
[i
] = IP_NULL
;
1671 * Consume send rights without any lock held.
1674 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1675 if (IP_VALID(old_port
[i
]))
1676 ipc_port_release_send(old_port
[i
]);
1677 if (IP_VALID(new_port
)) /* consume send right */
1678 ipc_port_release_send(new_port
);
1681 return KERN_SUCCESS
;
1682 }/* task_swap_exception_ports */
1685 * Routine: thread/task_get_exception_ports [kernel call]
1687 * Clones a send right for each of the thread/task's exception
1688 * ports specified in the mask and returns the behaviour
1689 * and flavor of said port.
1691 * Returns upto [in} CountCnt elements.
1696 * KERN_SUCCESS Extracted a send right.
1697 * KERN_INVALID_ARGUMENT The thread is null,
1698 * Invalid special port,
1699 * Illegal mask bit set.
1700 * KERN_FAILURE The thread is dead.
1704 thread_get_exception_ports(
1705 thread_act_t thr_act
,
1706 exception_mask_t exception_mask
,
1707 exception_mask_array_t masks
,
1708 mach_msg_type_number_t
* CountCnt
,
1709 exception_port_array_t ports
,
1710 exception_behavior_array_t behaviors
,
1711 thread_state_flavor_array_t flavors
)
1718 return KERN_INVALID_ARGUMENT
;
1720 if (exception_mask
& ~EXC_MASK_ALL
) {
1721 return KERN_INVALID_ARGUMENT
;
1725 if (!thr_act
->active
) {
1726 act_unlock(thr_act
);
1727 return KERN_FAILURE
;
1732 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1733 if (exception_mask
& (1 << i
)) {
1734 for (j
= 0; j
< count
; j
++) {
1736 * search for an identical entry, if found
1737 * set corresponding mask for this exception.
1739 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1740 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1741 && thr_act
->exc_actions
[i
].flavor
== flavors
[j
])
1743 masks
[j
] |= (1 << i
);
1748 masks
[j
] = (1 << i
);
1750 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1751 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1752 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1754 if (count
>= *CountCnt
) {
1761 act_unlock(thr_act
);
1764 return KERN_SUCCESS
;
1765 }/* thread_get_exception_ports */
1768 task_get_exception_ports(
1770 exception_mask_t exception_mask
,
1771 exception_mask_array_t masks
,
1772 mach_msg_type_number_t
* CountCnt
,
1773 exception_port_array_t ports
,
1774 exception_behavior_array_t behaviors
,
1775 thread_state_flavor_array_t flavors
)
1781 if (task
== TASK_NULL
)
1782 return KERN_INVALID_ARGUMENT
;
1784 if (exception_mask
& ~EXC_MASK_ALL
) {
1785 return KERN_INVALID_ARGUMENT
;
1789 if (task
->itk_self
== IP_NULL
) {
1791 return KERN_FAILURE
;
1796 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1797 if (exception_mask
& (1 << i
)) {
1798 for (j
= 0; j
< count
; j
++) {
1800 * search for an identical entry, if found
1801 * set corresponding mask for this exception.
1803 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1804 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1805 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1807 masks
[j
] |= (1 << i
);
1812 masks
[j
] = (1 << i
);
1814 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1815 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1816 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1818 if (count
> *CountCnt
) {
1828 return KERN_SUCCESS
;
1829 }/* task_get_exception_ports */