2 * Copyright (c) 2000-2003 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/mach_types.h>
60 #include <mach/boolean.h>
62 #include <mach/kern_return.h>
63 #include <mach/mach_param.h>
64 #include <mach/task_special_ports.h>
65 #include <mach/thread_special_ports.h>
66 #include <mach/thread_status.h>
67 #include <mach/exception_types.h>
68 #include <mach/mach_traps.h>
69 #include <mach/task_server.h>
70 #include <mach/thread_act_server.h>
71 #include <mach/mach_host_server.h>
72 #include <mach/vm_map_server.h>
73 #include <kern/host.h>
74 #include <kern/ipc_tt.h>
75 #include <kern/thread_act.h>
76 #include <kern/misc_protos.h>
77 #include <vm/vm_pageout.h>
80 * Routine: ipc_task_init
82 * Initialize a task's IPC state.
84 * If non-null, some state will be inherited from the parent.
85 * The parent must be appropriately initialized.
101 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
102 if (kr
!= KERN_SUCCESS
)
103 panic("ipc_task_init");
106 kport
= ipc_port_alloc_kernel();
107 if (kport
== IP_NULL
)
108 panic("ipc_task_init");
111 task
->itk_self
= kport
;
112 task
->itk_sself
= ipc_port_make_send(kport
);
113 task
->itk_space
= space
;
114 space
->is_fast
= FALSE
;
116 if (parent
== TASK_NULL
) {
119 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
120 task
->exc_actions
[i
].port
= IP_NULL
;
123 kr
= host_get_host_port(host_priv_self(), &port
);
124 assert(kr
== KERN_SUCCESS
);
125 task
->itk_host
= port
;
127 task
->itk_bootstrap
= IP_NULL
;
129 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
130 task
->itk_registered
[i
] = IP_NULL
;
133 assert(parent
->itk_self
!= IP_NULL
);
135 /* inherit registered ports */
137 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
138 task
->itk_registered
[i
] =
139 ipc_port_copy_send(parent
->itk_registered
[i
]);
141 /* inherit exception and bootstrap ports */
143 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
144 task
->exc_actions
[i
].port
=
145 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
146 task
->exc_actions
[i
].flavor
=
147 parent
->exc_actions
[i
].flavor
;
148 task
->exc_actions
[i
].behavior
=
149 parent
->exc_actions
[i
].behavior
;
152 ipc_port_copy_send(parent
->itk_host
);
154 task
->itk_bootstrap
=
155 ipc_port_copy_send(parent
->itk_bootstrap
);
162 * Routine: ipc_task_enable
164 * Enable a task for IPC access.
176 kport
= task
->itk_self
;
177 if (kport
!= IP_NULL
)
178 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
183 * Routine: ipc_task_disable
185 * Disable IPC access to a task.
197 kport
= task
->itk_self
;
198 if (kport
!= IP_NULL
)
199 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
204 * Routine: ipc_task_terminate
206 * Clean up and destroy a task's IPC state.
208 * Nothing locked. The task must be suspended.
209 * (Or the current thread must be in the task.)
220 kport
= task
->itk_self
;
222 if (kport
== IP_NULL
) {
223 /* the task is already terminated (can this happen?) */
228 task
->itk_self
= IP_NULL
;
231 /* release the naked send rights */
233 if (IP_VALID(task
->itk_sself
))
234 ipc_port_release_send(task
->itk_sself
);
236 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
237 if (IP_VALID(task
->exc_actions
[i
].port
)) {
238 ipc_port_release_send(task
->exc_actions
[i
].port
);
241 if (IP_VALID(task
->itk_host
))
242 ipc_port_release_send(task
->itk_host
);
244 if (IP_VALID(task
->itk_bootstrap
))
245 ipc_port_release_send(task
->itk_bootstrap
);
247 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
248 if (IP_VALID(task
->itk_registered
[i
]))
249 ipc_port_release_send(task
->itk_registered
[i
]);
251 ipc_port_release_send(task
->wired_ledger_port
);
252 ipc_port_release_send(task
->paged_ledger_port
);
254 /* destroy the kernel port */
255 ipc_port_dealloc_kernel(kport
);
259 * Routine: ipc_task_reset
261 * Reset a task's IPC state to protect it when
262 * it enters an elevated security context.
264 * Nothing locked. The task must be suspended.
265 * (Or the current thread must be in the task.)
272 ipc_port_t old_kport
, new_kport
;
273 ipc_port_t old_sself
;
275 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
279 new_kport
= ipc_port_alloc_kernel();
280 if (new_kport
== IP_NULL
)
281 panic("ipc_task_reset");
285 old_kport
= task
->itk_self
;
287 if (old_kport
== IP_NULL
) {
288 /* the task is already terminated (can this happen?) */
290 ipc_port_dealloc_kernel(new_kport
);
294 task
->itk_self
= new_kport
;
295 old_sself
= task
->itk_sself
;
296 task
->itk_sself
= ipc_port_make_send(new_kport
);
297 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
298 ipc_kobject_set(new_kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
301 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
302 old_exc_actions
[i
] = task
->exc_action
[i
].port
;
303 task
->exc_actions
[i
].port
= IP_NULL
;
309 /* release the naked send rights */
311 if (IP_VALID(old_sself
))
312 ipc_port_release_send(old_sself
);
315 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
316 if (IP_VALID(old_exc_actions
[i
])) {
317 ipc_port_release_send(old_exc_actions
[i
]);
322 /* destroy the kernel port */
323 ipc_port_dealloc_kernel(old_kport
);
327 * Routine: ipc_thread_init
329 * Initialize a thread's IPC state.
338 ipc_kmsg_queue_init(&thread
->ith_messages
);
339 thread
->ith_mig_reply
= MACH_PORT_NULL
;
340 thread
->ith_rpc_reply
= IP_NULL
;
344 * Routine: ipc_thread_terminate
346 * Clean up and destroy a thread's IPC state.
348 * Nothing locked. The thread must be suspended.
349 * (Or be the current thread.)
353 ipc_thread_terminate(
356 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
358 if (thread
->ith_rpc_reply
!= IP_NULL
)
359 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
360 thread
->ith_rpc_reply
= IP_NULL
;
364 * Routine: ipc_thr_act_init
366 * Initialize an thr_act's IPC state.
372 ipc_thr_act_init(task_t task
, thread_act_t thr_act
)
374 ipc_port_t kport
; int i
;
376 kport
= ipc_port_alloc_kernel();
377 if (kport
== IP_NULL
)
378 panic("ipc_thr_act_init");
380 thr_act
->ith_self
= kport
;
381 thr_act
->ith_sself
= ipc_port_make_send(kport
);
383 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
384 thr_act
->exc_actions
[i
].port
= IP_NULL
;
386 ipc_kobject_set(kport
, (ipc_kobject_t
) thr_act
, IKOT_ACT
);
390 ipc_thr_act_disable(thread_act_t thr_act
)
395 kport
= thr_act
->ith_self
;
397 if (kport
!= IP_NULL
)
398 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
402 ipc_thr_act_terminate(thread_act_t thr_act
)
404 ipc_port_t kport
; int i
;
406 kport
= thr_act
->ith_self
;
408 if (kport
== IP_NULL
) {
409 /* the thread is already terminated (can this happen?) */
413 thr_act
->ith_self
= IP_NULL
;
415 /* release the naked send rights */
417 if (IP_VALID(thr_act
->ith_sself
))
418 ipc_port_release_send(thr_act
->ith_sself
);
419 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
420 if (IP_VALID(thr_act
->exc_actions
[i
].port
))
421 ipc_port_release_send(thr_act
->exc_actions
[i
].port
);
424 /* destroy the kernel port */
425 ipc_port_dealloc_kernel(kport
);
429 * Routine: retrieve_task_self_fast
431 * Optimized version of retrieve_task_self,
432 * that only works for the current task.
434 * Return a send right (possibly null/dead)
435 * for the task's user-visible self port.
441 retrieve_task_self_fast(
442 register task_t task
)
444 register ipc_port_t port
;
446 assert(task
== current_task());
449 assert(task
->itk_self
!= IP_NULL
);
451 if ((port
= task
->itk_sself
) == task
->itk_self
) {
455 assert(ip_active(port
));
460 port
= ipc_port_copy_send(port
);
467 * Routine: retrieve_act_self_fast
469 * Optimized version of retrieve_thread_self,
470 * that only works for the current thread.
472 * Return a send right (possibly null/dead)
473 * for the thread's user-visible self port.
479 retrieve_act_self_fast(thread_act_t thr_act
)
481 register ipc_port_t port
;
483 assert(thr_act
== current_act());
485 assert(thr_act
->ith_self
!= IP_NULL
);
487 if ((port
= thr_act
->ith_sself
) == thr_act
->ith_self
) {
491 assert(ip_active(port
));
496 port
= ipc_port_copy_send(port
);
503 * Routine: task_self_trap [mach trap]
505 * Give the caller send rights for his own task port.
509 * MACH_PORT_NULL if there are any resource failures
516 task_t task
= current_task();
519 sright
= retrieve_task_self_fast(task
);
520 return ipc_port_copyout_send(sright
, task
->itk_space
);
524 * Routine: thread_self_trap [mach trap]
526 * Give the caller send rights for his own thread port.
530 * MACH_PORT_NULL if there are any resource failures
535 thread_self_trap(void)
537 thread_act_t thr_act
= current_act();
538 task_t task
= thr_act
->task
;
541 sright
= retrieve_act_self_fast(thr_act
);
542 return ipc_port_copyout_send(sright
, task
->itk_space
);
546 * Routine: mach_reply_port [mach trap]
548 * Allocate a port for the caller.
552 * MACH_PORT_NULL if there are any resource failures
557 mach_reply_port(void)
560 mach_port_name_t name
;
563 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
564 if (kr
== KERN_SUCCESS
)
567 name
= MACH_PORT_NULL
;
573 * Routine: task_get_special_port [kernel call]
575 * Clones a send right for one of the task's
580 * KERN_SUCCESS Extracted a send right.
581 * KERN_INVALID_ARGUMENT The task is null.
582 * KERN_FAILURE The task/space is dead.
583 * KERN_INVALID_ARGUMENT Invalid special port.
587 task_get_special_port(
595 if (task
== TASK_NULL
)
596 return KERN_INVALID_ARGUMENT
;
599 case TASK_KERNEL_PORT
:
600 whichp
= &task
->itk_sself
;
604 whichp
= &task
->itk_host
;
607 case TASK_BOOTSTRAP_PORT
:
608 whichp
= &task
->itk_bootstrap
;
611 case TASK_WIRED_LEDGER_PORT
:
612 whichp
= &task
->wired_ledger_port
;
615 case TASK_PAGED_LEDGER_PORT
:
616 whichp
= &task
->paged_ledger_port
;
620 return KERN_INVALID_ARGUMENT
;
624 if (task
->itk_self
== IP_NULL
) {
629 port
= ipc_port_copy_send(*whichp
);
637 * Routine: task_set_special_port [kernel call]
639 * Changes one of the task's special ports,
640 * setting it to the supplied send right.
642 * Nothing locked. If successful, consumes
643 * the supplied send right.
645 * KERN_SUCCESS Changed the special port.
646 * KERN_INVALID_ARGUMENT The task is null.
647 * KERN_FAILURE The task/space is dead.
648 * KERN_INVALID_ARGUMENT Invalid special port.
652 task_set_special_port(
660 if (task
== TASK_NULL
)
661 return KERN_INVALID_ARGUMENT
;
664 case TASK_KERNEL_PORT
:
665 whichp
= &task
->itk_sself
;
669 whichp
= &task
->itk_host
;
672 case TASK_BOOTSTRAP_PORT
:
673 whichp
= &task
->itk_bootstrap
;
676 case TASK_WIRED_LEDGER_PORT
:
677 whichp
= &task
->wired_ledger_port
;
680 case TASK_PAGED_LEDGER_PORT
:
681 whichp
= &task
->paged_ledger_port
;
685 return KERN_INVALID_ARGUMENT
;
689 if (task
->itk_self
== IP_NULL
) {
699 ipc_port_release_send(old
);
705 * Routine: mach_ports_register [kernel call]
707 * Stash a handful of port send rights in the task.
708 * Child tasks will inherit these rights, but they
709 * must use mach_ports_lookup to acquire them.
711 * The rights are supplied in a (wired) kalloc'd segment.
712 * Rights which aren't supplied are assumed to be null.
714 * Nothing locked. If successful, consumes
715 * the supplied rights and memory.
717 * KERN_SUCCESS Stashed the port rights.
718 * KERN_INVALID_ARGUMENT The task is null.
719 * KERN_INVALID_ARGUMENT The task is dead.
720 * KERN_INVALID_ARGUMENT Too many port rights supplied.
726 mach_port_array_t memory
,
727 mach_msg_type_number_t portsCnt
)
729 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
732 if ((task
== TASK_NULL
) ||
733 (portsCnt
> TASK_PORT_REGISTER_MAX
))
734 return KERN_INVALID_ARGUMENT
;
737 * Pad the port rights with nulls.
740 for (i
= 0; i
< portsCnt
; i
++)
741 ports
[i
] = memory
[i
];
742 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
746 if (task
->itk_self
== IP_NULL
) {
748 return KERN_INVALID_ARGUMENT
;
752 * Replace the old send rights with the new.
753 * Release the old rights after unlocking.
756 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
759 old
= task
->itk_registered
[i
];
760 task
->itk_registered
[i
] = ports
[i
];
766 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
767 if (IP_VALID(ports
[i
]))
768 ipc_port_release_send(ports
[i
]);
771 * Now that the operation is known to be successful,
772 * we can free the memory.
776 kfree((vm_offset_t
) memory
,
777 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
783 * Routine: mach_ports_lookup [kernel call]
785 * Retrieves (clones) the stashed port send rights.
787 * Nothing locked. If successful, the caller gets
790 * KERN_SUCCESS Retrieved the send rights.
791 * KERN_INVALID_ARGUMENT The task is null.
792 * KERN_INVALID_ARGUMENT The task is dead.
793 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
799 mach_port_array_t
*portsp
,
800 mach_msg_type_number_t
*portsCnt
)
809 if (task
== TASK_NULL
)
810 return KERN_INVALID_ARGUMENT
;
812 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
814 memory
= kalloc(size
);
816 return KERN_RESOURCE_SHORTAGE
;
819 if (task
->itk_self
== IP_NULL
) {
823 return KERN_INVALID_ARGUMENT
;
826 ports
= (ipc_port_t
*) memory
;
829 * Clone port rights. Because kalloc'd memory
830 * is wired, we won't fault while holding the task lock.
833 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
834 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
838 *portsp
= (mach_port_array_t
) ports
;
839 *portsCnt
= TASK_PORT_REGISTER_MAX
;
844 * Routine: convert_port_to_locked_task
846 * Internal helper routine to convert from a port to a locked
847 * task. Used by several routines that try to convert from a
848 * task port to a reference on some task related object.
850 * Nothing locked, blocking OK.
853 convert_port_to_locked_task(ipc_port_t port
)
855 while (IP_VALID(port
)) {
859 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
863 task
= (task_t
) port
->ip_kobject
;
864 assert(task
!= TASK_NULL
);
867 * Normal lock ordering puts task_lock() before ip_lock().
868 * Attempt out-of-order locking here.
870 if (task_lock_try(task
)) {
882 * Routine: convert_port_to_task
884 * Convert from a port to a task.
885 * Doesn't consume the port ref; produces a task ref,
891 convert_port_to_task(
896 task
= convert_port_to_locked_task(port
);
905 * Routine: convert_port_to_space
907 * Convert from a port to a space.
908 * Doesn't consume the port ref; produces a space ref,
914 convert_port_to_space(
920 task
= convert_port_to_locked_task(port
);
922 if (task
== TASK_NULL
)
923 return IPC_SPACE_NULL
;
927 return IPC_SPACE_NULL
;
930 space
= task
->itk_space
;
943 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_UPL
)) {
947 upl
= (upl_t
) port
->ip_kobject
;
959 return MACH_PORT_NULL
;
962 __private_extern__
void
965 mach_port_mscount_t mscount
)
971 * Routine: convert_port_entry_to_map
973 * Convert from a port specifying an entry or a task
974 * to a map. Doesn't consume the port ref; produces a map ref,
975 * which may be null. Unlike convert_port_to_map, the
976 * port may be task or a named entry backed.
983 convert_port_entry_to_map(
988 vm_named_entry_t named_entry
;
990 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
993 if(ip_active(port
) && (ip_kotype(port
)
994 == IKOT_NAMED_ENTRY
)) {
996 (vm_named_entry_t
)port
->ip_kobject
;
997 if (!(mutex_try(&(named_entry
)->Lock
))) {
1002 named_entry
->ref_count
++;
1003 mutex_unlock(&(named_entry
)->Lock
);
1005 if ((named_entry
->is_sub_map
) &&
1006 (named_entry
->protection
1008 map
= named_entry
->backing
.map
;
1010 mach_destroy_memory_entry(port
);
1013 vm_map_reference_swap(map
);
1014 mach_destroy_memory_entry(port
);
1023 task
= convert_port_to_locked_task(port
);
1025 if (task
== TASK_NULL
)
1028 if (!task
->active
) {
1034 vm_map_reference_swap(map
);
1042 * Routine: convert_port_entry_to_object
1044 * Convert from a port specifying a named entry to an
1045 * object. Doesn't consume the port ref; produces a map ref,
1046 * which may be null.
1053 convert_port_entry_to_object(
1057 vm_named_entry_t named_entry
;
1059 if(IP_VALID(port
) && (ip_kotype(port
) == IKOT_NAMED_ENTRY
)) {
1062 if(ip_active(port
) && (ip_kotype(port
)
1063 == IKOT_NAMED_ENTRY
)) {
1065 (vm_named_entry_t
)port
->ip_kobject
;
1066 if (!(mutex_try(&(named_entry
)->Lock
))) {
1071 named_entry
->ref_count
++;
1072 mutex_unlock(&(named_entry
)->Lock
);
1074 if ((!named_entry
->is_sub_map
) &&
1075 (named_entry
->protection
1077 object
= named_entry
->object
;
1079 mach_destroy_memory_entry(port
);
1080 return (vm_object_t
)NULL
;
1082 vm_object_reference(named_entry
->object
);
1083 mach_destroy_memory_entry(port
);
1087 return (vm_object_t
)NULL
;
1090 return (vm_object_t
)NULL
;
1097 * Routine: convert_port_to_map
1099 * Convert from a port to a map.
1100 * Doesn't consume the port ref; produces a map ref,
1101 * which may be null.
1107 convert_port_to_map(
1113 task
= convert_port_to_locked_task(port
);
1115 if (task
== TASK_NULL
)
1118 if (!task
->active
) {
1124 vm_map_reference_swap(map
);
1131 * Routine: convert_port_to_act
1133 * Convert from a port to a thr_act.
1134 * Doesn't consume the port ref; produces an thr_act ref,
1135 * which may be null.
1141 convert_port_to_act( ipc_port_t port
)
1144 thread_act_t thr_act
= 0;
1147 while (!r
&& IP_VALID(port
)) {
1149 r
= ref_act_port_locked(port
, &thr_act
);
1156 ref_act_port_locked( ipc_port_t port
, thread_act_t
*pthr_act
)
1158 thread_act_t thr_act
;
1161 if (ip_active(port
) &&
1162 (ip_kotype(port
) == IKOT_ACT
)) {
1163 thr_act
= (thread_act_t
) port
->ip_kobject
;
1164 assert(thr_act
!= THR_ACT_NULL
);
1167 * Out of order locking here, normal
1168 * ordering is act_lock(), then ip_lock().
1170 if (!act_lock_try(thr_act
)) {
1175 act_reference_locked(thr_act
);
1176 act_unlock(thr_act
);
1178 *pthr_act
= thr_act
;
1184 * Routine: port_name_to_act
1186 * Convert from a port name to an act reference
1187 * A name of MACH_PORT_NULL is valid for the null act
1193 mach_port_name_t name
)
1195 thread_act_t thr_act
= THR_ACT_NULL
;
1196 ipc_port_t kern_port
;
1199 if (MACH_PORT_VALID(name
)) {
1200 kr
= ipc_object_copyin(current_space(), name
,
1201 MACH_MSG_TYPE_COPY_SEND
,
1202 (ipc_object_t
*) &kern_port
);
1203 if (kr
!= KERN_SUCCESS
)
1204 return THR_ACT_NULL
;
1206 thr_act
= convert_port_to_act(kern_port
);
1208 if (IP_VALID(kern_port
))
1209 ipc_port_release_send(kern_port
);
1216 mach_port_name_t name
)
1218 ipc_port_t kern_port
;
1220 task_t task
= TASK_NULL
;
1222 if (MACH_PORT_VALID(name
)) {
1223 kr
= ipc_object_copyin(current_space(), name
,
1224 MACH_MSG_TYPE_COPY_SEND
,
1225 (ipc_object_t
*) &kern_port
);
1226 if (kr
!= KERN_SUCCESS
)
1229 task
= convert_port_to_task(kern_port
);
1231 if (IP_VALID(kern_port
))
1232 ipc_port_release_send(kern_port
);
1238 * Routine: convert_task_to_port
1240 * Convert from a task to a port.
1241 * Consumes a task ref; produces a naked send right
1242 * which may be invalid.
1248 convert_task_to_port(
1254 if (task
->itk_self
!= IP_NULL
)
1256 if (task
->map
== VM_MAP_NULL
)
1257 /* norma placeholder task */
1258 port
= ipc_port_copy_send(task
->itk_self
);
1260 #endif /* NORMA_TASK */
1261 port
= ipc_port_make_send(task
->itk_self
);
1266 task_deallocate(task
);
1271 * Routine: convert_act_to_port
1273 * Convert from a thr_act to a port.
1274 * Consumes an thr_act ref; produces a naked send right
1275 * which may be invalid.
1281 convert_act_to_port(thr_act
)
1282 thread_act_t thr_act
;
1287 if (thr_act
->ith_self
!= IP_NULL
)
1288 port
= ipc_port_make_send(thr_act
->ith_self
);
1291 act_unlock(thr_act
);
1293 act_deallocate(thr_act
);
1298 * Routine: space_deallocate
1300 * Deallocate a space ref produced by convert_port_to_space.
1309 if (space
!= IS_NULL
)
1314 * Routine: thread/task_set_exception_ports [kernel call]
1316 * Sets the thread/task exception port, flavor and
1317 * behavior for the exception types specified by the mask.
1318 * There will be one send right per exception per valid
1321 * Nothing locked. If successful, consumes
1322 * the supplied send right.
1324 * KERN_SUCCESS Changed the special port.
1325 * KERN_INVALID_ARGUMENT The thread is null,
1326 * Illegal mask bit set.
1327 * Illegal exception behavior
1328 * KERN_FAILURE The thread is dead.
1332 thread_set_exception_ports(
1333 thread_act_t thr_act
,
1334 exception_mask_t exception_mask
,
1335 ipc_port_t new_port
,
1336 exception_behavior_t new_behavior
,
1337 thread_state_flavor_t new_flavor
)
1340 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1343 return KERN_INVALID_ARGUMENT
;
1345 if (exception_mask
& ~EXC_MASK_ALL
)
1346 return KERN_INVALID_ARGUMENT
;
1348 if (IP_VALID(new_port
)) {
1349 switch (new_behavior
) {
1350 case EXCEPTION_DEFAULT
:
1351 case EXCEPTION_STATE
:
1352 case EXCEPTION_STATE_IDENTITY
:
1355 return KERN_INVALID_ARGUMENT
;
1360 * Check the validity of the thread_state_flavor by calling the
1361 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1362 * osfmk/mach/ARCHITECTURE/thread_status.h
1364 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
)) {
1365 return KERN_INVALID_ARGUMENT
;
1369 if (!thr_act
->active
) {
1370 act_unlock(thr_act
);
1371 return KERN_FAILURE
;
1374 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1375 if (exception_mask
& (1 << i
)) {
1376 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1377 thr_act
->exc_actions
[i
].port
=
1378 ipc_port_copy_send(new_port
);
1379 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1380 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1382 old_port
[i
] = IP_NULL
;
1385 * Consume send rights without any lock held.
1387 act_unlock(thr_act
);
1388 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1389 if (IP_VALID(old_port
[i
]))
1390 ipc_port_release_send(old_port
[i
]);
1391 if (IP_VALID(new_port
)) /* consume send right */
1392 ipc_port_release_send(new_port
);
1394 return KERN_SUCCESS
;
1395 }/* thread_set_exception_port */
1398 task_set_exception_ports(
1400 exception_mask_t exception_mask
,
1401 ipc_port_t new_port
,
1402 exception_behavior_t new_behavior
,
1403 thread_state_flavor_t new_flavor
)
1406 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1408 if (task
== TASK_NULL
) {
1409 return KERN_INVALID_ARGUMENT
;
1412 if (exception_mask
& ~EXC_MASK_ALL
) {
1413 return KERN_INVALID_ARGUMENT
;
1416 if (IP_VALID(new_port
)) {
1417 switch (new_behavior
) {
1418 case EXCEPTION_DEFAULT
:
1419 case EXCEPTION_STATE
:
1420 case EXCEPTION_STATE_IDENTITY
:
1423 return KERN_INVALID_ARGUMENT
;
1426 /* Cannot easily check "new_flavor", but that just means that
1427 * the flavor in the generated exception message might be garbage:
1431 if (task
->itk_self
== IP_NULL
) {
1433 return KERN_FAILURE
;
1436 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1437 if (exception_mask
& (1 << i
)) {
1438 old_port
[i
] = task
->exc_actions
[i
].port
;
1439 task
->exc_actions
[i
].port
=
1440 ipc_port_copy_send(new_port
);
1441 task
->exc_actions
[i
].behavior
= new_behavior
;
1442 task
->exc_actions
[i
].flavor
= new_flavor
;
1444 old_port
[i
] = IP_NULL
;
1448 * Consume send rights without any lock held.
1451 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1452 if (IP_VALID(old_port
[i
]))
1453 ipc_port_release_send(old_port
[i
]);
1454 if (IP_VALID(new_port
)) /* consume send right */
1455 ipc_port_release_send(new_port
);
1457 return KERN_SUCCESS
;
1458 }/* task_set_exception_port */
1461 * Routine: thread/task_swap_exception_ports [kernel call]
1463 * Sets the thread/task exception port, flavor and
1464 * behavior for the exception types specified by the
1467 * The old ports, behavior and flavors are returned
1468 * Count specifies the array sizes on input and
1469 * the number of returned ports etc. on output. The
1470 * arrays must be large enough to hold all the returned
1471 * data, MIG returnes an error otherwise. The masks
1472 * array specifies the corresponding exception type(s).
1475 * Nothing locked. If successful, consumes
1476 * the supplied send right.
1478 * Returns upto [in} CountCnt elements.
1480 * KERN_SUCCESS Changed the special port.
1481 * KERN_INVALID_ARGUMENT The thread is null,
1482 * Illegal mask bit set.
1483 * Illegal exception behavior
1484 * KERN_FAILURE The thread is dead.
1488 thread_swap_exception_ports(
1489 thread_act_t thr_act
,
1490 exception_mask_t exception_mask
,
1491 ipc_port_t new_port
,
1492 exception_behavior_t new_behavior
,
1493 thread_state_flavor_t new_flavor
,
1494 exception_mask_array_t masks
,
1495 mach_msg_type_number_t
* CountCnt
,
1496 exception_port_array_t ports
,
1497 exception_behavior_array_t behaviors
,
1498 thread_state_flavor_array_t flavors
)
1503 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1506 return KERN_INVALID_ARGUMENT
;
1508 if (exception_mask
& ~EXC_MASK_ALL
) {
1509 return KERN_INVALID_ARGUMENT
;
1512 if (IP_VALID(new_port
)) {
1513 switch (new_behavior
) {
1514 case EXCEPTION_DEFAULT
:
1515 case EXCEPTION_STATE
:
1516 case EXCEPTION_STATE_IDENTITY
:
1519 return KERN_INVALID_ARGUMENT
;
1522 /* Cannot easily check "new_flavor", but that just means that
1523 * the flavor in the generated exception message might be garbage:
1527 if (!thr_act
->active
) {
1528 act_unlock(thr_act
);
1529 return KERN_FAILURE
;
1534 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1535 if (exception_mask
& (1 << i
)) {
1536 for (j
= 0; j
< count
; j
++) {
1538 * search for an identical entry, if found
1539 * set corresponding mask for this exception.
1541 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1542 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1543 && thr_act
->exc_actions
[i
].flavor
==flavors
[j
])
1545 masks
[j
] |= (1 << i
);
1550 masks
[j
] = (1 << i
);
1552 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1554 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1555 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1559 old_port
[i
] = thr_act
->exc_actions
[i
].port
;
1560 thr_act
->exc_actions
[i
].port
=
1561 ipc_port_copy_send(new_port
);
1562 thr_act
->exc_actions
[i
].behavior
= new_behavior
;
1563 thr_act
->exc_actions
[i
].flavor
= new_flavor
;
1564 if (count
> *CountCnt
) {
1568 old_port
[i
] = IP_NULL
;
1572 * Consume send rights without any lock held.
1574 act_unlock(thr_act
);
1575 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1576 if (IP_VALID(old_port
[i
]))
1577 ipc_port_release_send(old_port
[i
]);
1578 if (IP_VALID(new_port
)) /* consume send right */
1579 ipc_port_release_send(new_port
);
1581 return KERN_SUCCESS
;
1582 }/* thread_swap_exception_ports */
1585 task_swap_exception_ports(
1587 exception_mask_t exception_mask
,
1588 ipc_port_t new_port
,
1589 exception_behavior_t new_behavior
,
1590 thread_state_flavor_t new_flavor
,
1591 exception_mask_array_t masks
,
1592 mach_msg_type_number_t
* CountCnt
,
1593 exception_port_array_t ports
,
1594 exception_behavior_array_t behaviors
,
1595 thread_state_flavor_array_t flavors
)
1600 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1602 if (task
== TASK_NULL
)
1603 return KERN_INVALID_ARGUMENT
;
1605 if (exception_mask
& ~EXC_MASK_ALL
) {
1606 return KERN_INVALID_ARGUMENT
;
1609 if (IP_VALID(new_port
)) {
1610 switch (new_behavior
) {
1611 case EXCEPTION_DEFAULT
:
1612 case EXCEPTION_STATE
:
1613 case EXCEPTION_STATE_IDENTITY
:
1616 return KERN_INVALID_ARGUMENT
;
1619 /* Cannot easily check "new_flavor", but that just means that
1620 * the flavor in the generated exception message might be garbage:
1624 if (task
->itk_self
== IP_NULL
) {
1626 return KERN_FAILURE
;
1631 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1632 if (exception_mask
& (1 << i
)) {
1633 for (j
= 0; j
< count
; j
++) {
1635 * search for an identical entry, if found
1636 * set corresponding mask for this exception.
1638 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1639 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1640 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1642 masks
[j
] |= (1 << i
);
1647 masks
[j
] = (1 << i
);
1649 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1650 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1651 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1654 old_port
[i
] = task
->exc_actions
[i
].port
;
1655 task
->exc_actions
[i
].port
=
1656 ipc_port_copy_send(new_port
);
1657 task
->exc_actions
[i
].behavior
= new_behavior
;
1658 task
->exc_actions
[i
].flavor
= new_flavor
;
1659 if (count
> *CountCnt
) {
1663 old_port
[i
] = IP_NULL
;
1668 * Consume send rights without any lock held.
1671 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1672 if (IP_VALID(old_port
[i
]))
1673 ipc_port_release_send(old_port
[i
]);
1674 if (IP_VALID(new_port
)) /* consume send right */
1675 ipc_port_release_send(new_port
);
1678 return KERN_SUCCESS
;
1679 }/* task_swap_exception_ports */
1682 * Routine: thread/task_get_exception_ports [kernel call]
1684 * Clones a send right for each of the thread/task's exception
1685 * ports specified in the mask and returns the behaviour
1686 * and flavor of said port.
1688 * Returns upto [in} CountCnt elements.
1693 * KERN_SUCCESS Extracted a send right.
1694 * KERN_INVALID_ARGUMENT The thread is null,
1695 * Invalid special port,
1696 * Illegal mask bit set.
1697 * KERN_FAILURE The thread is dead.
1701 thread_get_exception_ports(
1702 thread_act_t thr_act
,
1703 exception_mask_t exception_mask
,
1704 exception_mask_array_t masks
,
1705 mach_msg_type_number_t
* CountCnt
,
1706 exception_port_array_t ports
,
1707 exception_behavior_array_t behaviors
,
1708 thread_state_flavor_array_t flavors
)
1715 return KERN_INVALID_ARGUMENT
;
1717 if (exception_mask
& ~EXC_MASK_ALL
) {
1718 return KERN_INVALID_ARGUMENT
;
1722 if (!thr_act
->active
) {
1723 act_unlock(thr_act
);
1724 return KERN_FAILURE
;
1729 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1730 if (exception_mask
& (1 << i
)) {
1731 for (j
= 0; j
< count
; j
++) {
1733 * search for an identical entry, if found
1734 * set corresponding mask for this exception.
1736 if (thr_act
->exc_actions
[i
].port
== ports
[j
] &&
1737 thr_act
->exc_actions
[i
].behavior
==behaviors
[j
]
1738 && thr_act
->exc_actions
[i
].flavor
== flavors
[j
])
1740 masks
[j
] |= (1 << i
);
1745 masks
[j
] = (1 << i
);
1747 ipc_port_copy_send(thr_act
->exc_actions
[i
].port
);
1748 behaviors
[j
] = thr_act
->exc_actions
[i
].behavior
;
1749 flavors
[j
] = thr_act
->exc_actions
[i
].flavor
;
1751 if (count
>= *CountCnt
) {
1758 act_unlock(thr_act
);
1761 return KERN_SUCCESS
;
1762 }/* thread_get_exception_ports */
1765 task_get_exception_ports(
1767 exception_mask_t exception_mask
,
1768 exception_mask_array_t masks
,
1769 mach_msg_type_number_t
* CountCnt
,
1770 exception_port_array_t ports
,
1771 exception_behavior_array_t behaviors
,
1772 thread_state_flavor_array_t flavors
)
1778 if (task
== TASK_NULL
)
1779 return KERN_INVALID_ARGUMENT
;
1781 if (exception_mask
& ~EXC_MASK_ALL
) {
1782 return KERN_INVALID_ARGUMENT
;
1786 if (task
->itk_self
== IP_NULL
) {
1788 return KERN_FAILURE
;
1793 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
1794 if (exception_mask
& (1 << i
)) {
1795 for (j
= 0; j
< count
; j
++) {
1797 * search for an identical entry, if found
1798 * set corresponding mask for this exception.
1800 if (task
->exc_actions
[i
].port
== ports
[j
] &&
1801 task
->exc_actions
[i
].behavior
== behaviors
[j
]
1802 && task
->exc_actions
[i
].flavor
== flavors
[j
])
1804 masks
[j
] |= (1 << i
);
1809 masks
[j
] = (1 << i
);
1811 ipc_port_copy_send(task
->exc_actions
[i
].port
);
1812 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1813 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1815 if (count
> *CountCnt
) {
1825 return KERN_SUCCESS
;
1826 }/* task_get_exception_ports */