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
->exc_actions
[EXC_MACH_SYSCALL
].port
=
120 ipc_port_make_send(realhost
.host_self
);
121 task
->itk_host
= ipc_port_make_send(realhost
.host_self
);
122 task
->itk_bootstrap
= IP_NULL
;
123 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
124 task
->itk_registered
[i
] = IP_NULL
;
127 assert(parent
->itk_self
!= IP_NULL
);
129 /* inherit registered ports */
131 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
132 task
->itk_registered
[i
] =
133 ipc_port_copy_send(parent
->itk_registered
[i
]);
135 /* inherit exception and bootstrap ports */
137 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
138 task
->exc_actions
[i
].port
=
139 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
140 task
->exc_actions
[i
].flavor
=
141 parent
->exc_actions
[i
].flavor
;
142 task
->exc_actions
[i
].behavior
=
143 parent
->exc_actions
[i
].behavior
;
146 ipc_port_copy_send(parent
->itk_host
);
148 task
->itk_bootstrap
=
149 ipc_port_copy_send(parent
->itk_bootstrap
);
156 * Routine: ipc_task_enable
158 * Enable a task for IPC access.
170 kport
= task
->itk_self
;
171 if (kport
!= IP_NULL
)
172 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
177 * Routine: ipc_task_disable
179 * Disable IPC access to a task.
191 kport
= task
->itk_self
;
192 if (kport
!= IP_NULL
)
193 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
198 * Routine: ipc_task_terminate
200 * Clean up and destroy a task's IPC state.
202 * Nothing locked. The task must be suspended.
203 * (Or the current thread must be in the task.)
214 kport
= task
->itk_self
;
216 if (kport
== IP_NULL
) {
217 /* the task is already terminated (can this happen?) */
222 task
->itk_self
= IP_NULL
;
225 /* release the naked send rights */
227 if (IP_VALID(task
->itk_sself
))
228 ipc_port_release_send(task
->itk_sself
);
230 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
231 if (IP_VALID(task
->exc_actions
[i
].port
)) {
232 ipc_port_release_send(task
->exc_actions
[i
].port
);
235 if (IP_VALID(task
->itk_host
))
236 ipc_port_release_send(task
->itk_host
);
238 if (IP_VALID(task
->itk_bootstrap
))
239 ipc_port_release_send(task
->itk_bootstrap
);
241 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
242 if (IP_VALID(task
->itk_registered
[i
]))
243 ipc_port_release_send(task
->itk_registered
[i
]);
245 ipc_port_release_send(task
->wired_ledger_port
);
246 ipc_port_release_send(task
->paged_ledger_port
);
248 /* destroy the kernel port */
249 ipc_port_dealloc_kernel(kport
);
253 * Routine: ipc_thread_init
255 * Initialize a thread's IPC state.
264 ipc_kmsg_queue_init(&thread
->ith_messages
);
265 thread
->ith_mig_reply
= MACH_PORT_NULL
;
266 thread
->ith_rpc_reply
= IP_NULL
;
270 * Routine: ipc_thread_terminate
272 * Clean up and destroy a thread's IPC state.
274 * Nothing locked. The thread must be suspended.
275 * (Or be the current thread.)
279 ipc_thread_terminate(
282 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
284 if (thread
->ith_rpc_reply
!= IP_NULL
)
285 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
286 thread
->ith_rpc_reply
= IP_NULL
;
290 * Routine: ipc_thr_act_init
292 * Initialize an thr_act's IPC state.
298 ipc_thr_act_init(task_t task
, thread_act_t thr_act
)
300 ipc_port_t kport
; int i
;
302 kport
= ipc_port_alloc_kernel();
303 if (kport
== IP_NULL
)
304 panic("ipc_thr_act_init");
306 thr_act
->ith_self
= kport
;
307 thr_act
->ith_sself
= ipc_port_make_send(kport
);
309 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
310 thr_act
->exc_actions
[i
].port
= IP_NULL
;
312 thr_act
->exc_actions
[EXC_MACH_SYSCALL
].port
=
313 ipc_port_make_send(realhost
.host_self
);
315 ipc_kobject_set(kport
, (ipc_kobject_t
) thr_act
, IKOT_ACT
);
319 ipc_thr_act_disable(thread_act_t thr_act
)
324 kport
= thr_act
->ith_self
;
326 if (kport
!= IP_NULL
)
327 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
331 ipc_thr_act_terminate(thread_act_t thr_act
)
333 ipc_port_t kport
; int i
;
335 kport
= thr_act
->ith_self
;
337 if (kport
== IP_NULL
) {
338 /* the thread is already terminated (can this happen?) */
342 thr_act
->ith_self
= IP_NULL
;
344 /* release the naked send rights */
346 if (IP_VALID(thr_act
->ith_sself
))
347 ipc_port_release_send(thr_act
->ith_sself
);
348 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
349 if (IP_VALID(thr_act
->exc_actions
[i
].port
))
350 ipc_port_release_send(thr_act
->exc_actions
[i
].port
);
353 /* destroy the kernel port */
354 ipc_port_dealloc_kernel(kport
);
358 * Routine: retrieve_task_self_fast
360 * Optimized version of retrieve_task_self,
361 * that only works for the current task.
363 * Return a send right (possibly null/dead)
364 * for the task's user-visible self port.
370 retrieve_task_self_fast(
371 register task_t task
)
373 register ipc_port_t port
;
375 assert(task
== current_task());
378 assert(task
->itk_self
!= IP_NULL
);
380 if ((port
= task
->itk_sself
) == task
->itk_self
) {
384 assert(ip_active(port
));
389 port
= ipc_port_copy_send(port
);
396 * Routine: retrieve_act_self_fast
398 * Optimized version of retrieve_thread_self,
399 * that only works for the current thread.
401 * Return a send right (possibly null/dead)
402 * for the thread's user-visible self port.
408 retrieve_act_self_fast(thread_act_t thr_act
)
410 register ipc_port_t port
;
412 assert(thr_act
== current_act());
414 assert(thr_act
->ith_self
!= IP_NULL
);
416 if ((port
= thr_act
->ith_sself
) == thr_act
->ith_self
) {
420 assert(ip_active(port
));
425 port
= ipc_port_copy_send(port
);
432 * Routine: task_self_trap [mach trap]
434 * Give the caller send rights for his own task port.
438 * MACH_PORT_NULL if there are any resource failures
445 task_t task
= current_task();
448 sright
= retrieve_task_self_fast(task
);
449 return ipc_port_copyout_send(sright
, task
->itk_space
);
453 * Routine: thread_self_trap [mach trap]
455 * Give the caller send rights for his own thread port.
459 * MACH_PORT_NULL if there are any resource failures
464 thread_self_trap(void)
466 thread_act_t thr_act
= current_act();
467 task_t task
= thr_act
->task
;
470 sright
= retrieve_act_self_fast(thr_act
);
471 return ipc_port_copyout_send(sright
, task
->itk_space
);
475 * Routine: mach_reply_port [mach trap]
477 * Allocate a port for the caller.
481 * MACH_PORT_NULL if there are any resource failures
486 mach_reply_port(void)
489 mach_port_name_t name
;
492 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
493 if (kr
== KERN_SUCCESS
)
496 name
= MACH_PORT_NULL
;
502 * Routine: task_get_special_port [kernel call]
504 * Clones a send right for one of the task's
509 * KERN_SUCCESS Extracted a send right.
510 * KERN_INVALID_ARGUMENT The task is null.
511 * KERN_FAILURE The task/space is dead.
512 * KERN_INVALID_ARGUMENT Invalid special port.
516 task_get_special_port(
524 if (task
== TASK_NULL
)
525 return KERN_INVALID_ARGUMENT
;
528 case TASK_KERNEL_PORT
:
529 whichp
= &task
->itk_sself
;
533 whichp
= &task
->itk_host
;
536 case TASK_BOOTSTRAP_PORT
:
537 whichp
= &task
->itk_bootstrap
;
540 case TASK_WIRED_LEDGER_PORT
:
541 whichp
= &task
->wired_ledger_port
;
544 case TASK_PAGED_LEDGER_PORT
:
545 whichp
= &task
->paged_ledger_port
;
549 return KERN_INVALID_ARGUMENT
;
553 if (task
->itk_self
== IP_NULL
) {
558 port
= ipc_port_copy_send(*whichp
);
566 * Routine: task_set_special_port [kernel call]
568 * Changes one of the task's special ports,
569 * setting it to the supplied send right.
571 * Nothing locked. If successful, consumes
572 * the supplied send right.
574 * KERN_SUCCESS Changed the special port.
575 * KERN_INVALID_ARGUMENT The task is null.
576 * KERN_FAILURE The task/space is dead.
577 * KERN_INVALID_ARGUMENT Invalid special port.
581 task_set_special_port(
589 if (task
== TASK_NULL
)
590 return KERN_INVALID_ARGUMENT
;
593 case TASK_KERNEL_PORT
:
594 whichp
= &task
->itk_sself
;
598 whichp
= &task
->itk_host
;
601 case TASK_BOOTSTRAP_PORT
:
602 whichp
= &task
->itk_bootstrap
;
605 case TASK_WIRED_LEDGER_PORT
:
606 whichp
= &task
->wired_ledger_port
;
609 case TASK_PAGED_LEDGER_PORT
:
610 whichp
= &task
->paged_ledger_port
;
614 return KERN_INVALID_ARGUMENT
;
618 if (task
->itk_self
== IP_NULL
) {
628 ipc_port_release_send(old
);
634 * Routine: mach_ports_register [kernel call]
636 * Stash a handful of port send rights in the task.
637 * Child tasks will inherit these rights, but they
638 * must use mach_ports_lookup to acquire them.
640 * The rights are supplied in a (wired) kalloc'd segment.
641 * Rights which aren't supplied are assumed to be null.
643 * Nothing locked. If successful, consumes
644 * the supplied rights and memory.
646 * KERN_SUCCESS Stashed the port rights.
647 * KERN_INVALID_ARGUMENT The task is null.
648 * KERN_INVALID_ARGUMENT The task is dead.
649 * KERN_INVALID_ARGUMENT Too many port rights supplied.
655 mach_port_array_t memory
,
656 mach_msg_type_number_t portsCnt
)
658 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
661 if ((task
== TASK_NULL
) ||
662 (portsCnt
> TASK_PORT_REGISTER_MAX
))
663 return KERN_INVALID_ARGUMENT
;
666 * Pad the port rights with nulls.
669 for (i
= 0; i
< portsCnt
; i
++)
670 ports
[i
] = memory
[i
];
671 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
675 if (task
->itk_self
== IP_NULL
) {
677 return KERN_INVALID_ARGUMENT
;
681 * Replace the old send rights with the new.
682 * Release the old rights after unlocking.
685 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
688 old
= task
->itk_registered
[i
];
689 task
->itk_registered
[i
] = ports
[i
];
695 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
696 if (IP_VALID(ports
[i
]))
697 ipc_port_release_send(ports
[i
]);
700 * Now that the operation is known to be successful,
701 * we can free the memory.
705 kfree((vm_offset_t
) memory
,
706 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
712 * Routine: mach_ports_lookup [kernel call]
714 * Retrieves (clones) the stashed port send rights.
716 * Nothing locked. If successful, the caller gets
719 * KERN_SUCCESS Retrieved the send rights.
720 * KERN_INVALID_ARGUMENT The task is null.
721 * KERN_INVALID_ARGUMENT The task is dead.
722 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
728 mach_port_array_t
*portsp
,
729 mach_msg_type_number_t
*portsCnt
)
738 if (task
== TASK_NULL
)
739 return KERN_INVALID_ARGUMENT
;
741 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
743 memory
= kalloc(size
);
745 return KERN_RESOURCE_SHORTAGE
;
748 if (task
->itk_self
== IP_NULL
) {
752 return KERN_INVALID_ARGUMENT
;
755 ports
= (ipc_port_t
*) memory
;
758 * Clone port rights. Because kalloc'd memory
759 * is wired, we won't fault while holding the task lock.
762 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
763 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
767 *portsp
= (mach_port_array_t
) ports
;
768 *portsCnt
= TASK_PORT_REGISTER_MAX
;
773 * Routine: convert_port_to_locked_task
775 * Internal helper routine to convert from a port to a locked
776 * task. Used by several routines that try to convert from a
777 * task port to a reference on some task related object.
779 * Nothing locked, blocking OK.
782 convert_port_to_locked_task(ipc_port_t port
)
784 while (IP_VALID(port
)) {
788 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
792 task
= (task_t
) port
->ip_kobject
;
793 assert(task
!= TASK_NULL
);
796 * Normal lock ordering puts task_lock() before ip_lock().
797 * Attempt out-of-order locking here.
799 if (task_lock_try(task
)) {
811 * Routine: convert_port_to_task
813 * Convert from a port to a task.
814 * Doesn't consume the port ref; produces a task ref,
820 convert_port_to_task(
825 task
= convert_port_to_locked_task(port
);
834 * Routine: convert_port_to_space
836 * Convert from a port to a space.
837 * Doesn't consume the port ref; produces a space ref,
843 convert_port_to_space(
849 task
= convert_port_to_locked_task(port
);
851 if (task
== TASK_NULL
)
852 return IPC_SPACE_NULL
;
856 return IPC_SPACE_NULL
;
859 space
= task
->itk_space
;
872 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_UPL
)) {
876 upl
= (upl_t
) port
->ip_kobject
;
888 return MACH_PORT_NULL
;
891 __private_extern__
void
894 mach_port_mscount_t mscount
)
900 * Routine: convert_port_entry_to_map
902 * Convert from a port specifying an entry or a task
903 * to a map. Doesn't consume the port ref; produces a map ref,
904 * which may be null. Unlike convert_port_to_map, the
905 * port may be task or a named entry backed.
912 convert_port_entry_to_map(
917 vm_named_entry_t named_entry
;
919 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
922 if(ip_active(port
) && (ip_kotype(port
)
923 == IKOT_NAMED_ENTRY
)) {
925 (vm_named_entry_t
)port
->ip_kobject
;
926 if (!(mutex_try(&(named_entry
)->Lock
))) {
931 named_entry
->ref_count
++;
932 mutex_unlock(&(named_entry
)->Lock
);
934 if ((named_entry
->is_sub_map
) &&
935 (named_entry
->protection
937 map
= named_entry
->backing
.map
;
939 mach_destroy_memory_entry(port
);
942 vm_map_reference_swap(map
);
943 mach_destroy_memory_entry(port
);
952 task
= convert_port_to_locked_task(port
);
954 if (task
== TASK_NULL
)
963 vm_map_reference_swap(map
);
971 * Routine: convert_port_entry_to_object
973 * Convert from a port specifying a named entry to an
974 * object. Doesn't consume the port ref; produces a map ref,
982 convert_port_entry_to_object(
986 vm_named_entry_t named_entry
;
988 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
991 if(ip_active(port
) && (ip_kotype(port
)
992 == IKOT_NAMED_ENTRY
)) {
994 (vm_named_entry_t
)port
->ip_kobject
;
995 if (!(mutex_try(&(named_entry
)->Lock
))) {
1000 named_entry
->ref_count
++;
1001 mutex_unlock(&(named_entry
)->Lock
);
1003 if ((!named_entry
->is_sub_map
) &&
1004 (named_entry
->protection
1006 object
= named_entry
->object
;
1008 mach_destroy_memory_entry(port
);
1009 return (vm_object_t
)NULL
;
1011 vm_object_reference(named_entry
->object
);
1012 mach_destroy_memory_entry(port
);
1016 return (vm_object_t
)NULL
;
1019 return (vm_object_t
)NULL
;
1026 * Routine: convert_port_to_map
1028 * Convert from a port to a map.
1029 * Doesn't consume the port ref; produces a map ref,
1030 * which may be null.
1036 convert_port_to_map(
1042 task
= convert_port_to_locked_task(port
);
1044 if (task
== TASK_NULL
)
1047 if (!task
->active
) {
1053 vm_map_reference_swap(map
);
1060 * Routine: convert_port_to_act
1062 * Convert from a port to a thr_act.
1063 * Doesn't consume the port ref; produces an thr_act ref,
1064 * which may be null.
1070 convert_port_to_act( ipc_port_t port
)
1073 thread_act_t thr_act
= 0;
1076 while (!r
&& IP_VALID(port
)) {
1078 r
= ref_act_port_locked(port
, &thr_act
);
1085 ref_act_port_locked( ipc_port_t port
, thread_act_t
*pthr_act
)
1087 thread_act_t thr_act
;
1090 if (ip_active(port
) &&
1091 (ip_kotype(port
) == IKOT_ACT
)) {
1092 thr_act
= (thread_act_t
) port
->ip_kobject
;
1093 assert(thr_act
!= THR_ACT_NULL
);
1096 * Normal lock ordering is act_lock(), then ip_lock().
1097 * Allow out-of-order locking here, using
1098 * act_reference_act_locked() to accomodate it.
1100 if (!act_lock_try(thr_act
)) {
1105 act_locked_act_reference(thr_act
);
1106 act_unlock(thr_act
);
1108 *pthr_act
= thr_act
;
1114 * Routine: port_name_to_act
1116 * Convert from a port name to an act reference
1117 * A name of MACH_PORT_NULL is valid for the null act
1123 mach_port_name_t name
)
1125 thread_act_t thr_act
= THR_ACT_NULL
;
1126 ipc_port_t kern_port
;
1129 if (MACH_PORT_VALID(name
)) {
1130 kr
= ipc_object_copyin(current_space(), name
,
1131 MACH_MSG_TYPE_COPY_SEND
,
1132 (ipc_object_t
*) &kern_port
);
1133 if (kr
!= KERN_SUCCESS
)
1134 return THR_ACT_NULL
;
1136 thr_act
= convert_port_to_act(kern_port
);
1138 if (IP_VALID(kern_port
))
1139 ipc_port_release_send(kern_port
);
1146 mach_port_name_t name
)
1148 ipc_port_t kern_port
;
1150 task_t task
= TASK_NULL
;
1152 if (MACH_PORT_VALID(name
)) {
1153 kr
= ipc_object_copyin(current_space(), name
,
1154 MACH_MSG_TYPE_COPY_SEND
,
1155 (ipc_object_t
*) &kern_port
);
1156 if (kr
!= KERN_SUCCESS
)
1159 task
= convert_port_to_task(kern_port
);
1161 if (IP_VALID(kern_port
))
1162 ipc_port_release_send(kern_port
);
1168 * Routine: convert_task_to_port
1170 * Convert from a task to a port.
1171 * Consumes a task ref; produces a naked send right
1172 * which may be invalid.
1178 convert_task_to_port(
1184 if (task
->itk_self
!= IP_NULL
)
1186 if (task
->map
== VM_MAP_NULL
)
1187 /* norma placeholder task */
1188 port
= ipc_port_copy_send(task
->itk_self
);
1190 #endif /* NORMA_TASK */
1191 port
= ipc_port_make_send(task
->itk_self
);
1196 task_deallocate(task
);
1201 * Routine: convert_act_to_port
1203 * Convert from a thr_act to a port.
1204 * Consumes an thr_act ref; produces a naked send right
1205 * which may be invalid.
1211 convert_act_to_port(thr_act
)
1212 thread_act_t thr_act
;
1217 if (thr_act
->ith_self
!= IP_NULL
)
1218 port
= ipc_port_make_send(thr_act
->ith_self
);
1221 act_unlock(thr_act
);
1223 act_deallocate(thr_act
);
1228 * Routine: space_deallocate
1230 * Deallocate a space ref produced by convert_port_to_space.
1239 if (space
!= IS_NULL
)
1244 * Routine: thread/task_set_exception_ports [kernel call]
1246 * Sets the thread/task exception port, flavor and
1247 * behavior for the exception types specified by the mask.
1248 * There will be one send right per exception per valid
1251 * Nothing locked. If successful, consumes
1252 * the supplied send right.
1254 * KERN_SUCCESS Changed the special port.
1255 * KERN_INVALID_ARGUMENT The thread is null,
1256 * Illegal mask bit set.
1257 * Illegal exception behavior
1258 * KERN_FAILURE The thread is dead.
1262 thread_set_exception_ports(
1263 thread_act_t thr_act
,
1264 exception_mask_t exception_mask
,
1265 ipc_port_t new_port
,
1266 exception_behavior_t new_behavior
,
1267 thread_state_flavor_t new_flavor
)
1270 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1273 return KERN_INVALID_ARGUMENT
;
1275 if (exception_mask
& ~EXC_MASK_ALL
)
1276 return KERN_INVALID_ARGUMENT
;
1278 if (IP_VALID(new_port
)) {
1279 switch (new_behavior
) {
1280 case EXCEPTION_DEFAULT
:
1281 case EXCEPTION_STATE
:
1282 case EXCEPTION_STATE_IDENTITY
:
1285 return KERN_INVALID_ARGUMENT
;
1290 * Check the validity of the thread_state_flavor by calling the
1291 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1292 * osfmk/mach/ARCHITECTURE/thread_status.h
1294 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
1295 return KERN_INVALID_ARGUMENT
;
1299 if (!thr_act
->active
) {
1300 act_unlock(thr_act
);
1301 return KERN_FAILURE
;
1304 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1305 if (exception_mask
& (1 << i
)) {
1306 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1307 thr_act
->exc_actions
[i
].port
=
1308 ipc_port_copy_send(new_port
);
1309 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1310 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1312 old_port
[i
] = IP_NULL
;
1315 * Consume send rights without any lock held.
1317 act_unlock(thr_act
);
1318 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1319 if (IP_VALID(old_port
[i
]))
1320 ipc_port_release_send(old_port
[i
]);
1321 if (IP_VALID(new_port
)) /* consume send right */
1322 ipc_port_release_send(new_port
);
1324 return KERN_SUCCESS
;
1325 }/* thread_set_exception_port */
1328 task_set_exception_ports(
1330 exception_mask_t exception_mask
,
1331 ipc_port_t new_port
,
1332 exception_behavior_t new_behavior
,
1333 thread_state_flavor_t new_flavor
)
1336 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1338 if (task
== TASK_NULL
) {
1339 return KERN_INVALID_ARGUMENT
;
1342 if (exception_mask
& ~EXC_MASK_ALL
) {
1343 return KERN_INVALID_ARGUMENT
;
1346 if (IP_VALID(new_port
)) {
1347 switch (new_behavior
) {
1348 case EXCEPTION_DEFAULT
:
1349 case EXCEPTION_STATE
:
1350 case EXCEPTION_STATE_IDENTITY
:
1353 return KERN_INVALID_ARGUMENT
;
1356 /* Cannot easily check "new_flavor", but that just means that
1357 * the flavor in the generated exception message might be garbage:
1361 if (task
->itk_self
== IP_NULL
) {
1363 return KERN_FAILURE
;
1366 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1367 if (exception_mask
& (1 << i
)) {
1368 old_port
[i
] = task
->exc_actions
[i
].port
;
1369 task
->exc_actions
[i
].port
=
1370 ipc_port_copy_send(new_port
);
1371 task
->exc_actions
[i
].behavior
= new_behavior
;
1372 task
->exc_actions
[i
].flavor
= new_flavor
;
1374 old_port
[i
] = IP_NULL
;
1378 * Consume send rights without any lock held.
1381 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1382 if (IP_VALID(old_port
[i
]))
1383 ipc_port_release_send(old_port
[i
]);
1384 if (IP_VALID(new_port
)) /* consume send right */
1385 ipc_port_release_send(new_port
);
1387 return KERN_SUCCESS
;
1388 }/* task_set_exception_port */
1391 * Routine: thread/task_swap_exception_ports [kernel call]
1393 * Sets the thread/task exception port, flavor and
1394 * behavior for the exception types specified by the
1397 * The old ports, behavior and flavors are returned
1398 * Count specifies the array sizes on input and
1399 * the number of returned ports etc. on output. The
1400 * arrays must be large enough to hold all the returned
1401 * data, MIG returnes an error otherwise. The masks
1402 * array specifies the corresponding exception type(s).
1405 * Nothing locked. If successful, consumes
1406 * the supplied send right.
1408 * Returns upto [in} CountCnt elements.
1410 * KERN_SUCCESS Changed the special port.
1411 * KERN_INVALID_ARGUMENT The thread is null,
1412 * Illegal mask bit set.
1413 * Illegal exception behavior
1414 * KERN_FAILURE The thread is dead.
1418 thread_swap_exception_ports(
1419 thread_act_t thr_act
,
1420 exception_mask_t exception_mask
,
1421 ipc_port_t new_port
,
1422 exception_behavior_t new_behavior
,
1423 thread_state_flavor_t new_flavor
,
1424 exception_mask_array_t masks
,
1425 mach_msg_type_number_t
* CountCnt
,
1426 exception_port_array_t ports
,
1427 exception_behavior_array_t behaviors
,
1428 thread_state_flavor_array_t flavors
)
1433 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1436 return KERN_INVALID_ARGUMENT
;
1438 if (exception_mask
& ~EXC_MASK_ALL
) {
1439 return KERN_INVALID_ARGUMENT
;
1442 if (IP_VALID(new_port
)) {
1443 switch (new_behavior
) {
1444 case EXCEPTION_DEFAULT
:
1445 case EXCEPTION_STATE
:
1446 case EXCEPTION_STATE_IDENTITY
:
1449 return KERN_INVALID_ARGUMENT
;
1452 /* Cannot easily check "new_flavor", but that just means that
1453 * the flavor in the generated exception message might be garbage:
1457 if (!thr_act
->active
) {
1458 act_unlock(thr_act
);
1459 return KERN_FAILURE
;
1464 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1465 if (exception_mask
& (1 << i
)) {
1466 for (j
= 0; j
< count
; j
++) {
1468 * search for an identical entry, if found
1469 * set corresponding mask for this exception.
1471 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1472 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1473 && thr_act
->exc_actions
[i
].flavor
==flavors
[j
])
1475 masks
[j
] |= (1 << i
);
1480 masks
[j
] = (1 << i
);
1482 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1484 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1485 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1489 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1490 thr_act
->exc_actions
[i
].port
=
1491 ipc_port_copy_send(new_port
);
1492 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1493 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1494 if (count
> *CountCnt
) {
1498 old_port
[i
] = IP_NULL
;
1502 * Consume send rights without any lock held.
1504 act_unlock(thr_act
);
1505 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1506 if (IP_VALID(old_port
[i
]))
1507 ipc_port_release_send(old_port
[i
]);
1508 if (IP_VALID(new_port
)) /* consume send right */
1509 ipc_port_release_send(new_port
);
1511 return KERN_SUCCESS
;
1512 }/* thread_swap_exception_ports */
1515 task_swap_exception_ports(
1517 exception_mask_t exception_mask
,
1518 ipc_port_t new_port
,
1519 exception_behavior_t new_behavior
,
1520 thread_state_flavor_t new_flavor
,
1521 exception_mask_array_t masks
,
1522 mach_msg_type_number_t
* CountCnt
,
1523 exception_port_array_t ports
,
1524 exception_behavior_array_t behaviors
,
1525 thread_state_flavor_array_t flavors
)
1530 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1532 if (task
== TASK_NULL
)
1533 return KERN_INVALID_ARGUMENT
;
1535 if (exception_mask
& ~EXC_MASK_ALL
) {
1536 return KERN_INVALID_ARGUMENT
;
1539 if (IP_VALID(new_port
)) {
1540 switch (new_behavior
) {
1541 case EXCEPTION_DEFAULT
:
1542 case EXCEPTION_STATE
:
1543 case EXCEPTION_STATE_IDENTITY
:
1546 return KERN_INVALID_ARGUMENT
;
1549 /* Cannot easily check "new_flavor", but that just means that
1550 * the flavor in the generated exception message might be garbage:
1554 if (task
->itk_self
== IP_NULL
) {
1556 return KERN_FAILURE
;
1561 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1562 if (exception_mask
& (1 << i
)) {
1563 for (j
= 0; j
< count
; j
++) {
1565 * search for an identical entry, if found
1566 * set corresponding mask for this exception.
1568 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1569 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1570 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1572 masks
[j
] |= (1 << i
);
1577 masks
[j
] = (1 << i
);
1579 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1580 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1581 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1584 old_port
[i
] = task
->exc_actions
[i
].port
;
1585 task
->exc_actions
[i
].port
=
1586 ipc_port_copy_send(new_port
);
1587 task
->exc_actions
[i
].behavior
= new_behavior
;
1588 task
->exc_actions
[i
].flavor
= new_flavor
;
1589 if (count
> *CountCnt
) {
1593 old_port
[i
] = IP_NULL
;
1598 * Consume send rights without any lock held.
1601 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1602 if (IP_VALID(old_port
[i
]))
1603 ipc_port_release_send(old_port
[i
]);
1604 if (IP_VALID(new_port
)) /* consume send right */
1605 ipc_port_release_send(new_port
);
1608 return KERN_SUCCESS
;
1609 }/* task_swap_exception_ports */
1612 * Routine: thread/task_get_exception_ports [kernel call]
1614 * Clones a send right for each of the thread/task's exception
1615 * ports specified in the mask and returns the behaviour
1616 * and flavor of said port.
1618 * Returns upto [in} CountCnt elements.
1623 * KERN_SUCCESS Extracted a send right.
1624 * KERN_INVALID_ARGUMENT The thread is null,
1625 * Invalid special port,
1626 * Illegal mask bit set.
1627 * KERN_FAILURE The thread is dead.
1631 thread_get_exception_ports(
1632 thread_act_t thr_act
,
1633 exception_mask_t exception_mask
,
1634 exception_mask_array_t masks
,
1635 mach_msg_type_number_t
* CountCnt
,
1636 exception_port_array_t ports
,
1637 exception_behavior_array_t behaviors
,
1638 thread_state_flavor_array_t flavors
)
1645 return KERN_INVALID_ARGUMENT
;
1647 if (exception_mask
& ~EXC_MASK_ALL
) {
1648 return KERN_INVALID_ARGUMENT
;
1652 if (!thr_act
->active
) {
1653 act_unlock(thr_act
);
1654 return KERN_FAILURE
;
1659 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1660 if (exception_mask
& (1 << i
)) {
1661 for (j
= 0; j
< count
; j
++) {
1663 * search for an identical entry, if found
1664 * set corresponding mask for this exception.
1666 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1667 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1668 && thr_act
->exc_actions
[i
].flavor
== flavors
[j
])
1670 masks
[j
] |= (1 << i
);
1675 masks
[j
] = (1 << i
);
1677 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1678 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1679 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1681 if (count
>= *CountCnt
) {
1688 act_unlock(thr_act
);
1691 return KERN_SUCCESS
;
1692 }/* thread_get_exception_ports */
1695 task_get_exception_ports(
1697 exception_mask_t exception_mask
,
1698 exception_mask_array_t masks
,
1699 mach_msg_type_number_t
* CountCnt
,
1700 exception_port_array_t ports
,
1701 exception_behavior_array_t behaviors
,
1702 thread_state_flavor_array_t flavors
)
1708 if (task
== TASK_NULL
)
1709 return KERN_INVALID_ARGUMENT
;
1711 if (exception_mask
& ~EXC_MASK_ALL
) {
1712 return KERN_INVALID_ARGUMENT
;
1716 if (task
->itk_self
== IP_NULL
) {
1718 return KERN_FAILURE
;
1723 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1724 if (exception_mask
& (1 << i
)) {
1725 for (j
= 0; j
< count
; j
++) {
1727 * search for an identical entry, if found
1728 * set corresponding mask for this exception.
1730 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1731 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1732 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1734 masks
[j
] |= (1 << i
);
1739 masks
[j
] = (1 << i
);
1741 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1742 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1743 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1745 if (count
> *CountCnt
) {
1755 return KERN_SUCCESS
;
1756 }/* task_get_exception_ports */