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/boolean.h>
64 #include <mach/kern_return.h>
65 #include <mach/mach_param.h>
66 #include <mach/task_special_ports.h>
67 #include <mach/thread_special_ports.h>
68 #include <mach/thread_status.h>
69 #include <mach/exception_types.h>
70 #include <mach/mach_traps.h>
71 #include <mach/task_server.h>
72 #include <mach/thread_act_server.h>
73 #include <mach/mach_host_server.h>
74 #include <mach/vm_map_server.h>
75 #include <kern/host.h>
76 #include <kern/ipc_tt.h>
77 #include <kern/thread_act.h>
78 #include <kern/misc_protos.h>
79 #include <vm/vm_pageout.h>
82 * Routine: ipc_task_init
84 * Initialize a task's IPC state.
86 * If non-null, some state will be inherited from the parent.
87 * The parent must be appropriately initialized.
103 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
104 if (kr
!= KERN_SUCCESS
)
105 panic("ipc_task_init");
108 kport
= ipc_port_alloc_kernel();
109 if (kport
== IP_NULL
)
110 panic("ipc_task_init");
113 task
->itk_self
= kport
;
114 task
->itk_sself
= ipc_port_make_send(kport
);
115 task
->itk_space
= space
;
116 space
->is_fast
= task
->kernel_loaded
;
118 if (parent
== TASK_NULL
) {
119 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
120 task
->exc_actions
[i
].port
= IP_NULL
;
122 task
->itk_host
= ipc_port_make_send(realhost
.host_self
);
123 task
->itk_bootstrap
= IP_NULL
;
124 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
125 task
->itk_registered
[i
] = IP_NULL
;
128 assert(parent
->itk_self
!= IP_NULL
);
130 /* inherit registered ports */
132 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
133 task
->itk_registered
[i
] =
134 ipc_port_copy_send(parent
->itk_registered
[i
]);
136 /* inherit exception and bootstrap ports */
138 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
139 task
->exc_actions
[i
].port
=
140 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
141 task
->exc_actions
[i
].flavor
=
142 parent
->exc_actions
[i
].flavor
;
143 task
->exc_actions
[i
].behavior
=
144 parent
->exc_actions
[i
].behavior
;
147 ipc_port_copy_send(parent
->itk_host
);
149 task
->itk_bootstrap
=
150 ipc_port_copy_send(parent
->itk_bootstrap
);
157 * Routine: ipc_task_enable
159 * Enable a task for IPC access.
171 kport
= task
->itk_self
;
172 if (kport
!= IP_NULL
)
173 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
178 * Routine: ipc_task_disable
180 * Disable IPC access to a task.
192 kport
= task
->itk_self
;
193 if (kport
!= IP_NULL
)
194 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
199 * Routine: ipc_task_terminate
201 * Clean up and destroy a task's IPC state.
203 * Nothing locked. The task must be suspended.
204 * (Or the current thread must be in the task.)
215 kport
= task
->itk_self
;
217 if (kport
== IP_NULL
) {
218 /* the task is already terminated (can this happen?) */
223 task
->itk_self
= IP_NULL
;
226 /* release the naked send rights */
228 if (IP_VALID(task
->itk_sself
))
229 ipc_port_release_send(task
->itk_sself
);
231 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
232 if (IP_VALID(task
->exc_actions
[i
].port
)) {
233 ipc_port_release_send(task
->exc_actions
[i
].port
);
236 if (IP_VALID(task
->itk_host
))
237 ipc_port_release_send(task
->itk_host
);
239 if (IP_VALID(task
->itk_bootstrap
))
240 ipc_port_release_send(task
->itk_bootstrap
);
242 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
243 if (IP_VALID(task
->itk_registered
[i
]))
244 ipc_port_release_send(task
->itk_registered
[i
]);
246 ipc_port_release_send(task
->wired_ledger_port
);
247 ipc_port_release_send(task
->paged_ledger_port
);
249 /* destroy the kernel port */
250 ipc_port_dealloc_kernel(kport
);
254 * Routine: ipc_thread_init
256 * Initialize a thread's IPC state.
265 ipc_kmsg_queue_init(&thread
->ith_messages
);
266 thread
->ith_mig_reply
= MACH_PORT_NULL
;
267 thread
->ith_rpc_reply
= IP_NULL
;
271 * Routine: ipc_thread_terminate
273 * Clean up and destroy a thread's IPC state.
275 * Nothing locked. The thread must be suspended.
276 * (Or be the current thread.)
280 ipc_thread_terminate(
283 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
285 if (thread
->ith_rpc_reply
!= IP_NULL
)
286 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
287 thread
->ith_rpc_reply
= IP_NULL
;
291 * Routine: ipc_thr_act_init
293 * Initialize an thr_act's IPC state.
299 ipc_thr_act_init(task_t task
, thread_act_t thr_act
)
301 ipc_port_t kport
; int i
;
303 kport
= ipc_port_alloc_kernel();
304 if (kport
== IP_NULL
)
305 panic("ipc_thr_act_init");
307 thr_act
->ith_self
= kport
;
308 thr_act
->ith_sself
= ipc_port_make_send(kport
);
310 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
311 thr_act
->exc_actions
[i
].port
= IP_NULL
;
313 ipc_kobject_set(kport
, (ipc_kobject_t
) thr_act
, IKOT_ACT
);
317 ipc_thr_act_disable(thread_act_t thr_act
)
322 kport
= thr_act
->ith_self
;
324 if (kport
!= IP_NULL
)
325 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
329 ipc_thr_act_terminate(thread_act_t thr_act
)
331 ipc_port_t kport
; int i
;
333 kport
= thr_act
->ith_self
;
335 if (kport
== IP_NULL
) {
336 /* the thread is already terminated (can this happen?) */
340 thr_act
->ith_self
= IP_NULL
;
342 /* release the naked send rights */
344 if (IP_VALID(thr_act
->ith_sself
))
345 ipc_port_release_send(thr_act
->ith_sself
);
346 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
347 if (IP_VALID(thr_act
->exc_actions
[i
].port
))
348 ipc_port_release_send(thr_act
->exc_actions
[i
].port
);
351 /* destroy the kernel port */
352 ipc_port_dealloc_kernel(kport
);
356 * Routine: retrieve_task_self_fast
358 * Optimized version of retrieve_task_self,
359 * that only works for the current task.
361 * Return a send right (possibly null/dead)
362 * for the task's user-visible self port.
368 retrieve_task_self_fast(
369 register task_t task
)
371 register ipc_port_t port
;
373 assert(task
== current_task());
376 assert(task
->itk_self
!= IP_NULL
);
378 if ((port
= task
->itk_sself
) == task
->itk_self
) {
382 assert(ip_active(port
));
387 port
= ipc_port_copy_send(port
);
394 * Routine: retrieve_act_self_fast
396 * Optimized version of retrieve_thread_self,
397 * that only works for the current thread.
399 * Return a send right (possibly null/dead)
400 * for the thread's user-visible self port.
406 retrieve_act_self_fast(thread_act_t thr_act
)
408 register ipc_port_t port
;
410 assert(thr_act
== current_act());
412 assert(thr_act
->ith_self
!= IP_NULL
);
414 if ((port
= thr_act
->ith_sself
) == thr_act
->ith_self
) {
418 assert(ip_active(port
));
423 port
= ipc_port_copy_send(port
);
430 * Routine: task_self_trap [mach trap]
432 * Give the caller send rights for his own task port.
436 * MACH_PORT_NULL if there are any resource failures
443 task_t task
= current_task();
446 sright
= retrieve_task_self_fast(task
);
447 return ipc_port_copyout_send(sright
, task
->itk_space
);
451 * Routine: thread_self_trap [mach trap]
453 * Give the caller send rights for his own thread port.
457 * MACH_PORT_NULL if there are any resource failures
462 thread_self_trap(void)
464 thread_act_t thr_act
= current_act();
465 task_t task
= thr_act
->task
;
468 sright
= retrieve_act_self_fast(thr_act
);
469 return ipc_port_copyout_send(sright
, task
->itk_space
);
473 * Routine: mach_reply_port [mach trap]
475 * Allocate a port for the caller.
479 * MACH_PORT_NULL if there are any resource failures
484 mach_reply_port(void)
487 mach_port_name_t name
;
490 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
491 if (kr
== KERN_SUCCESS
)
494 name
= MACH_PORT_NULL
;
500 * Routine: task_get_special_port [kernel call]
502 * Clones a send right for one of the task's
507 * KERN_SUCCESS Extracted a send right.
508 * KERN_INVALID_ARGUMENT The task is null.
509 * KERN_FAILURE The task/space is dead.
510 * KERN_INVALID_ARGUMENT Invalid special port.
514 task_get_special_port(
522 if (task
== TASK_NULL
)
523 return KERN_INVALID_ARGUMENT
;
526 case TASK_KERNEL_PORT
:
527 whichp
= &task
->itk_sself
;
531 whichp
= &task
->itk_host
;
534 case TASK_BOOTSTRAP_PORT
:
535 whichp
= &task
->itk_bootstrap
;
538 case TASK_WIRED_LEDGER_PORT
:
539 whichp
= &task
->wired_ledger_port
;
542 case TASK_PAGED_LEDGER_PORT
:
543 whichp
= &task
->paged_ledger_port
;
547 return KERN_INVALID_ARGUMENT
;
551 if (task
->itk_self
== IP_NULL
) {
556 port
= ipc_port_copy_send(*whichp
);
564 * Routine: task_set_special_port [kernel call]
566 * Changes one of the task's special ports,
567 * setting it to the supplied send right.
569 * Nothing locked. If successful, consumes
570 * the supplied send right.
572 * KERN_SUCCESS Changed the special port.
573 * KERN_INVALID_ARGUMENT The task is null.
574 * KERN_FAILURE The task/space is dead.
575 * KERN_INVALID_ARGUMENT Invalid special port.
579 task_set_special_port(
587 if (task
== TASK_NULL
)
588 return KERN_INVALID_ARGUMENT
;
591 case TASK_KERNEL_PORT
:
592 whichp
= &task
->itk_sself
;
596 whichp
= &task
->itk_host
;
599 case TASK_BOOTSTRAP_PORT
:
600 whichp
= &task
->itk_bootstrap
;
603 case TASK_WIRED_LEDGER_PORT
:
604 whichp
= &task
->wired_ledger_port
;
607 case TASK_PAGED_LEDGER_PORT
:
608 whichp
= &task
->paged_ledger_port
;
612 return KERN_INVALID_ARGUMENT
;
616 if (task
->itk_self
== IP_NULL
) {
626 ipc_port_release_send(old
);
632 * Routine: mach_ports_register [kernel call]
634 * Stash a handful of port send rights in the task.
635 * Child tasks will inherit these rights, but they
636 * must use mach_ports_lookup to acquire them.
638 * The rights are supplied in a (wired) kalloc'd segment.
639 * Rights which aren't supplied are assumed to be null.
641 * Nothing locked. If successful, consumes
642 * the supplied rights and memory.
644 * KERN_SUCCESS Stashed the port rights.
645 * KERN_INVALID_ARGUMENT The task is null.
646 * KERN_INVALID_ARGUMENT The task is dead.
647 * KERN_INVALID_ARGUMENT Too many port rights supplied.
653 mach_port_array_t memory
,
654 mach_msg_type_number_t portsCnt
)
656 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
659 if ((task
== TASK_NULL
) ||
660 (portsCnt
> TASK_PORT_REGISTER_MAX
))
661 return KERN_INVALID_ARGUMENT
;
664 * Pad the port rights with nulls.
667 for (i
= 0; i
< portsCnt
; i
++)
668 ports
[i
] = memory
[i
];
669 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
673 if (task
->itk_self
== IP_NULL
) {
675 return KERN_INVALID_ARGUMENT
;
679 * Replace the old send rights with the new.
680 * Release the old rights after unlocking.
683 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
686 old
= task
->itk_registered
[i
];
687 task
->itk_registered
[i
] = ports
[i
];
693 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
694 if (IP_VALID(ports
[i
]))
695 ipc_port_release_send(ports
[i
]);
698 * Now that the operation is known to be successful,
699 * we can free the memory.
703 kfree((vm_offset_t
) memory
,
704 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
710 * Routine: mach_ports_lookup [kernel call]
712 * Retrieves (clones) the stashed port send rights.
714 * Nothing locked. If successful, the caller gets
717 * KERN_SUCCESS Retrieved the send rights.
718 * KERN_INVALID_ARGUMENT The task is null.
719 * KERN_INVALID_ARGUMENT The task is dead.
720 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
726 mach_port_array_t
*portsp
,
727 mach_msg_type_number_t
*portsCnt
)
736 if (task
== TASK_NULL
)
737 return KERN_INVALID_ARGUMENT
;
739 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
741 memory
= kalloc(size
);
743 return KERN_RESOURCE_SHORTAGE
;
746 if (task
->itk_self
== IP_NULL
) {
750 return KERN_INVALID_ARGUMENT
;
753 ports
= (ipc_port_t
*) memory
;
756 * Clone port rights. Because kalloc'd memory
757 * is wired, we won't fault while holding the task lock.
760 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
761 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
765 *portsp
= (mach_port_array_t
) ports
;
766 *portsCnt
= TASK_PORT_REGISTER_MAX
;
771 * Routine: convert_port_to_locked_task
773 * Internal helper routine to convert from a port to a locked
774 * task. Used by several routines that try to convert from a
775 * task port to a reference on some task related object.
777 * Nothing locked, blocking OK.
780 convert_port_to_locked_task(ipc_port_t port
)
782 while (IP_VALID(port
)) {
786 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
790 task
= (task_t
) port
->ip_kobject
;
791 assert(task
!= TASK_NULL
);
794 * Normal lock ordering puts task_lock() before ip_lock().
795 * Attempt out-of-order locking here.
797 if (task_lock_try(task
)) {
809 * Routine: convert_port_to_task
811 * Convert from a port to a task.
812 * Doesn't consume the port ref; produces a task ref,
818 convert_port_to_task(
823 task
= convert_port_to_locked_task(port
);
832 * Routine: convert_port_to_space
834 * Convert from a port to a space.
835 * Doesn't consume the port ref; produces a space ref,
841 convert_port_to_space(
847 task
= convert_port_to_locked_task(port
);
849 if (task
== TASK_NULL
)
850 return IPC_SPACE_NULL
;
854 return IPC_SPACE_NULL
;
857 space
= task
->itk_space
;
870 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_UPL
)) {
874 upl
= (upl_t
) port
->ip_kobject
;
886 return MACH_PORT_NULL
;
889 __private_extern__
void
892 mach_port_mscount_t mscount
)
898 * Routine: convert_port_entry_to_map
900 * Convert from a port specifying an entry or a task
901 * to a map. Doesn't consume the port ref; produces a map ref,
902 * which may be null. Unlike convert_port_to_map, the
903 * port may be task or a named entry backed.
910 convert_port_entry_to_map(
915 vm_named_entry_t named_entry
;
917 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
920 if(ip_active(port
) && (ip_kotype(port
)
921 == IKOT_NAMED_ENTRY
)) {
923 (vm_named_entry_t
)port
->ip_kobject
;
924 if (!(mutex_try(&(named_entry
)->Lock
))) {
929 named_entry
->ref_count
++;
930 mutex_unlock(&(named_entry
)->Lock
);
932 if ((named_entry
->is_sub_map
) &&
933 (named_entry
->protection
935 map
= named_entry
->backing
.map
;
937 mach_destroy_memory_entry(port
);
940 vm_map_reference_swap(map
);
941 mach_destroy_memory_entry(port
);
950 task
= convert_port_to_locked_task(port
);
952 if (task
== TASK_NULL
)
961 vm_map_reference_swap(map
);
969 * Routine: convert_port_entry_to_object
971 * Convert from a port specifying a named entry to an
972 * object. Doesn't consume the port ref; produces a map ref,
980 convert_port_entry_to_object(
984 vm_named_entry_t named_entry
;
986 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
989 if(ip_active(port
) && (ip_kotype(port
)
990 == IKOT_NAMED_ENTRY
)) {
992 (vm_named_entry_t
)port
->ip_kobject
;
993 if (!(mutex_try(&(named_entry
)->Lock
))) {
998 named_entry
->ref_count
++;
999 mutex_unlock(&(named_entry
)->Lock
);
1001 if ((!named_entry
->is_sub_map
) &&
1002 (named_entry
->protection
1004 object
= named_entry
->object
;
1006 mach_destroy_memory_entry(port
);
1007 return (vm_object_t
)NULL
;
1009 vm_object_reference(named_entry
->object
);
1010 mach_destroy_memory_entry(port
);
1014 return (vm_object_t
)NULL
;
1017 return (vm_object_t
)NULL
;
1024 * Routine: convert_port_to_map
1026 * Convert from a port to a map.
1027 * Doesn't consume the port ref; produces a map ref,
1028 * which may be null.
1034 convert_port_to_map(
1040 task
= convert_port_to_locked_task(port
);
1042 if (task
== TASK_NULL
)
1045 if (!task
->active
) {
1051 vm_map_reference_swap(map
);
1058 * Routine: convert_port_to_act
1060 * Convert from a port to a thr_act.
1061 * Doesn't consume the port ref; produces an thr_act ref,
1062 * which may be null.
1068 convert_port_to_act( ipc_port_t port
)
1071 thread_act_t thr_act
= 0;
1074 while (!r
&& IP_VALID(port
)) {
1076 r
= ref_act_port_locked(port
, &thr_act
);
1083 ref_act_port_locked( ipc_port_t port
, thread_act_t
*pthr_act
)
1085 thread_act_t thr_act
;
1088 if (ip_active(port
) &&
1089 (ip_kotype(port
) == IKOT_ACT
)) {
1090 thr_act
= (thread_act_t
) port
->ip_kobject
;
1091 assert(thr_act
!= THR_ACT_NULL
);
1094 * Normal lock ordering is act_lock(), then ip_lock().
1095 * Allow out-of-order locking here, using
1096 * act_reference_act_locked() to accomodate it.
1098 if (!act_lock_try(thr_act
)) {
1103 act_locked_act_reference(thr_act
);
1104 act_unlock(thr_act
);
1106 *pthr_act
= thr_act
;
1112 * Routine: port_name_to_act
1114 * Convert from a port name to an act reference
1115 * A name of MACH_PORT_NULL is valid for the null act
1121 mach_port_name_t name
)
1123 thread_act_t thr_act
= THR_ACT_NULL
;
1124 ipc_port_t kern_port
;
1127 if (MACH_PORT_VALID(name
)) {
1128 kr
= ipc_object_copyin(current_space(), name
,
1129 MACH_MSG_TYPE_COPY_SEND
,
1130 (ipc_object_t
*) &kern_port
);
1131 if (kr
!= KERN_SUCCESS
)
1132 return THR_ACT_NULL
;
1134 thr_act
= convert_port_to_act(kern_port
);
1136 if (IP_VALID(kern_port
))
1137 ipc_port_release_send(kern_port
);
1144 mach_port_name_t name
)
1146 ipc_port_t kern_port
;
1148 task_t task
= TASK_NULL
;
1150 if (MACH_PORT_VALID(name
)) {
1151 kr
= ipc_object_copyin(current_space(), name
,
1152 MACH_MSG_TYPE_COPY_SEND
,
1153 (ipc_object_t
*) &kern_port
);
1154 if (kr
!= KERN_SUCCESS
)
1157 task
= convert_port_to_task(kern_port
);
1159 if (IP_VALID(kern_port
))
1160 ipc_port_release_send(kern_port
);
1166 * Routine: convert_task_to_port
1168 * Convert from a task to a port.
1169 * Consumes a task ref; produces a naked send right
1170 * which may be invalid.
1176 convert_task_to_port(
1182 if (task
->itk_self
!= IP_NULL
)
1184 if (task
->map
== VM_MAP_NULL
)
1185 /* norma placeholder task */
1186 port
= ipc_port_copy_send(task
->itk_self
);
1188 #endif /* NORMA_TASK */
1189 port
= ipc_port_make_send(task
->itk_self
);
1194 task_deallocate(task
);
1199 * Routine: convert_act_to_port
1201 * Convert from a thr_act to a port.
1202 * Consumes an thr_act ref; produces a naked send right
1203 * which may be invalid.
1209 convert_act_to_port(thr_act
)
1210 thread_act_t thr_act
;
1215 if (thr_act
->ith_self
!= IP_NULL
)
1216 port
= ipc_port_make_send(thr_act
->ith_self
);
1219 act_unlock(thr_act
);
1221 act_deallocate(thr_act
);
1226 * Routine: space_deallocate
1228 * Deallocate a space ref produced by convert_port_to_space.
1237 if (space
!= IS_NULL
)
1242 * Routine: thread/task_set_exception_ports [kernel call]
1244 * Sets the thread/task exception port, flavor and
1245 * behavior for the exception types specified by the mask.
1246 * There will be one send right per exception per valid
1249 * Nothing locked. If successful, consumes
1250 * the supplied send right.
1252 * KERN_SUCCESS Changed the special port.
1253 * KERN_INVALID_ARGUMENT The thread is null,
1254 * Illegal mask bit set.
1255 * Illegal exception behavior
1256 * KERN_FAILURE The thread is dead.
1260 thread_set_exception_ports(
1261 thread_act_t thr_act
,
1262 exception_mask_t exception_mask
,
1263 ipc_port_t new_port
,
1264 exception_behavior_t new_behavior
,
1265 thread_state_flavor_t new_flavor
)
1268 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1271 return KERN_INVALID_ARGUMENT
;
1273 if (exception_mask
& ~EXC_MASK_ALL
)
1274 return KERN_INVALID_ARGUMENT
;
1276 if (IP_VALID(new_port
)) {
1277 switch (new_behavior
) {
1278 case EXCEPTION_DEFAULT
:
1279 case EXCEPTION_STATE
:
1280 case EXCEPTION_STATE_IDENTITY
:
1283 return KERN_INVALID_ARGUMENT
;
1288 * Check the validity of the thread_state_flavor by calling the
1289 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1290 * osfmk/mach/ARCHITECTURE/thread_status.h
1292 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
1293 return KERN_INVALID_ARGUMENT
;
1297 if (!thr_act
->active
) {
1298 act_unlock(thr_act
);
1299 return KERN_FAILURE
;
1302 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1303 if (exception_mask
& (1 << i
)) {
1304 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1305 thr_act
->exc_actions
[i
].port
=
1306 ipc_port_copy_send(new_port
);
1307 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1308 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1310 old_port
[i
] = IP_NULL
;
1313 * Consume send rights without any lock held.
1315 act_unlock(thr_act
);
1316 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1317 if (IP_VALID(old_port
[i
]))
1318 ipc_port_release_send(old_port
[i
]);
1319 if (IP_VALID(new_port
)) /* consume send right */
1320 ipc_port_release_send(new_port
);
1322 return KERN_SUCCESS
;
1323 }/* thread_set_exception_port */
1326 task_set_exception_ports(
1328 exception_mask_t exception_mask
,
1329 ipc_port_t new_port
,
1330 exception_behavior_t new_behavior
,
1331 thread_state_flavor_t new_flavor
)
1334 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1336 if (task
== TASK_NULL
) {
1337 return KERN_INVALID_ARGUMENT
;
1340 if (exception_mask
& ~EXC_MASK_ALL
) {
1341 return KERN_INVALID_ARGUMENT
;
1344 if (IP_VALID(new_port
)) {
1345 switch (new_behavior
) {
1346 case EXCEPTION_DEFAULT
:
1347 case EXCEPTION_STATE
:
1348 case EXCEPTION_STATE_IDENTITY
:
1351 return KERN_INVALID_ARGUMENT
;
1354 /* Cannot easily check "new_flavor", but that just means that
1355 * the flavor in the generated exception message might be garbage:
1359 if (task
->itk_self
== IP_NULL
) {
1361 return KERN_FAILURE
;
1364 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1365 if (exception_mask
& (1 << i
)) {
1366 old_port
[i
] = task
->exc_actions
[i
].port
;
1367 task
->exc_actions
[i
].port
=
1368 ipc_port_copy_send(new_port
);
1369 task
->exc_actions
[i
].behavior
= new_behavior
;
1370 task
->exc_actions
[i
].flavor
= new_flavor
;
1372 old_port
[i
] = IP_NULL
;
1376 * Consume send rights without any lock held.
1379 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1380 if (IP_VALID(old_port
[i
]))
1381 ipc_port_release_send(old_port
[i
]);
1382 if (IP_VALID(new_port
)) /* consume send right */
1383 ipc_port_release_send(new_port
);
1385 return KERN_SUCCESS
;
1386 }/* task_set_exception_port */
1389 * Routine: thread/task_swap_exception_ports [kernel call]
1391 * Sets the thread/task exception port, flavor and
1392 * behavior for the exception types specified by the
1395 * The old ports, behavior and flavors are returned
1396 * Count specifies the array sizes on input and
1397 * the number of returned ports etc. on output. The
1398 * arrays must be large enough to hold all the returned
1399 * data, MIG returnes an error otherwise. The masks
1400 * array specifies the corresponding exception type(s).
1403 * Nothing locked. If successful, consumes
1404 * the supplied send right.
1406 * Returns upto [in} CountCnt elements.
1408 * KERN_SUCCESS Changed the special port.
1409 * KERN_INVALID_ARGUMENT The thread is null,
1410 * Illegal mask bit set.
1411 * Illegal exception behavior
1412 * KERN_FAILURE The thread is dead.
1416 thread_swap_exception_ports(
1417 thread_act_t thr_act
,
1418 exception_mask_t exception_mask
,
1419 ipc_port_t new_port
,
1420 exception_behavior_t new_behavior
,
1421 thread_state_flavor_t new_flavor
,
1422 exception_mask_array_t masks
,
1423 mach_msg_type_number_t
* CountCnt
,
1424 exception_port_array_t ports
,
1425 exception_behavior_array_t behaviors
,
1426 thread_state_flavor_array_t flavors
)
1431 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1434 return KERN_INVALID_ARGUMENT
;
1436 if (exception_mask
& ~EXC_MASK_ALL
) {
1437 return KERN_INVALID_ARGUMENT
;
1440 if (IP_VALID(new_port
)) {
1441 switch (new_behavior
) {
1442 case EXCEPTION_DEFAULT
:
1443 case EXCEPTION_STATE
:
1444 case EXCEPTION_STATE_IDENTITY
:
1447 return KERN_INVALID_ARGUMENT
;
1450 /* Cannot easily check "new_flavor", but that just means that
1451 * the flavor in the generated exception message might be garbage:
1455 if (!thr_act
->active
) {
1456 act_unlock(thr_act
);
1457 return KERN_FAILURE
;
1462 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1463 if (exception_mask
& (1 << i
)) {
1464 for (j
= 0; j
< count
; j
++) {
1466 * search for an identical entry, if found
1467 * set corresponding mask for this exception.
1469 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1470 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1471 && thr_act
->exc_actions
[i
].flavor
==flavors
[j
])
1473 masks
[j
] |= (1 << i
);
1478 masks
[j
] = (1 << i
);
1480 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1482 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1483 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1487 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1488 thr_act
->exc_actions
[i
].port
=
1489 ipc_port_copy_send(new_port
);
1490 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1491 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1492 if (count
> *CountCnt
) {
1496 old_port
[i
] = IP_NULL
;
1500 * Consume send rights without any lock held.
1502 act_unlock(thr_act
);
1503 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1504 if (IP_VALID(old_port
[i
]))
1505 ipc_port_release_send(old_port
[i
]);
1506 if (IP_VALID(new_port
)) /* consume send right */
1507 ipc_port_release_send(new_port
);
1509 return KERN_SUCCESS
;
1510 }/* thread_swap_exception_ports */
1513 task_swap_exception_ports(
1515 exception_mask_t exception_mask
,
1516 ipc_port_t new_port
,
1517 exception_behavior_t new_behavior
,
1518 thread_state_flavor_t new_flavor
,
1519 exception_mask_array_t masks
,
1520 mach_msg_type_number_t
* CountCnt
,
1521 exception_port_array_t ports
,
1522 exception_behavior_array_t behaviors
,
1523 thread_state_flavor_array_t flavors
)
1528 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1530 if (task
== TASK_NULL
)
1531 return KERN_INVALID_ARGUMENT
;
1533 if (exception_mask
& ~EXC_MASK_ALL
) {
1534 return KERN_INVALID_ARGUMENT
;
1537 if (IP_VALID(new_port
)) {
1538 switch (new_behavior
) {
1539 case EXCEPTION_DEFAULT
:
1540 case EXCEPTION_STATE
:
1541 case EXCEPTION_STATE_IDENTITY
:
1544 return KERN_INVALID_ARGUMENT
;
1547 /* Cannot easily check "new_flavor", but that just means that
1548 * the flavor in the generated exception message might be garbage:
1552 if (task
->itk_self
== IP_NULL
) {
1554 return KERN_FAILURE
;
1559 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1560 if (exception_mask
& (1 << i
)) {
1561 for (j
= 0; j
< count
; j
++) {
1563 * search for an identical entry, if found
1564 * set corresponding mask for this exception.
1566 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1567 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1568 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1570 masks
[j
] |= (1 << i
);
1575 masks
[j
] = (1 << i
);
1577 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1578 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1579 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1582 old_port
[i
] = task
->exc_actions
[i
].port
;
1583 task
->exc_actions
[i
].port
=
1584 ipc_port_copy_send(new_port
);
1585 task
->exc_actions
[i
].behavior
= new_behavior
;
1586 task
->exc_actions
[i
].flavor
= new_flavor
;
1587 if (count
> *CountCnt
) {
1591 old_port
[i
] = IP_NULL
;
1596 * Consume send rights without any lock held.
1599 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1600 if (IP_VALID(old_port
[i
]))
1601 ipc_port_release_send(old_port
[i
]);
1602 if (IP_VALID(new_port
)) /* consume send right */
1603 ipc_port_release_send(new_port
);
1606 return KERN_SUCCESS
;
1607 }/* task_swap_exception_ports */
1610 * Routine: thread/task_get_exception_ports [kernel call]
1612 * Clones a send right for each of the thread/task's exception
1613 * ports specified in the mask and returns the behaviour
1614 * and flavor of said port.
1616 * Returns upto [in} CountCnt elements.
1621 * KERN_SUCCESS Extracted a send right.
1622 * KERN_INVALID_ARGUMENT The thread is null,
1623 * Invalid special port,
1624 * Illegal mask bit set.
1625 * KERN_FAILURE The thread is dead.
1629 thread_get_exception_ports(
1630 thread_act_t thr_act
,
1631 exception_mask_t exception_mask
,
1632 exception_mask_array_t masks
,
1633 mach_msg_type_number_t
* CountCnt
,
1634 exception_port_array_t ports
,
1635 exception_behavior_array_t behaviors
,
1636 thread_state_flavor_array_t flavors
)
1643 return KERN_INVALID_ARGUMENT
;
1645 if (exception_mask
& ~EXC_MASK_ALL
) {
1646 return KERN_INVALID_ARGUMENT
;
1650 if (!thr_act
->active
) {
1651 act_unlock(thr_act
);
1652 return KERN_FAILURE
;
1657 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1658 if (exception_mask
& (1 << i
)) {
1659 for (j
= 0; j
< count
; j
++) {
1661 * search for an identical entry, if found
1662 * set corresponding mask for this exception.
1664 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1665 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1666 && thr_act
->exc_actions
[i
].flavor
== flavors
[j
])
1668 masks
[j
] |= (1 << i
);
1673 masks
[j
] = (1 << i
);
1675 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1676 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1677 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1679 if (count
>= *CountCnt
) {
1686 act_unlock(thr_act
);
1689 return KERN_SUCCESS
;
1690 }/* thread_get_exception_ports */
1693 task_get_exception_ports(
1695 exception_mask_t exception_mask
,
1696 exception_mask_array_t masks
,
1697 mach_msg_type_number_t
* CountCnt
,
1698 exception_port_array_t ports
,
1699 exception_behavior_array_t behaviors
,
1700 thread_state_flavor_array_t flavors
)
1706 if (task
== TASK_NULL
)
1707 return KERN_INVALID_ARGUMENT
;
1709 if (exception_mask
& ~EXC_MASK_ALL
) {
1710 return KERN_INVALID_ARGUMENT
;
1714 if (task
->itk_self
== IP_NULL
) {
1716 return KERN_FAILURE
;
1721 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1722 if (exception_mask
& (1 << i
)) {
1723 for (j
= 0; j
< count
; j
++) {
1725 * search for an identical entry, if found
1726 * set corresponding mask for this exception.
1728 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1729 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1730 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1732 masks
[j
] |= (1 << i
);
1737 masks
[j
] = (1 << i
);
1739 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1740 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1741 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1743 if (count
> *CountCnt
) {
1753 return KERN_SUCCESS
;
1754 }/* task_get_exception_ports */