2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28 * All Rights Reserved.
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
56 * Task and thread related IPC functions.
59 #include <mach/boolean.h>
61 #include <mach/kern_return.h>
62 #include <mach/mach_param.h>
63 #include <mach/task_special_ports.h>
64 #include <mach/thread_special_ports.h>
65 #include <mach/thread_status.h>
66 #include <mach/exception_types.h>
67 #include <mach/mach_traps.h>
68 #include <mach/task_server.h>
69 #include <mach/thread_act_server.h>
70 #include <mach/mach_host_server.h>
71 #include <mach/vm_map_server.h>
72 #include <kern/host.h>
73 #include <kern/ipc_tt.h>
74 #include <kern/thread_act.h>
75 #include <kern/misc_protos.h>
76 #include <vm/vm_pageout.h>
79 * Routine: ipc_task_init
81 * Initialize a task's IPC state.
83 * If non-null, some state will be inherited from the parent.
84 * The parent must be appropriately initialized.
100 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
101 if (kr
!= KERN_SUCCESS
)
102 panic("ipc_task_init");
105 kport
= ipc_port_alloc_kernel();
106 if (kport
== IP_NULL
)
107 panic("ipc_task_init");
110 task
->itk_self
= kport
;
111 task
->itk_sself
= ipc_port_make_send(kport
);
112 task
->itk_space
= space
;
113 space
->is_fast
= task
->kernel_loaded
;
115 if (parent
== TASK_NULL
) {
116 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
117 task
->exc_actions
[i
].port
= IP_NULL
;
119 task
->itk_host
= ipc_port_make_send(realhost
.host_self
);
120 task
->itk_bootstrap
= IP_NULL
;
121 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
122 task
->itk_registered
[i
] = IP_NULL
;
125 assert(parent
->itk_self
!= IP_NULL
);
127 /* inherit registered ports */
129 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
130 task
->itk_registered
[i
] =
131 ipc_port_copy_send(parent
->itk_registered
[i
]);
133 /* inherit exception and bootstrap ports */
135 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
136 task
->exc_actions
[i
].port
=
137 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
138 task
->exc_actions
[i
].flavor
=
139 parent
->exc_actions
[i
].flavor
;
140 task
->exc_actions
[i
].behavior
=
141 parent
->exc_actions
[i
].behavior
;
144 ipc_port_copy_send(parent
->itk_host
);
146 task
->itk_bootstrap
=
147 ipc_port_copy_send(parent
->itk_bootstrap
);
154 * Routine: ipc_task_enable
156 * Enable a task for IPC access.
168 kport
= task
->itk_self
;
169 if (kport
!= IP_NULL
)
170 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
175 * Routine: ipc_task_disable
177 * Disable IPC access to a task.
189 kport
= task
->itk_self
;
190 if (kport
!= IP_NULL
)
191 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
196 * Routine: ipc_task_terminate
198 * Clean up and destroy a task's IPC state.
200 * Nothing locked. The task must be suspended.
201 * (Or the current thread must be in the task.)
212 kport
= task
->itk_self
;
214 if (kport
== IP_NULL
) {
215 /* the task is already terminated (can this happen?) */
220 task
->itk_self
= IP_NULL
;
223 /* release the naked send rights */
225 if (IP_VALID(task
->itk_sself
))
226 ipc_port_release_send(task
->itk_sself
);
228 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
229 if (IP_VALID(task
->exc_actions
[i
].port
)) {
230 ipc_port_release_send(task
->exc_actions
[i
].port
);
233 if (IP_VALID(task
->itk_host
))
234 ipc_port_release_send(task
->itk_host
);
236 if (IP_VALID(task
->itk_bootstrap
))
237 ipc_port_release_send(task
->itk_bootstrap
);
239 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
240 if (IP_VALID(task
->itk_registered
[i
]))
241 ipc_port_release_send(task
->itk_registered
[i
]);
243 ipc_port_release_send(task
->wired_ledger_port
);
244 ipc_port_release_send(task
->paged_ledger_port
);
246 /* destroy the kernel port */
247 ipc_port_dealloc_kernel(kport
);
251 * Routine: ipc_thread_init
253 * Initialize a thread's IPC state.
262 ipc_kmsg_queue_init(&thread
->ith_messages
);
263 thread
->ith_mig_reply
= MACH_PORT_NULL
;
264 thread
->ith_rpc_reply
= IP_NULL
;
268 * Routine: ipc_thread_terminate
270 * Clean up and destroy a thread's IPC state.
272 * Nothing locked. The thread must be suspended.
273 * (Or be the current thread.)
277 ipc_thread_terminate(
280 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
282 if (thread
->ith_rpc_reply
!= IP_NULL
)
283 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
284 thread
->ith_rpc_reply
= IP_NULL
;
288 * Routine: ipc_thr_act_init
290 * Initialize an thr_act's IPC state.
296 ipc_thr_act_init(task_t task
, thread_act_t thr_act
)
298 ipc_port_t kport
; int i
;
300 kport
= ipc_port_alloc_kernel();
301 if (kport
== IP_NULL
)
302 panic("ipc_thr_act_init");
304 thr_act
->ith_self
= kport
;
305 thr_act
->ith_sself
= ipc_port_make_send(kport
);
307 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
308 thr_act
->exc_actions
[i
].port
= IP_NULL
;
310 ipc_kobject_set(kport
, (ipc_kobject_t
) thr_act
, IKOT_ACT
);
314 ipc_thr_act_disable(thread_act_t thr_act
)
319 kport
= thr_act
->ith_self
;
321 if (kport
!= IP_NULL
)
322 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
326 ipc_thr_act_terminate(thread_act_t thr_act
)
328 ipc_port_t kport
; int i
;
330 kport
= thr_act
->ith_self
;
332 if (kport
== IP_NULL
) {
333 /* the thread is already terminated (can this happen?) */
337 thr_act
->ith_self
= IP_NULL
;
339 /* release the naked send rights */
341 if (IP_VALID(thr_act
->ith_sself
))
342 ipc_port_release_send(thr_act
->ith_sself
);
343 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
344 if (IP_VALID(thr_act
->exc_actions
[i
].port
))
345 ipc_port_release_send(thr_act
->exc_actions
[i
].port
);
348 /* destroy the kernel port */
349 ipc_port_dealloc_kernel(kport
);
353 * Routine: retrieve_task_self_fast
355 * Optimized version of retrieve_task_self,
356 * that only works for the current task.
358 * Return a send right (possibly null/dead)
359 * for the task's user-visible self port.
365 retrieve_task_self_fast(
366 register task_t task
)
368 register ipc_port_t port
;
370 assert(task
== current_task());
373 assert(task
->itk_self
!= IP_NULL
);
375 if ((port
= task
->itk_sself
) == task
->itk_self
) {
379 assert(ip_active(port
));
384 port
= ipc_port_copy_send(port
);
391 * Routine: retrieve_act_self_fast
393 * Optimized version of retrieve_thread_self,
394 * that only works for the current thread.
396 * Return a send right (possibly null/dead)
397 * for the thread's user-visible self port.
403 retrieve_act_self_fast(thread_act_t thr_act
)
405 register ipc_port_t port
;
407 assert(thr_act
== current_act());
409 assert(thr_act
->ith_self
!= IP_NULL
);
411 if ((port
= thr_act
->ith_sself
) == thr_act
->ith_self
) {
415 assert(ip_active(port
));
420 port
= ipc_port_copy_send(port
);
427 * Routine: task_self_trap [mach trap]
429 * Give the caller send rights for his own task port.
433 * MACH_PORT_NULL if there are any resource failures
440 task_t task
= current_task();
443 sright
= retrieve_task_self_fast(task
);
444 return ipc_port_copyout_send(sright
, task
->itk_space
);
448 * Routine: thread_self_trap [mach trap]
450 * Give the caller send rights for his own thread port.
454 * MACH_PORT_NULL if there are any resource failures
459 thread_self_trap(void)
461 thread_act_t thr_act
= current_act();
462 task_t task
= thr_act
->task
;
465 sright
= retrieve_act_self_fast(thr_act
);
466 return ipc_port_copyout_send(sright
, task
->itk_space
);
470 * Routine: mach_reply_port [mach trap]
472 * Allocate a port for the caller.
476 * MACH_PORT_NULL if there are any resource failures
481 mach_reply_port(void)
484 mach_port_name_t name
;
487 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
488 if (kr
== KERN_SUCCESS
)
491 name
= MACH_PORT_NULL
;
497 * Routine: task_get_special_port [kernel call]
499 * Clones a send right for one of the task's
504 * KERN_SUCCESS Extracted a send right.
505 * KERN_INVALID_ARGUMENT The task is null.
506 * KERN_FAILURE The task/space is dead.
507 * KERN_INVALID_ARGUMENT Invalid special port.
511 task_get_special_port(
519 if (task
== TASK_NULL
)
520 return KERN_INVALID_ARGUMENT
;
523 case TASK_KERNEL_PORT
:
524 whichp
= &task
->itk_sself
;
528 whichp
= &task
->itk_host
;
531 case TASK_BOOTSTRAP_PORT
:
532 whichp
= &task
->itk_bootstrap
;
535 case TASK_WIRED_LEDGER_PORT
:
536 whichp
= &task
->wired_ledger_port
;
539 case TASK_PAGED_LEDGER_PORT
:
540 whichp
= &task
->paged_ledger_port
;
544 return KERN_INVALID_ARGUMENT
;
548 if (task
->itk_self
== IP_NULL
) {
553 port
= ipc_port_copy_send(*whichp
);
561 * Routine: task_set_special_port [kernel call]
563 * Changes one of the task's special ports,
564 * setting it to the supplied send right.
566 * Nothing locked. If successful, consumes
567 * the supplied send right.
569 * KERN_SUCCESS Changed the special port.
570 * KERN_INVALID_ARGUMENT The task is null.
571 * KERN_FAILURE The task/space is dead.
572 * KERN_INVALID_ARGUMENT Invalid special port.
576 task_set_special_port(
584 if (task
== TASK_NULL
)
585 return KERN_INVALID_ARGUMENT
;
588 case TASK_KERNEL_PORT
:
589 whichp
= &task
->itk_sself
;
593 whichp
= &task
->itk_host
;
596 case TASK_BOOTSTRAP_PORT
:
597 whichp
= &task
->itk_bootstrap
;
600 case TASK_WIRED_LEDGER_PORT
:
601 whichp
= &task
->wired_ledger_port
;
604 case TASK_PAGED_LEDGER_PORT
:
605 whichp
= &task
->paged_ledger_port
;
609 return KERN_INVALID_ARGUMENT
;
613 if (task
->itk_self
== IP_NULL
) {
623 ipc_port_release_send(old
);
629 * Routine: mach_ports_register [kernel call]
631 * Stash a handful of port send rights in the task.
632 * Child tasks will inherit these rights, but they
633 * must use mach_ports_lookup to acquire them.
635 * The rights are supplied in a (wired) kalloc'd segment.
636 * Rights which aren't supplied are assumed to be null.
638 * Nothing locked. If successful, consumes
639 * the supplied rights and memory.
641 * KERN_SUCCESS Stashed the port rights.
642 * KERN_INVALID_ARGUMENT The task is null.
643 * KERN_INVALID_ARGUMENT The task is dead.
644 * KERN_INVALID_ARGUMENT Too many port rights supplied.
650 mach_port_array_t memory
,
651 mach_msg_type_number_t portsCnt
)
653 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
656 if ((task
== TASK_NULL
) ||
657 (portsCnt
> TASK_PORT_REGISTER_MAX
))
658 return KERN_INVALID_ARGUMENT
;
661 * Pad the port rights with nulls.
664 for (i
= 0; i
< portsCnt
; i
++)
665 ports
[i
] = memory
[i
];
666 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
670 if (task
->itk_self
== IP_NULL
) {
672 return KERN_INVALID_ARGUMENT
;
676 * Replace the old send rights with the new.
677 * Release the old rights after unlocking.
680 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
683 old
= task
->itk_registered
[i
];
684 task
->itk_registered
[i
] = ports
[i
];
690 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
691 if (IP_VALID(ports
[i
]))
692 ipc_port_release_send(ports
[i
]);
695 * Now that the operation is known to be successful,
696 * we can free the memory.
700 kfree((vm_offset_t
) memory
,
701 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
707 * Routine: mach_ports_lookup [kernel call]
709 * Retrieves (clones) the stashed port send rights.
711 * Nothing locked. If successful, the caller gets
714 * KERN_SUCCESS Retrieved the send rights.
715 * KERN_INVALID_ARGUMENT The task is null.
716 * KERN_INVALID_ARGUMENT The task is dead.
717 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
723 mach_port_array_t
*portsp
,
724 mach_msg_type_number_t
*portsCnt
)
733 if (task
== TASK_NULL
)
734 return KERN_INVALID_ARGUMENT
;
736 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
738 memory
= kalloc(size
);
740 return KERN_RESOURCE_SHORTAGE
;
743 if (task
->itk_self
== IP_NULL
) {
747 return KERN_INVALID_ARGUMENT
;
750 ports
= (ipc_port_t
*) memory
;
753 * Clone port rights. Because kalloc'd memory
754 * is wired, we won't fault while holding the task lock.
757 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
758 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
762 *portsp
= (mach_port_array_t
) ports
;
763 *portsCnt
= TASK_PORT_REGISTER_MAX
;
768 * Routine: convert_port_to_locked_task
770 * Internal helper routine to convert from a port to a locked
771 * task. Used by several routines that try to convert from a
772 * task port to a reference on some task related object.
774 * Nothing locked, blocking OK.
777 convert_port_to_locked_task(ipc_port_t port
)
779 while (IP_VALID(port
)) {
783 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
787 task
= (task_t
) port
->ip_kobject
;
788 assert(task
!= TASK_NULL
);
791 * Normal lock ordering puts task_lock() before ip_lock().
792 * Attempt out-of-order locking here.
794 if (task_lock_try(task
)) {
806 * Routine: convert_port_to_task
808 * Convert from a port to a task.
809 * Doesn't consume the port ref; produces a task ref,
815 convert_port_to_task(
820 task
= convert_port_to_locked_task(port
);
829 * Routine: convert_port_to_space
831 * Convert from a port to a space.
832 * Doesn't consume the port ref; produces a space ref,
838 convert_port_to_space(
844 task
= convert_port_to_locked_task(port
);
846 if (task
== TASK_NULL
)
847 return IPC_SPACE_NULL
;
851 return IPC_SPACE_NULL
;
854 space
= task
->itk_space
;
867 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_UPL
)) {
871 upl
= (upl_t
) port
->ip_kobject
;
883 return MACH_PORT_NULL
;
886 __private_extern__
void
889 mach_port_mscount_t mscount
)
895 * Routine: convert_port_entry_to_map
897 * Convert from a port specifying an entry or a task
898 * to a map. Doesn't consume the port ref; produces a map ref,
899 * which may be null. Unlike convert_port_to_map, the
900 * port may be task or a named entry backed.
907 convert_port_entry_to_map(
912 vm_named_entry_t named_entry
;
914 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
917 if(ip_active(port
) && (ip_kotype(port
)
918 == IKOT_NAMED_ENTRY
)) {
920 (vm_named_entry_t
)port
->ip_kobject
;
921 if (!(mutex_try(&(named_entry
)->Lock
))) {
926 named_entry
->ref_count
++;
927 mutex_unlock(&(named_entry
)->Lock
);
929 if ((named_entry
->is_sub_map
) &&
930 (named_entry
->protection
932 map
= named_entry
->backing
.map
;
934 mach_destroy_memory_entry(port
);
937 vm_map_reference_swap(map
);
938 mach_destroy_memory_entry(port
);
947 task
= convert_port_to_locked_task(port
);
949 if (task
== TASK_NULL
)
958 vm_map_reference_swap(map
);
966 * Routine: convert_port_entry_to_object
968 * Convert from a port specifying a named entry to an
969 * object. Doesn't consume the port ref; produces a map ref,
977 convert_port_entry_to_object(
981 vm_named_entry_t named_entry
;
983 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
986 if(ip_active(port
) && (ip_kotype(port
)
987 == IKOT_NAMED_ENTRY
)) {
989 (vm_named_entry_t
)port
->ip_kobject
;
990 if (!(mutex_try(&(named_entry
)->Lock
))) {
995 named_entry
->ref_count
++;
996 mutex_unlock(&(named_entry
)->Lock
);
998 if ((!named_entry
->is_sub_map
) &&
999 (named_entry
->protection
1001 object
= named_entry
->object
;
1003 mach_destroy_memory_entry(port
);
1004 return (vm_object_t
)NULL
;
1006 vm_object_reference(named_entry
->object
);
1007 mach_destroy_memory_entry(port
);
1011 return (vm_object_t
)NULL
;
1014 return (vm_object_t
)NULL
;
1021 * Routine: convert_port_to_map
1023 * Convert from a port to a map.
1024 * Doesn't consume the port ref; produces a map ref,
1025 * which may be null.
1031 convert_port_to_map(
1037 task
= convert_port_to_locked_task(port
);
1039 if (task
== TASK_NULL
)
1042 if (!task
->active
) {
1048 vm_map_reference_swap(map
);
1055 * Routine: convert_port_to_act
1057 * Convert from a port to a thr_act.
1058 * Doesn't consume the port ref; produces an thr_act ref,
1059 * which may be null.
1065 convert_port_to_act( ipc_port_t port
)
1068 thread_act_t thr_act
= 0;
1071 while (!r
&& IP_VALID(port
)) {
1073 r
= ref_act_port_locked(port
, &thr_act
);
1080 ref_act_port_locked( ipc_port_t port
, thread_act_t
*pthr_act
)
1082 thread_act_t thr_act
;
1085 if (ip_active(port
) &&
1086 (ip_kotype(port
) == IKOT_ACT
)) {
1087 thr_act
= (thread_act_t
) port
->ip_kobject
;
1088 assert(thr_act
!= THR_ACT_NULL
);
1091 * Normal lock ordering is act_lock(), then ip_lock().
1092 * Allow out-of-order locking here, using
1093 * act_reference_act_locked() to accomodate it.
1095 if (!act_lock_try(thr_act
)) {
1100 act_locked_act_reference(thr_act
);
1101 act_unlock(thr_act
);
1103 *pthr_act
= thr_act
;
1109 * Routine: port_name_to_act
1111 * Convert from a port name to an act reference
1112 * A name of MACH_PORT_NULL is valid for the null act
1118 mach_port_name_t name
)
1120 thread_act_t thr_act
= THR_ACT_NULL
;
1121 ipc_port_t kern_port
;
1124 if (MACH_PORT_VALID(name
)) {
1125 kr
= ipc_object_copyin(current_space(), name
,
1126 MACH_MSG_TYPE_COPY_SEND
,
1127 (ipc_object_t
*) &kern_port
);
1128 if (kr
!= KERN_SUCCESS
)
1129 return THR_ACT_NULL
;
1131 thr_act
= convert_port_to_act(kern_port
);
1133 if (IP_VALID(kern_port
))
1134 ipc_port_release_send(kern_port
);
1141 mach_port_name_t name
)
1143 ipc_port_t kern_port
;
1145 task_t task
= TASK_NULL
;
1147 if (MACH_PORT_VALID(name
)) {
1148 kr
= ipc_object_copyin(current_space(), name
,
1149 MACH_MSG_TYPE_COPY_SEND
,
1150 (ipc_object_t
*) &kern_port
);
1151 if (kr
!= KERN_SUCCESS
)
1154 task
= convert_port_to_task(kern_port
);
1156 if (IP_VALID(kern_port
))
1157 ipc_port_release_send(kern_port
);
1163 * Routine: convert_task_to_port
1165 * Convert from a task to a port.
1166 * Consumes a task ref; produces a naked send right
1167 * which may be invalid.
1173 convert_task_to_port(
1179 if (task
->itk_self
!= IP_NULL
)
1181 if (task
->map
== VM_MAP_NULL
)
1182 /* norma placeholder task */
1183 port
= ipc_port_copy_send(task
->itk_self
);
1185 #endif /* NORMA_TASK */
1186 port
= ipc_port_make_send(task
->itk_self
);
1191 task_deallocate(task
);
1196 * Routine: convert_act_to_port
1198 * Convert from a thr_act to a port.
1199 * Consumes an thr_act ref; produces a naked send right
1200 * which may be invalid.
1206 convert_act_to_port(thr_act
)
1207 thread_act_t thr_act
;
1212 if (thr_act
->ith_self
!= IP_NULL
)
1213 port
= ipc_port_make_send(thr_act
->ith_self
);
1216 act_unlock(thr_act
);
1218 act_deallocate(thr_act
);
1223 * Routine: space_deallocate
1225 * Deallocate a space ref produced by convert_port_to_space.
1234 if (space
!= IS_NULL
)
1239 * Routine: thread/task_set_exception_ports [kernel call]
1241 * Sets the thread/task exception port, flavor and
1242 * behavior for the exception types specified by the mask.
1243 * There will be one send right per exception per valid
1246 * Nothing locked. If successful, consumes
1247 * the supplied send right.
1249 * KERN_SUCCESS Changed the special port.
1250 * KERN_INVALID_ARGUMENT The thread is null,
1251 * Illegal mask bit set.
1252 * Illegal exception behavior
1253 * KERN_FAILURE The thread is dead.
1257 thread_set_exception_ports(
1258 thread_act_t thr_act
,
1259 exception_mask_t exception_mask
,
1260 ipc_port_t new_port
,
1261 exception_behavior_t new_behavior
,
1262 thread_state_flavor_t new_flavor
)
1265 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1268 return KERN_INVALID_ARGUMENT
;
1270 if (exception_mask
& ~EXC_MASK_ALL
)
1271 return KERN_INVALID_ARGUMENT
;
1273 if (IP_VALID(new_port
)) {
1274 switch (new_behavior
) {
1275 case EXCEPTION_DEFAULT
:
1276 case EXCEPTION_STATE
:
1277 case EXCEPTION_STATE_IDENTITY
:
1280 return KERN_INVALID_ARGUMENT
;
1285 * Check the validity of the thread_state_flavor by calling the
1286 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1287 * osfmk/mach/ARCHITECTURE/thread_status.h
1289 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
1290 return KERN_INVALID_ARGUMENT
;
1294 if (!thr_act
->active
) {
1295 act_unlock(thr_act
);
1296 return KERN_FAILURE
;
1299 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1300 if (exception_mask
& (1 << i
)) {
1301 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1302 thr_act
->exc_actions
[i
].port
=
1303 ipc_port_copy_send(new_port
);
1304 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1305 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1307 old_port
[i
] = IP_NULL
;
1310 * Consume send rights without any lock held.
1312 act_unlock(thr_act
);
1313 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1314 if (IP_VALID(old_port
[i
]))
1315 ipc_port_release_send(old_port
[i
]);
1316 if (IP_VALID(new_port
)) /* consume send right */
1317 ipc_port_release_send(new_port
);
1319 return KERN_SUCCESS
;
1320 }/* thread_set_exception_port */
1323 task_set_exception_ports(
1325 exception_mask_t exception_mask
,
1326 ipc_port_t new_port
,
1327 exception_behavior_t new_behavior
,
1328 thread_state_flavor_t new_flavor
)
1331 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1333 if (task
== TASK_NULL
) {
1334 return KERN_INVALID_ARGUMENT
;
1337 if (exception_mask
& ~EXC_MASK_ALL
) {
1338 return KERN_INVALID_ARGUMENT
;
1341 if (IP_VALID(new_port
)) {
1342 switch (new_behavior
) {
1343 case EXCEPTION_DEFAULT
:
1344 case EXCEPTION_STATE
:
1345 case EXCEPTION_STATE_IDENTITY
:
1348 return KERN_INVALID_ARGUMENT
;
1351 /* Cannot easily check "new_flavor", but that just means that
1352 * the flavor in the generated exception message might be garbage:
1356 if (task
->itk_self
== IP_NULL
) {
1358 return KERN_FAILURE
;
1361 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1362 if (exception_mask
& (1 << i
)) {
1363 old_port
[i
] = task
->exc_actions
[i
].port
;
1364 task
->exc_actions
[i
].port
=
1365 ipc_port_copy_send(new_port
);
1366 task
->exc_actions
[i
].behavior
= new_behavior
;
1367 task
->exc_actions
[i
].flavor
= new_flavor
;
1369 old_port
[i
] = IP_NULL
;
1373 * Consume send rights without any lock held.
1376 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1377 if (IP_VALID(old_port
[i
]))
1378 ipc_port_release_send(old_port
[i
]);
1379 if (IP_VALID(new_port
)) /* consume send right */
1380 ipc_port_release_send(new_port
);
1382 return KERN_SUCCESS
;
1383 }/* task_set_exception_port */
1386 * Routine: thread/task_swap_exception_ports [kernel call]
1388 * Sets the thread/task exception port, flavor and
1389 * behavior for the exception types specified by the
1392 * The old ports, behavior and flavors are returned
1393 * Count specifies the array sizes on input and
1394 * the number of returned ports etc. on output. The
1395 * arrays must be large enough to hold all the returned
1396 * data, MIG returnes an error otherwise. The masks
1397 * array specifies the corresponding exception type(s).
1400 * Nothing locked. If successful, consumes
1401 * the supplied send right.
1403 * Returns upto [in} CountCnt elements.
1405 * KERN_SUCCESS Changed the special port.
1406 * KERN_INVALID_ARGUMENT The thread is null,
1407 * Illegal mask bit set.
1408 * Illegal exception behavior
1409 * KERN_FAILURE The thread is dead.
1413 thread_swap_exception_ports(
1414 thread_act_t thr_act
,
1415 exception_mask_t exception_mask
,
1416 ipc_port_t new_port
,
1417 exception_behavior_t new_behavior
,
1418 thread_state_flavor_t new_flavor
,
1419 exception_mask_array_t masks
,
1420 mach_msg_type_number_t
* CountCnt
,
1421 exception_port_array_t ports
,
1422 exception_behavior_array_t behaviors
,
1423 thread_state_flavor_array_t flavors
)
1428 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1431 return KERN_INVALID_ARGUMENT
;
1433 if (exception_mask
& ~EXC_MASK_ALL
) {
1434 return KERN_INVALID_ARGUMENT
;
1437 if (IP_VALID(new_port
)) {
1438 switch (new_behavior
) {
1439 case EXCEPTION_DEFAULT
:
1440 case EXCEPTION_STATE
:
1441 case EXCEPTION_STATE_IDENTITY
:
1444 return KERN_INVALID_ARGUMENT
;
1447 /* Cannot easily check "new_flavor", but that just means that
1448 * the flavor in the generated exception message might be garbage:
1452 if (!thr_act
->active
) {
1453 act_unlock(thr_act
);
1454 return KERN_FAILURE
;
1459 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1460 if (exception_mask
& (1 << i
)) {
1461 for (j
= 0; j
< count
; j
++) {
1463 * search for an identical entry, if found
1464 * set corresponding mask for this exception.
1466 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1467 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1468 && thr_act
->exc_actions
[i
].flavor
==flavors
[j
])
1470 masks
[j
] |= (1 << i
);
1475 masks
[j
] = (1 << i
);
1477 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1479 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1480 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1484 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1485 thr_act
->exc_actions
[i
].port
=
1486 ipc_port_copy_send(new_port
);
1487 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1488 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1489 if (count
> *CountCnt
) {
1493 old_port
[i
] = IP_NULL
;
1497 * Consume send rights without any lock held.
1499 act_unlock(thr_act
);
1500 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1501 if (IP_VALID(old_port
[i
]))
1502 ipc_port_release_send(old_port
[i
]);
1503 if (IP_VALID(new_port
)) /* consume send right */
1504 ipc_port_release_send(new_port
);
1506 return KERN_SUCCESS
;
1507 }/* thread_swap_exception_ports */
1510 task_swap_exception_ports(
1512 exception_mask_t exception_mask
,
1513 ipc_port_t new_port
,
1514 exception_behavior_t new_behavior
,
1515 thread_state_flavor_t new_flavor
,
1516 exception_mask_array_t masks
,
1517 mach_msg_type_number_t
* CountCnt
,
1518 exception_port_array_t ports
,
1519 exception_behavior_array_t behaviors
,
1520 thread_state_flavor_array_t flavors
)
1525 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1527 if (task
== TASK_NULL
)
1528 return KERN_INVALID_ARGUMENT
;
1530 if (exception_mask
& ~EXC_MASK_ALL
) {
1531 return KERN_INVALID_ARGUMENT
;
1534 if (IP_VALID(new_port
)) {
1535 switch (new_behavior
) {
1536 case EXCEPTION_DEFAULT
:
1537 case EXCEPTION_STATE
:
1538 case EXCEPTION_STATE_IDENTITY
:
1541 return KERN_INVALID_ARGUMENT
;
1544 /* Cannot easily check "new_flavor", but that just means that
1545 * the flavor in the generated exception message might be garbage:
1549 if (task
->itk_self
== IP_NULL
) {
1551 return KERN_FAILURE
;
1556 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1557 if (exception_mask
& (1 << i
)) {
1558 for (j
= 0; j
< count
; j
++) {
1560 * search for an identical entry, if found
1561 * set corresponding mask for this exception.
1563 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1564 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1565 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1567 masks
[j
] |= (1 << i
);
1572 masks
[j
] = (1 << i
);
1574 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1575 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1576 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1579 old_port
[i
] = task
->exc_actions
[i
].port
;
1580 task
->exc_actions
[i
].port
=
1581 ipc_port_copy_send(new_port
);
1582 task
->exc_actions
[i
].behavior
= new_behavior
;
1583 task
->exc_actions
[i
].flavor
= new_flavor
;
1584 if (count
> *CountCnt
) {
1588 old_port
[i
] = IP_NULL
;
1593 * Consume send rights without any lock held.
1596 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1597 if (IP_VALID(old_port
[i
]))
1598 ipc_port_release_send(old_port
[i
]);
1599 if (IP_VALID(new_port
)) /* consume send right */
1600 ipc_port_release_send(new_port
);
1603 return KERN_SUCCESS
;
1604 }/* task_swap_exception_ports */
1607 * Routine: thread/task_get_exception_ports [kernel call]
1609 * Clones a send right for each of the thread/task's exception
1610 * ports specified in the mask and returns the behaviour
1611 * and flavor of said port.
1613 * Returns upto [in} CountCnt elements.
1618 * KERN_SUCCESS Extracted a send right.
1619 * KERN_INVALID_ARGUMENT The thread is null,
1620 * Invalid special port,
1621 * Illegal mask bit set.
1622 * KERN_FAILURE The thread is dead.
1626 thread_get_exception_ports(
1627 thread_act_t thr_act
,
1628 exception_mask_t exception_mask
,
1629 exception_mask_array_t masks
,
1630 mach_msg_type_number_t
* CountCnt
,
1631 exception_port_array_t ports
,
1632 exception_behavior_array_t behaviors
,
1633 thread_state_flavor_array_t flavors
)
1640 return KERN_INVALID_ARGUMENT
;
1642 if (exception_mask
& ~EXC_MASK_ALL
) {
1643 return KERN_INVALID_ARGUMENT
;
1647 if (!thr_act
->active
) {
1648 act_unlock(thr_act
);
1649 return KERN_FAILURE
;
1654 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1655 if (exception_mask
& (1 << i
)) {
1656 for (j
= 0; j
< count
; j
++) {
1658 * search for an identical entry, if found
1659 * set corresponding mask for this exception.
1661 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1662 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1663 && thr_act
->exc_actions
[i
].flavor
== flavors
[j
])
1665 masks
[j
] |= (1 << i
);
1670 masks
[j
] = (1 << i
);
1672 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1673 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1674 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1676 if (count
>= *CountCnt
) {
1683 act_unlock(thr_act
);
1686 return KERN_SUCCESS
;
1687 }/* thread_get_exception_ports */
1690 task_get_exception_ports(
1692 exception_mask_t exception_mask
,
1693 exception_mask_array_t masks
,
1694 mach_msg_type_number_t
* CountCnt
,
1695 exception_port_array_t ports
,
1696 exception_behavior_array_t behaviors
,
1697 thread_state_flavor_array_t flavors
)
1703 if (task
== TASK_NULL
)
1704 return KERN_INVALID_ARGUMENT
;
1706 if (exception_mask
& ~EXC_MASK_ALL
) {
1707 return KERN_INVALID_ARGUMENT
;
1711 if (task
->itk_self
== IP_NULL
) {
1713 return KERN_FAILURE
;
1718 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1719 if (exception_mask
& (1 << i
)) {
1720 for (j
= 0; j
< count
; j
++) {
1722 * search for an identical entry, if found
1723 * set corresponding mask for this exception.
1725 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1726 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1727 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1729 masks
[j
] |= (1 << i
);
1734 masks
[j
] = (1 << i
);
1736 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1737 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1738 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1740 if (count
> *CountCnt
) {
1750 return KERN_SUCCESS
;
1751 }/* task_get_exception_ports */