2 * Copyright (c) 2000 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
= task
->kernel_loaded
;
119 if (parent
== TASK_NULL
) {
120 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
121 task
->exc_actions
[i
].port
= IP_NULL
;
123 task
->itk_host
= ipc_port_make_send(realhost
.host_self
);
124 task
->itk_bootstrap
= IP_NULL
;
125 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
126 task
->itk_registered
[i
] = IP_NULL
;
129 assert(parent
->itk_self
!= IP_NULL
);
131 /* inherit registered ports */
133 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
134 task
->itk_registered
[i
] =
135 ipc_port_copy_send(parent
->itk_registered
[i
]);
137 /* inherit exception and bootstrap ports */
139 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
140 task
->exc_actions
[i
].port
=
141 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
142 task
->exc_actions
[i
].flavor
=
143 parent
->exc_actions
[i
].flavor
;
144 task
->exc_actions
[i
].behavior
=
145 parent
->exc_actions
[i
].behavior
;
148 ipc_port_copy_send(parent
->itk_host
);
150 task
->itk_bootstrap
=
151 ipc_port_copy_send(parent
->itk_bootstrap
);
158 * Routine: ipc_task_enable
160 * Enable a task for IPC access.
172 kport
= task
->itk_self
;
173 if (kport
!= IP_NULL
)
174 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
179 * Routine: ipc_task_disable
181 * Disable IPC access to a task.
193 kport
= task
->itk_self
;
194 if (kport
!= IP_NULL
)
195 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
200 * Routine: ipc_task_terminate
202 * Clean up and destroy a task's IPC state.
204 * Nothing locked. The task must be suspended.
205 * (Or the current thread must be in the task.)
216 kport
= task
->itk_self
;
218 if (kport
== IP_NULL
) {
219 /* the task is already terminated (can this happen?) */
224 task
->itk_self
= IP_NULL
;
227 /* release the naked send rights */
229 if (IP_VALID(task
->itk_sself
))
230 ipc_port_release_send(task
->itk_sself
);
232 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
233 if (IP_VALID(task
->exc_actions
[i
].port
)) {
234 ipc_port_release_send(task
->exc_actions
[i
].port
);
237 if (IP_VALID(task
->itk_host
))
238 ipc_port_release_send(task
->itk_host
);
240 if (IP_VALID(task
->itk_bootstrap
))
241 ipc_port_release_send(task
->itk_bootstrap
);
243 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
244 if (IP_VALID(task
->itk_registered
[i
]))
245 ipc_port_release_send(task
->itk_registered
[i
]);
247 ipc_port_release_send(task
->wired_ledger_port
);
248 ipc_port_release_send(task
->paged_ledger_port
);
250 /* destroy the kernel port */
251 ipc_port_dealloc_kernel(kport
);
255 * Routine: ipc_thread_init
257 * Initialize a thread's IPC state.
266 ipc_kmsg_queue_init(&thread
->ith_messages
);
267 thread
->ith_mig_reply
= MACH_PORT_NULL
;
268 thread
->ith_rpc_reply
= IP_NULL
;
272 * Routine: ipc_thread_terminate
274 * Clean up and destroy a thread's IPC state.
276 * Nothing locked. The thread must be suspended.
277 * (Or be the current thread.)
281 ipc_thread_terminate(
284 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
286 if (thread
->ith_rpc_reply
!= IP_NULL
)
287 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
288 thread
->ith_rpc_reply
= IP_NULL
;
292 * Routine: ipc_thr_act_init
294 * Initialize an thr_act's IPC state.
300 ipc_thr_act_init(task_t task
, thread_act_t thr_act
)
302 ipc_port_t kport
; int i
;
304 kport
= ipc_port_alloc_kernel();
305 if (kport
== IP_NULL
)
306 panic("ipc_thr_act_init");
308 thr_act
->ith_self
= kport
;
309 thr_act
->ith_sself
= ipc_port_make_send(kport
);
311 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
312 thr_act
->exc_actions
[i
].port
= IP_NULL
;
314 ipc_kobject_set(kport
, (ipc_kobject_t
) thr_act
, IKOT_ACT
);
318 ipc_thr_act_disable(thread_act_t thr_act
)
323 kport
= thr_act
->ith_self
;
325 if (kport
!= IP_NULL
)
326 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
330 ipc_thr_act_terminate(thread_act_t thr_act
)
332 ipc_port_t kport
; int i
;
334 kport
= thr_act
->ith_self
;
336 if (kport
== IP_NULL
) {
337 /* the thread is already terminated (can this happen?) */
341 thr_act
->ith_self
= IP_NULL
;
343 /* release the naked send rights */
345 if (IP_VALID(thr_act
->ith_sself
))
346 ipc_port_release_send(thr_act
->ith_sself
);
347 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
348 if (IP_VALID(thr_act
->exc_actions
[i
].port
))
349 ipc_port_release_send(thr_act
->exc_actions
[i
].port
);
352 /* destroy the kernel port */
353 ipc_port_dealloc_kernel(kport
);
357 * Routine: retrieve_task_self_fast
359 * Optimized version of retrieve_task_self,
360 * that only works for the current task.
362 * Return a send right (possibly null/dead)
363 * for the task's user-visible self port.
369 retrieve_task_self_fast(
370 register task_t task
)
372 register ipc_port_t port
;
374 assert(task
== current_task());
377 assert(task
->itk_self
!= IP_NULL
);
379 if ((port
= task
->itk_sself
) == task
->itk_self
) {
383 assert(ip_active(port
));
388 port
= ipc_port_copy_send(port
);
395 * Routine: retrieve_act_self_fast
397 * Optimized version of retrieve_thread_self,
398 * that only works for the current thread.
400 * Return a send right (possibly null/dead)
401 * for the thread's user-visible self port.
407 retrieve_act_self_fast(thread_act_t thr_act
)
409 register ipc_port_t port
;
411 assert(thr_act
== current_act());
413 assert(thr_act
->ith_self
!= IP_NULL
);
415 if ((port
= thr_act
->ith_sself
) == thr_act
->ith_self
) {
419 assert(ip_active(port
));
424 port
= ipc_port_copy_send(port
);
431 * Routine: task_self_trap [mach trap]
433 * Give the caller send rights for his own task port.
437 * MACH_PORT_NULL if there are any resource failures
444 task_t task
= current_task();
447 sright
= retrieve_task_self_fast(task
);
448 return ipc_port_copyout_send(sright
, task
->itk_space
);
452 * Routine: thread_self_trap [mach trap]
454 * Give the caller send rights for his own thread port.
458 * MACH_PORT_NULL if there are any resource failures
463 thread_self_trap(void)
465 thread_act_t thr_act
= current_act();
466 task_t task
= thr_act
->task
;
469 sright
= retrieve_act_self_fast(thr_act
);
470 return ipc_port_copyout_send(sright
, task
->itk_space
);
474 * Routine: mach_reply_port [mach trap]
476 * Allocate a port for the caller.
480 * MACH_PORT_NULL if there are any resource failures
485 mach_reply_port(void)
488 mach_port_name_t name
;
491 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
492 if (kr
== KERN_SUCCESS
)
495 name
= MACH_PORT_NULL
;
501 * Routine: task_get_special_port [kernel call]
503 * Clones a send right for one of the task's
508 * KERN_SUCCESS Extracted a send right.
509 * KERN_INVALID_ARGUMENT The task is null.
510 * KERN_FAILURE The task/space is dead.
511 * KERN_INVALID_ARGUMENT Invalid special port.
515 task_get_special_port(
523 if (task
== TASK_NULL
)
524 return KERN_INVALID_ARGUMENT
;
527 case TASK_KERNEL_PORT
:
528 whichp
= &task
->itk_sself
;
532 whichp
= &task
->itk_host
;
535 case TASK_BOOTSTRAP_PORT
:
536 whichp
= &task
->itk_bootstrap
;
539 case TASK_WIRED_LEDGER_PORT
:
540 whichp
= &task
->wired_ledger_port
;
543 case TASK_PAGED_LEDGER_PORT
:
544 whichp
= &task
->paged_ledger_port
;
548 return KERN_INVALID_ARGUMENT
;
552 if (task
->itk_self
== IP_NULL
) {
557 port
= ipc_port_copy_send(*whichp
);
565 * Routine: task_set_special_port [kernel call]
567 * Changes one of the task's special ports,
568 * setting it to the supplied send right.
570 * Nothing locked. If successful, consumes
571 * the supplied send right.
573 * KERN_SUCCESS Changed the special port.
574 * KERN_INVALID_ARGUMENT The task is null.
575 * KERN_FAILURE The task/space is dead.
576 * KERN_INVALID_ARGUMENT Invalid special port.
580 task_set_special_port(
588 if (task
== TASK_NULL
)
589 return KERN_INVALID_ARGUMENT
;
592 case TASK_KERNEL_PORT
:
593 whichp
= &task
->itk_sself
;
597 whichp
= &task
->itk_host
;
600 case TASK_BOOTSTRAP_PORT
:
601 whichp
= &task
->itk_bootstrap
;
604 case TASK_WIRED_LEDGER_PORT
:
605 whichp
= &task
->wired_ledger_port
;
608 case TASK_PAGED_LEDGER_PORT
:
609 whichp
= &task
->paged_ledger_port
;
613 return KERN_INVALID_ARGUMENT
;
617 if (task
->itk_self
== IP_NULL
) {
627 ipc_port_release_send(old
);
633 * Routine: mach_ports_register [kernel call]
635 * Stash a handful of port send rights in the task.
636 * Child tasks will inherit these rights, but they
637 * must use mach_ports_lookup to acquire them.
639 * The rights are supplied in a (wired) kalloc'd segment.
640 * Rights which aren't supplied are assumed to be null.
642 * Nothing locked. If successful, consumes
643 * the supplied rights and memory.
645 * KERN_SUCCESS Stashed the port rights.
646 * KERN_INVALID_ARGUMENT The task is null.
647 * KERN_INVALID_ARGUMENT The task is dead.
648 * KERN_INVALID_ARGUMENT Too many port rights supplied.
654 mach_port_array_t memory
,
655 mach_msg_type_number_t portsCnt
)
657 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
660 if ((task
== TASK_NULL
) ||
661 (portsCnt
> TASK_PORT_REGISTER_MAX
))
662 return KERN_INVALID_ARGUMENT
;
665 * Pad the port rights with nulls.
668 for (i
= 0; i
< portsCnt
; i
++)
669 ports
[i
] = memory
[i
];
670 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
674 if (task
->itk_self
== IP_NULL
) {
676 return KERN_INVALID_ARGUMENT
;
680 * Replace the old send rights with the new.
681 * Release the old rights after unlocking.
684 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
687 old
= task
->itk_registered
[i
];
688 task
->itk_registered
[i
] = ports
[i
];
694 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
695 if (IP_VALID(ports
[i
]))
696 ipc_port_release_send(ports
[i
]);
699 * Now that the operation is known to be successful,
700 * we can free the memory.
704 kfree((vm_offset_t
) memory
,
705 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
711 * Routine: mach_ports_lookup [kernel call]
713 * Retrieves (clones) the stashed port send rights.
715 * Nothing locked. If successful, the caller gets
718 * KERN_SUCCESS Retrieved the send rights.
719 * KERN_INVALID_ARGUMENT The task is null.
720 * KERN_INVALID_ARGUMENT The task is dead.
721 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
727 mach_port_array_t
*portsp
,
728 mach_msg_type_number_t
*portsCnt
)
737 if (task
== TASK_NULL
)
738 return KERN_INVALID_ARGUMENT
;
740 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
742 memory
= kalloc(size
);
744 return KERN_RESOURCE_SHORTAGE
;
747 if (task
->itk_self
== IP_NULL
) {
751 return KERN_INVALID_ARGUMENT
;
754 ports
= (ipc_port_t
*) memory
;
757 * Clone port rights. Because kalloc'd memory
758 * is wired, we won't fault while holding the task lock.
761 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
762 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
766 *portsp
= (mach_port_array_t
) ports
;
767 *portsCnt
= TASK_PORT_REGISTER_MAX
;
772 * Routine: convert_port_to_locked_task
774 * Internal helper routine to convert from a port to a locked
775 * task. Used by several routines that try to convert from a
776 * task port to a reference on some task related object.
778 * Nothing locked, blocking OK.
781 convert_port_to_locked_task(ipc_port_t port
)
783 while (IP_VALID(port
)) {
787 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
791 task
= (task_t
) port
->ip_kobject
;
792 assert(task
!= TASK_NULL
);
795 * Normal lock ordering puts task_lock() before ip_lock().
796 * Attempt out-of-order locking here.
798 if (task_lock_try(task
)) {
810 * Routine: convert_port_to_task
812 * Convert from a port to a task.
813 * Doesn't consume the port ref; produces a task ref,
819 convert_port_to_task(
824 task
= convert_port_to_locked_task(port
);
833 * Routine: convert_port_to_space
835 * Convert from a port to a space.
836 * Doesn't consume the port ref; produces a space ref,
842 convert_port_to_space(
848 task
= convert_port_to_locked_task(port
);
850 if (task
== TASK_NULL
)
851 return IPC_SPACE_NULL
;
855 return IPC_SPACE_NULL
;
858 space
= task
->itk_space
;
871 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_UPL
)) {
875 upl
= (upl_t
) port
->ip_kobject
;
887 return MACH_PORT_NULL
;
890 __private_extern__
void
893 mach_port_mscount_t mscount
)
899 * Routine: convert_port_entry_to_map
901 * Convert from a port specifying an entry or a task
902 * to a map. Doesn't consume the port ref; produces a map ref,
903 * which may be null. Unlike convert_port_to_map, the
904 * port may be task or a named entry backed.
911 convert_port_entry_to_map(
916 vm_named_entry_t named_entry
;
918 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
921 if(ip_active(port
) && (ip_kotype(port
)
922 == IKOT_NAMED_ENTRY
)) {
924 (vm_named_entry_t
)port
->ip_kobject
;
925 if (!(mutex_try(&(named_entry
)->Lock
))) {
930 named_entry
->ref_count
++;
931 mutex_unlock(&(named_entry
)->Lock
);
933 if ((named_entry
->is_sub_map
) &&
934 (named_entry
->protection
936 map
= named_entry
->backing
.map
;
938 mach_destroy_memory_entry(port
);
941 vm_map_reference_swap(map
);
942 mach_destroy_memory_entry(port
);
951 task
= convert_port_to_locked_task(port
);
953 if (task
== TASK_NULL
)
962 vm_map_reference_swap(map
);
970 * Routine: convert_port_entry_to_object
972 * Convert from a port specifying a named entry to an
973 * object. Doesn't consume the port ref; produces a map ref,
981 convert_port_entry_to_object(
985 vm_named_entry_t named_entry
;
987 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
990 if(ip_active(port
) && (ip_kotype(port
)
991 == IKOT_NAMED_ENTRY
)) {
993 (vm_named_entry_t
)port
->ip_kobject
;
994 if (!(mutex_try(&(named_entry
)->Lock
))) {
999 named_entry
->ref_count
++;
1000 mutex_unlock(&(named_entry
)->Lock
);
1002 if ((!named_entry
->is_sub_map
) &&
1003 (named_entry
->protection
1005 object
= named_entry
->object
;
1007 mach_destroy_memory_entry(port
);
1008 return (vm_object_t
)NULL
;
1010 vm_object_reference(named_entry
->object
);
1011 mach_destroy_memory_entry(port
);
1015 return (vm_object_t
)NULL
;
1018 return (vm_object_t
)NULL
;
1025 * Routine: convert_port_to_map
1027 * Convert from a port to a map.
1028 * Doesn't consume the port ref; produces a map ref,
1029 * which may be null.
1035 convert_port_to_map(
1041 task
= convert_port_to_locked_task(port
);
1043 if (task
== TASK_NULL
)
1046 if (!task
->active
) {
1052 vm_map_reference_swap(map
);
1059 * Routine: convert_port_to_act
1061 * Convert from a port to a thr_act.
1062 * Doesn't consume the port ref; produces an thr_act ref,
1063 * which may be null.
1069 convert_port_to_act( ipc_port_t port
)
1072 thread_act_t thr_act
= 0;
1075 while (!r
&& IP_VALID(port
)) {
1077 r
= ref_act_port_locked(port
, &thr_act
);
1084 ref_act_port_locked( ipc_port_t port
, thread_act_t
*pthr_act
)
1086 thread_act_t thr_act
;
1089 if (ip_active(port
) &&
1090 (ip_kotype(port
) == IKOT_ACT
)) {
1091 thr_act
= (thread_act_t
) port
->ip_kobject
;
1092 assert(thr_act
!= THR_ACT_NULL
);
1095 * Normal lock ordering is act_lock(), then ip_lock().
1096 * Allow out-of-order locking here, using
1097 * act_reference_act_locked() to accomodate it.
1099 if (!act_lock_try(thr_act
)) {
1104 act_locked_act_reference(thr_act
);
1105 act_unlock(thr_act
);
1107 *pthr_act
= thr_act
;
1113 * Routine: port_name_to_act
1115 * Convert from a port name to an act reference
1116 * A name of MACH_PORT_NULL is valid for the null act
1122 mach_port_name_t name
)
1124 thread_act_t thr_act
= THR_ACT_NULL
;
1125 ipc_port_t kern_port
;
1128 if (MACH_PORT_VALID(name
)) {
1129 kr
= ipc_object_copyin(current_space(), name
,
1130 MACH_MSG_TYPE_COPY_SEND
,
1131 (ipc_object_t
*) &kern_port
);
1132 if (kr
!= KERN_SUCCESS
)
1133 return THR_ACT_NULL
;
1135 thr_act
= convert_port_to_act(kern_port
);
1137 if (IP_VALID(kern_port
))
1138 ipc_port_release_send(kern_port
);
1145 mach_port_name_t name
)
1147 ipc_port_t kern_port
;
1149 task_t task
= TASK_NULL
;
1151 if (MACH_PORT_VALID(name
)) {
1152 kr
= ipc_object_copyin(current_space(), name
,
1153 MACH_MSG_TYPE_COPY_SEND
,
1154 (ipc_object_t
*) &kern_port
);
1155 if (kr
!= KERN_SUCCESS
)
1158 task
= convert_port_to_task(kern_port
);
1160 if (IP_VALID(kern_port
))
1161 ipc_port_release_send(kern_port
);
1167 * Routine: convert_task_to_port
1169 * Convert from a task to a port.
1170 * Consumes a task ref; produces a naked send right
1171 * which may be invalid.
1177 convert_task_to_port(
1183 if (task
->itk_self
!= IP_NULL
)
1185 if (task
->map
== VM_MAP_NULL
)
1186 /* norma placeholder task */
1187 port
= ipc_port_copy_send(task
->itk_self
);
1189 #endif /* NORMA_TASK */
1190 port
= ipc_port_make_send(task
->itk_self
);
1195 task_deallocate(task
);
1200 * Routine: convert_act_to_port
1202 * Convert from a thr_act to a port.
1203 * Consumes an thr_act ref; produces a naked send right
1204 * which may be invalid.
1210 convert_act_to_port(thr_act
)
1211 thread_act_t thr_act
;
1216 if (thr_act
->ith_self
!= IP_NULL
)
1217 port
= ipc_port_make_send(thr_act
->ith_self
);
1220 act_unlock(thr_act
);
1222 act_deallocate(thr_act
);
1227 * Routine: space_deallocate
1229 * Deallocate a space ref produced by convert_port_to_space.
1238 if (space
!= IS_NULL
)
1243 * Routine: thread/task_set_exception_ports [kernel call]
1245 * Sets the thread/task exception port, flavor and
1246 * behavior for the exception types specified by the mask.
1247 * There will be one send right per exception per valid
1250 * Nothing locked. If successful, consumes
1251 * the supplied send right.
1253 * KERN_SUCCESS Changed the special port.
1254 * KERN_INVALID_ARGUMENT The thread is null,
1255 * Illegal mask bit set.
1256 * Illegal exception behavior
1257 * KERN_FAILURE The thread is dead.
1261 thread_set_exception_ports(
1262 thread_act_t thr_act
,
1263 exception_mask_t exception_mask
,
1264 ipc_port_t new_port
,
1265 exception_behavior_t new_behavior
,
1266 thread_state_flavor_t new_flavor
)
1269 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1272 return KERN_INVALID_ARGUMENT
;
1274 if (exception_mask
& ~EXC_MASK_ALL
)
1275 return KERN_INVALID_ARGUMENT
;
1277 if (IP_VALID(new_port
)) {
1278 switch (new_behavior
) {
1279 case EXCEPTION_DEFAULT
:
1280 case EXCEPTION_STATE
:
1281 case EXCEPTION_STATE_IDENTITY
:
1284 return KERN_INVALID_ARGUMENT
;
1289 * Check the validity of the thread_state_flavor by calling the
1290 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1291 * osfmk/mach/ARCHITECTURE/thread_status.h
1293 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
1294 return KERN_INVALID_ARGUMENT
;
1298 if (!thr_act
->active
) {
1299 act_unlock(thr_act
);
1300 return KERN_FAILURE
;
1303 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1304 if (exception_mask
& (1 << i
)) {
1305 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1306 thr_act
->exc_actions
[i
].port
=
1307 ipc_port_copy_send(new_port
);
1308 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1309 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1311 old_port
[i
] = IP_NULL
;
1314 * Consume send rights without any lock held.
1316 act_unlock(thr_act
);
1317 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1318 if (IP_VALID(old_port
[i
]))
1319 ipc_port_release_send(old_port
[i
]);
1320 if (IP_VALID(new_port
)) /* consume send right */
1321 ipc_port_release_send(new_port
);
1323 return KERN_SUCCESS
;
1324 }/* thread_set_exception_port */
1327 task_set_exception_ports(
1329 exception_mask_t exception_mask
,
1330 ipc_port_t new_port
,
1331 exception_behavior_t new_behavior
,
1332 thread_state_flavor_t new_flavor
)
1335 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1337 if (task
== TASK_NULL
) {
1338 return KERN_INVALID_ARGUMENT
;
1341 if (exception_mask
& ~EXC_MASK_ALL
) {
1342 return KERN_INVALID_ARGUMENT
;
1345 if (IP_VALID(new_port
)) {
1346 switch (new_behavior
) {
1347 case EXCEPTION_DEFAULT
:
1348 case EXCEPTION_STATE
:
1349 case EXCEPTION_STATE_IDENTITY
:
1352 return KERN_INVALID_ARGUMENT
;
1355 /* Cannot easily check "new_flavor", but that just means that
1356 * the flavor in the generated exception message might be garbage:
1360 if (task
->itk_self
== IP_NULL
) {
1362 return KERN_FAILURE
;
1365 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1366 if (exception_mask
& (1 << i
)) {
1367 old_port
[i
] = task
->exc_actions
[i
].port
;
1368 task
->exc_actions
[i
].port
=
1369 ipc_port_copy_send(new_port
);
1370 task
->exc_actions
[i
].behavior
= new_behavior
;
1371 task
->exc_actions
[i
].flavor
= new_flavor
;
1373 old_port
[i
] = IP_NULL
;
1377 * Consume send rights without any lock held.
1380 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1381 if (IP_VALID(old_port
[i
]))
1382 ipc_port_release_send(old_port
[i
]);
1383 if (IP_VALID(new_port
)) /* consume send right */
1384 ipc_port_release_send(new_port
);
1386 return KERN_SUCCESS
;
1387 }/* task_set_exception_port */
1390 * Routine: thread/task_swap_exception_ports [kernel call]
1392 * Sets the thread/task exception port, flavor and
1393 * behavior for the exception types specified by the
1396 * The old ports, behavior and flavors are returned
1397 * Count specifies the array sizes on input and
1398 * the number of returned ports etc. on output. The
1399 * arrays must be large enough to hold all the returned
1400 * data, MIG returnes an error otherwise. The masks
1401 * array specifies the corresponding exception type(s).
1404 * Nothing locked. If successful, consumes
1405 * the supplied send right.
1407 * Returns upto [in} CountCnt elements.
1409 * KERN_SUCCESS Changed the special port.
1410 * KERN_INVALID_ARGUMENT The thread is null,
1411 * Illegal mask bit set.
1412 * Illegal exception behavior
1413 * KERN_FAILURE The thread is dead.
1417 thread_swap_exception_ports(
1418 thread_act_t thr_act
,
1419 exception_mask_t exception_mask
,
1420 ipc_port_t new_port
,
1421 exception_behavior_t new_behavior
,
1422 thread_state_flavor_t new_flavor
,
1423 exception_mask_array_t masks
,
1424 mach_msg_type_number_t
* CountCnt
,
1425 exception_port_array_t ports
,
1426 exception_behavior_array_t behaviors
,
1427 thread_state_flavor_array_t flavors
)
1432 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1435 return KERN_INVALID_ARGUMENT
;
1437 if (exception_mask
& ~EXC_MASK_ALL
) {
1438 return KERN_INVALID_ARGUMENT
;
1441 if (IP_VALID(new_port
)) {
1442 switch (new_behavior
) {
1443 case EXCEPTION_DEFAULT
:
1444 case EXCEPTION_STATE
:
1445 case EXCEPTION_STATE_IDENTITY
:
1448 return KERN_INVALID_ARGUMENT
;
1451 /* Cannot easily check "new_flavor", but that just means that
1452 * the flavor in the generated exception message might be garbage:
1456 if (!thr_act
->active
) {
1457 act_unlock(thr_act
);
1458 return KERN_FAILURE
;
1463 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1464 if (exception_mask
& (1 << i
)) {
1465 for (j
= 0; j
< count
; j
++) {
1467 * search for an identical entry, if found
1468 * set corresponding mask for this exception.
1470 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1471 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1472 && thr_act
->exc_actions
[i
].flavor
==flavors
[j
])
1474 masks
[j
] |= (1 << i
);
1479 masks
[j
] = (1 << i
);
1481 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1483 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1484 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1488 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1489 thr_act
->exc_actions
[i
].port
=
1490 ipc_port_copy_send(new_port
);
1491 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1492 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1493 if (count
> *CountCnt
) {
1497 old_port
[i
] = IP_NULL
;
1501 * Consume send rights without any lock held.
1503 act_unlock(thr_act
);
1504 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1505 if (IP_VALID(old_port
[i
]))
1506 ipc_port_release_send(old_port
[i
]);
1507 if (IP_VALID(new_port
)) /* consume send right */
1508 ipc_port_release_send(new_port
);
1510 return KERN_SUCCESS
;
1511 }/* thread_swap_exception_ports */
1514 task_swap_exception_ports(
1516 exception_mask_t exception_mask
,
1517 ipc_port_t new_port
,
1518 exception_behavior_t new_behavior
,
1519 thread_state_flavor_t new_flavor
,
1520 exception_mask_array_t masks
,
1521 mach_msg_type_number_t
* CountCnt
,
1522 exception_port_array_t ports
,
1523 exception_behavior_array_t behaviors
,
1524 thread_state_flavor_array_t flavors
)
1529 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1531 if (task
== TASK_NULL
)
1532 return KERN_INVALID_ARGUMENT
;
1534 if (exception_mask
& ~EXC_MASK_ALL
) {
1535 return KERN_INVALID_ARGUMENT
;
1538 if (IP_VALID(new_port
)) {
1539 switch (new_behavior
) {
1540 case EXCEPTION_DEFAULT
:
1541 case EXCEPTION_STATE
:
1542 case EXCEPTION_STATE_IDENTITY
:
1545 return KERN_INVALID_ARGUMENT
;
1548 /* Cannot easily check "new_flavor", but that just means that
1549 * the flavor in the generated exception message might be garbage:
1553 if (task
->itk_self
== IP_NULL
) {
1555 return KERN_FAILURE
;
1560 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1561 if (exception_mask
& (1 << i
)) {
1562 for (j
= 0; j
< count
; j
++) {
1564 * search for an identical entry, if found
1565 * set corresponding mask for this exception.
1567 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1568 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1569 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1571 masks
[j
] |= (1 << i
);
1576 masks
[j
] = (1 << i
);
1578 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1579 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1580 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1583 old_port
[i
] = task
->exc_actions
[i
].port
;
1584 task
->exc_actions
[i
].port
=
1585 ipc_port_copy_send(new_port
);
1586 task
->exc_actions
[i
].behavior
= new_behavior
;
1587 task
->exc_actions
[i
].flavor
= new_flavor
;
1588 if (count
> *CountCnt
) {
1592 old_port
[i
] = IP_NULL
;
1597 * Consume send rights without any lock held.
1600 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1601 if (IP_VALID(old_port
[i
]))
1602 ipc_port_release_send(old_port
[i
]);
1603 if (IP_VALID(new_port
)) /* consume send right */
1604 ipc_port_release_send(new_port
);
1607 return KERN_SUCCESS
;
1608 }/* task_swap_exception_ports */
1611 * Routine: thread/task_get_exception_ports [kernel call]
1613 * Clones a send right for each of the thread/task's exception
1614 * ports specified in the mask and returns the behaviour
1615 * and flavor of said port.
1617 * Returns upto [in} CountCnt elements.
1622 * KERN_SUCCESS Extracted a send right.
1623 * KERN_INVALID_ARGUMENT The thread is null,
1624 * Invalid special port,
1625 * Illegal mask bit set.
1626 * KERN_FAILURE The thread is dead.
1630 thread_get_exception_ports(
1631 thread_act_t thr_act
,
1632 exception_mask_t exception_mask
,
1633 exception_mask_array_t masks
,
1634 mach_msg_type_number_t
* CountCnt
,
1635 exception_port_array_t ports
,
1636 exception_behavior_array_t behaviors
,
1637 thread_state_flavor_array_t flavors
)
1644 return KERN_INVALID_ARGUMENT
;
1646 if (exception_mask
& ~EXC_MASK_ALL
) {
1647 return KERN_INVALID_ARGUMENT
;
1651 if (!thr_act
->active
) {
1652 act_unlock(thr_act
);
1653 return KERN_FAILURE
;
1658 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1659 if (exception_mask
& (1 << i
)) {
1660 for (j
= 0; j
< count
; j
++) {
1662 * search for an identical entry, if found
1663 * set corresponding mask for this exception.
1665 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1666 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1667 && thr_act
->exc_actions
[i
].flavor
== flavors
[j
])
1669 masks
[j
] |= (1 << i
);
1674 masks
[j
] = (1 << i
);
1676 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1677 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1678 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1680 if (count
>= *CountCnt
) {
1687 act_unlock(thr_act
);
1690 return KERN_SUCCESS
;
1691 }/* thread_get_exception_ports */
1694 task_get_exception_ports(
1696 exception_mask_t exception_mask
,
1697 exception_mask_array_t masks
,
1698 mach_msg_type_number_t
* CountCnt
,
1699 exception_port_array_t ports
,
1700 exception_behavior_array_t behaviors
,
1701 thread_state_flavor_array_t flavors
)
1707 if (task
== TASK_NULL
)
1708 return KERN_INVALID_ARGUMENT
;
1710 if (exception_mask
& ~EXC_MASK_ALL
) {
1711 return KERN_INVALID_ARGUMENT
;
1715 if (task
->itk_self
== IP_NULL
) {
1717 return KERN_FAILURE
;
1722 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1723 if (exception_mask
& (1 << i
)) {
1724 for (j
= 0; j
< count
; j
++) {
1726 * search for an identical entry, if found
1727 * set corresponding mask for this exception.
1729 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1730 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1731 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1733 masks
[j
] |= (1 << i
);
1738 masks
[j
] = (1 << i
);
1740 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1741 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1742 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1744 if (count
> *CountCnt
) {
1754 return KERN_SUCCESS
;
1755 }/* task_get_exception_ports */