2 * Copyright (c) 2000-2004 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>
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/memory_object_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/host_priv_server.h>
73 #include <mach/vm_map_server.h>
75 #include <kern/kern_types.h>
76 #include <kern/host.h>
77 #include <kern/ipc_kobject.h>
78 #include <kern/ipc_tt.h>
79 #include <kern/kalloc.h>
80 #include <kern/thread.h>
81 #include <kern/misc_protos.h>
83 #include <vm/vm_map.h>
84 #include <vm/vm_pageout.h>
85 #include <vm/vm_shared_memory_server.h>
86 #include <vm/vm_protos.h>
88 /* forward declarations */
89 task_t
convert_port_to_locked_task(ipc_port_t port
);
93 * Routine: ipc_task_init
95 * Initialize a task's IPC state.
97 * If non-null, some state will be inherited from the parent.
98 * The parent must be appropriately initialized.
115 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
116 if (kr
!= KERN_SUCCESS
)
117 panic("ipc_task_init");
120 kport
= ipc_port_alloc_kernel();
121 if (kport
== IP_NULL
)
122 panic("ipc_task_init");
124 nport
= ipc_port_alloc_kernel();
125 if (nport
== IP_NULL
)
126 panic("ipc_task_init");
129 task
->itk_self
= kport
;
130 task
->itk_nself
= nport
;
131 task
->itk_sself
= ipc_port_make_send(kport
);
132 task
->itk_space
= space
;
133 space
->is_fast
= FALSE
;
135 if (parent
== TASK_NULL
) {
138 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
139 task
->exc_actions
[i
].port
= IP_NULL
;
142 kr
= host_get_host_port(host_priv_self(), &port
);
143 assert(kr
== KERN_SUCCESS
);
144 task
->itk_host
= port
;
146 task
->itk_bootstrap
= IP_NULL
;
148 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
149 task
->itk_registered
[i
] = IP_NULL
;
152 assert(parent
->itk_self
!= IP_NULL
);
154 /* inherit registered ports */
156 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
157 task
->itk_registered
[i
] =
158 ipc_port_copy_send(parent
->itk_registered
[i
]);
160 /* inherit exception and bootstrap ports */
162 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
163 task
->exc_actions
[i
].port
=
164 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
165 task
->exc_actions
[i
].flavor
=
166 parent
->exc_actions
[i
].flavor
;
167 task
->exc_actions
[i
].behavior
=
168 parent
->exc_actions
[i
].behavior
;
171 ipc_port_copy_send(parent
->itk_host
);
173 task
->itk_bootstrap
=
174 ipc_port_copy_send(parent
->itk_bootstrap
);
181 * Routine: ipc_task_enable
183 * Enable a task for IPC access.
196 kport
= task
->itk_self
;
197 if (kport
!= IP_NULL
)
198 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
199 nport
= task
->itk_nself
;
200 if (nport
!= IP_NULL
)
201 ipc_kobject_set(nport
, (ipc_kobject_t
) task
, IKOT_TASK_NAME
);
206 * Routine: ipc_task_disable
208 * Disable IPC access to a task.
221 kport
= task
->itk_self
;
222 if (kport
!= IP_NULL
)
223 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
224 nport
= task
->itk_nself
;
225 if (nport
!= IP_NULL
)
226 ipc_kobject_set(nport
, IKO_NULL
, IKOT_NONE
);
231 * Routine: ipc_task_terminate
233 * Clean up and destroy a task's IPC state.
235 * Nothing locked. The task must be suspended.
236 * (Or the current thread must be in the task.)
248 kport
= task
->itk_self
;
250 if (kport
== IP_NULL
) {
251 /* the task is already terminated (can this happen?) */
255 task
->itk_self
= IP_NULL
;
257 nport
= task
->itk_nself
;
258 assert(nport
!= IP_NULL
);
259 task
->itk_nself
= IP_NULL
;
263 /* release the naked send rights */
265 if (IP_VALID(task
->itk_sself
))
266 ipc_port_release_send(task
->itk_sself
);
268 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
269 if (IP_VALID(task
->exc_actions
[i
].port
)) {
270 ipc_port_release_send(task
->exc_actions
[i
].port
);
274 if (IP_VALID(task
->itk_host
))
275 ipc_port_release_send(task
->itk_host
);
277 if (IP_VALID(task
->itk_bootstrap
))
278 ipc_port_release_send(task
->itk_bootstrap
);
280 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
281 if (IP_VALID(task
->itk_registered
[i
]))
282 ipc_port_release_send(task
->itk_registered
[i
]);
284 ipc_port_release_send(task
->wired_ledger_port
);
285 ipc_port_release_send(task
->paged_ledger_port
);
287 /* destroy the kernel ports */
288 ipc_port_dealloc_kernel(kport
);
289 ipc_port_dealloc_kernel(nport
);
293 * Routine: ipc_task_reset
295 * Reset a task's IPC state to protect it when
296 * it enters an elevated security context. The
297 * task name port can remain the same - since
298 * it represents no specific privilege.
300 * Nothing locked. The task must be suspended.
301 * (Or the current thread must be in the task.)
308 ipc_port_t old_kport
, new_kport
;
309 ipc_port_t old_sself
;
311 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
315 new_kport
= ipc_port_alloc_kernel();
316 if (new_kport
== IP_NULL
)
317 panic("ipc_task_reset");
321 old_kport
= task
->itk_self
;
323 if (old_kport
== IP_NULL
) {
324 /* the task is already terminated (can this happen?) */
326 ipc_port_dealloc_kernel(new_kport
);
330 task
->itk_self
= new_kport
;
331 old_sself
= task
->itk_sself
;
332 task
->itk_sself
= ipc_port_make_send(new_kport
);
333 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
334 ipc_kobject_set(new_kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
337 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
338 old_exc_actions
[i
] = task
->exc_action
[i
].port
;
339 task
->exc_actions
[i
].port
= IP_NULL
;
345 /* release the naked send rights */
347 if (IP_VALID(old_sself
))
348 ipc_port_release_send(old_sself
);
351 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
352 if (IP_VALID(old_exc_actions
[i
])) {
353 ipc_port_release_send(old_exc_actions
[i
]);
358 /* destroy the kernel port */
359 ipc_port_dealloc_kernel(old_kport
);
363 * Routine: ipc_thread_init
365 * Initialize a thread's IPC state.
377 kport
= ipc_port_alloc_kernel();
378 if (kport
== IP_NULL
)
379 panic("ipc_thread_init");
381 thread
->ith_self
= kport
;
382 thread
->ith_sself
= ipc_port_make_send(kport
);
384 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
385 thread
->exc_actions
[i
].port
= IP_NULL
;
387 ipc_kobject_set(kport
, (ipc_kobject_t
)thread
, IKOT_THREAD
);
389 ipc_kmsg_queue_init(&thread
->ith_messages
);
391 thread
->ith_rpc_reply
= IP_NULL
;
398 ipc_port_t kport
= thread
->ith_self
;
400 if (kport
!= IP_NULL
)
401 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
405 * Routine: ipc_thread_terminate
407 * Clean up and destroy a thread's IPC state.
413 ipc_thread_terminate(
416 ipc_port_t kport
= thread
->ith_self
;
418 if (kport
!= IP_NULL
) {
421 if (IP_VALID(thread
->ith_sself
))
422 ipc_port_release_send(thread
->ith_sself
);
424 thread
->ith_sself
= thread
->ith_self
= IP_NULL
;
426 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
427 if (IP_VALID(thread
->exc_actions
[i
].port
))
428 ipc_port_release_send(thread
->exc_actions
[i
].port
);
431 ipc_port_dealloc_kernel(kport
);
434 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
436 if (thread
->ith_rpc_reply
!= IP_NULL
)
437 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
439 thread
->ith_rpc_reply
= IP_NULL
;
443 * Routine: retrieve_task_self_fast
445 * Optimized version of retrieve_task_self,
446 * that only works for the current task.
448 * Return a send right (possibly null/dead)
449 * for the task's user-visible self port.
455 retrieve_task_self_fast(
456 register task_t task
)
458 register ipc_port_t port
;
460 assert(task
== current_task());
463 assert(task
->itk_self
!= IP_NULL
);
465 if ((port
= task
->itk_sself
) == task
->itk_self
) {
469 assert(ip_active(port
));
474 port
= ipc_port_copy_send(port
);
481 * Routine: retrieve_thread_self_fast
483 * Return a send right (possibly null/dead)
484 * for the thread's user-visible self port.
486 * Only works for the current thread.
493 retrieve_thread_self_fast(
496 register ipc_port_t port
;
498 assert(thread
== current_thread());
500 thread_mtx_lock(thread
);
502 assert(thread
->ith_self
!= IP_NULL
);
504 if ((port
= thread
->ith_sself
) == thread
->ith_self
) {
508 assert(ip_active(port
));
514 port
= ipc_port_copy_send(port
);
516 thread_mtx_unlock(thread
);
522 * Routine: task_self_trap [mach trap]
524 * Give the caller send rights for his own task port.
528 * MACH_PORT_NULL if there are any resource failures
534 __unused
struct task_self_trap_args
*args
)
536 task_t task
= current_task();
538 mach_port_name_t name
;
540 sright
= retrieve_task_self_fast(task
);
541 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
546 * Routine: thread_self_trap [mach trap]
548 * Give the caller send rights for his own thread port.
552 * MACH_PORT_NULL if there are any resource failures
558 __unused
struct thread_self_trap_args
*args
)
560 thread_t thread
= current_thread();
561 task_t task
= thread
->task
;
563 mach_port_name_t name
;
565 sright
= retrieve_thread_self_fast(thread
);
566 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
572 * Routine: mach_reply_port [mach trap]
574 * Allocate a port for the caller.
578 * MACH_PORT_NULL if there are any resource failures
584 __unused
struct mach_reply_port_args
*args
)
587 mach_port_name_t name
;
590 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
591 if (kr
== KERN_SUCCESS
)
594 name
= MACH_PORT_NULL
;
599 * Routine: thread_get_special_port [kernel call]
601 * Clones a send right for one of the thread's
606 * KERN_SUCCESS Extracted a send right.
607 * KERN_INVALID_ARGUMENT The thread is null.
608 * KERN_FAILURE The thread is dead.
609 * KERN_INVALID_ARGUMENT Invalid special port.
613 thread_get_special_port(
618 kern_return_t result
= KERN_SUCCESS
;
621 if (thread
== THREAD_NULL
)
622 return (KERN_INVALID_ARGUMENT
);
626 case THREAD_KERNEL_PORT
:
627 whichp
= &thread
->ith_sself
;
631 return (KERN_INVALID_ARGUMENT
);
634 thread_mtx_lock(thread
);
637 *portp
= ipc_port_copy_send(*whichp
);
639 result
= KERN_FAILURE
;
641 thread_mtx_unlock(thread
);
647 * Routine: thread_set_special_port [kernel call]
649 * Changes one of the thread's special ports,
650 * setting it to the supplied send right.
652 * Nothing locked. If successful, consumes
653 * the supplied send right.
655 * KERN_SUCCESS Changed the special port.
656 * KERN_INVALID_ARGUMENT The thread is null.
657 * KERN_FAILURE The thread is dead.
658 * KERN_INVALID_ARGUMENT Invalid special port.
662 thread_set_special_port(
667 kern_return_t result
= KERN_SUCCESS
;
668 ipc_port_t
*whichp
, old
= IP_NULL
;
670 if (thread
== THREAD_NULL
)
671 return (KERN_INVALID_ARGUMENT
);
675 case THREAD_KERNEL_PORT
:
676 whichp
= &thread
->ith_sself
;
680 return (KERN_INVALID_ARGUMENT
);
683 thread_mtx_lock(thread
);
685 if (thread
->active
) {
690 result
= KERN_FAILURE
;
692 thread_mtx_unlock(thread
);
695 ipc_port_release_send(old
);
701 * Routine: task_get_special_port [kernel call]
703 * Clones a send right for one of the task's
708 * KERN_SUCCESS Extracted a send right.
709 * KERN_INVALID_ARGUMENT The task is null.
710 * KERN_FAILURE The task/space is dead.
711 * KERN_INVALID_ARGUMENT Invalid special port.
715 task_get_special_port(
722 if (task
== TASK_NULL
)
723 return KERN_INVALID_ARGUMENT
;
726 if (task
->itk_self
== IP_NULL
) {
732 case TASK_KERNEL_PORT
:
733 port
= ipc_port_copy_send(task
->itk_sself
);
737 port
= ipc_port_make_send(task
->itk_nself
);
741 port
= ipc_port_copy_send(task
->itk_host
);
744 case TASK_BOOTSTRAP_PORT
:
745 port
= ipc_port_copy_send(task
->itk_bootstrap
);
748 case TASK_WIRED_LEDGER_PORT
:
749 port
= ipc_port_copy_send(task
->wired_ledger_port
);
752 case TASK_PAGED_LEDGER_PORT
:
753 port
= ipc_port_copy_send(task
->paged_ledger_port
);
757 return KERN_INVALID_ARGUMENT
;
766 * Routine: task_set_special_port [kernel call]
768 * Changes one of the task's special ports,
769 * setting it to the supplied send right.
771 * Nothing locked. If successful, consumes
772 * the supplied send right.
774 * KERN_SUCCESS Changed the special port.
775 * KERN_INVALID_ARGUMENT The task is null.
776 * KERN_FAILURE The task/space is dead.
777 * KERN_INVALID_ARGUMENT Invalid special port.
781 task_set_special_port(
789 if (task
== TASK_NULL
)
790 return KERN_INVALID_ARGUMENT
;
793 case TASK_KERNEL_PORT
:
794 whichp
= &task
->itk_sself
;
798 whichp
= &task
->itk_host
;
801 case TASK_BOOTSTRAP_PORT
:
802 whichp
= &task
->itk_bootstrap
;
805 case TASK_WIRED_LEDGER_PORT
:
806 whichp
= &task
->wired_ledger_port
;
809 case TASK_PAGED_LEDGER_PORT
:
810 whichp
= &task
->paged_ledger_port
;
814 return KERN_INVALID_ARGUMENT
;
818 if (task
->itk_self
== IP_NULL
) {
828 ipc_port_release_send(old
);
834 * Routine: mach_ports_register [kernel call]
836 * Stash a handful of port send rights in the task.
837 * Child tasks will inherit these rights, but they
838 * must use mach_ports_lookup to acquire them.
840 * The rights are supplied in a (wired) kalloc'd segment.
841 * Rights which aren't supplied are assumed to be null.
843 * Nothing locked. If successful, consumes
844 * the supplied rights and memory.
846 * KERN_SUCCESS Stashed the port rights.
847 * KERN_INVALID_ARGUMENT The task is null.
848 * KERN_INVALID_ARGUMENT The task is dead.
849 * KERN_INVALID_ARGUMENT Too many port rights supplied.
855 mach_port_array_t memory
,
856 mach_msg_type_number_t portsCnt
)
858 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
861 if ((task
== TASK_NULL
) ||
862 (portsCnt
> TASK_PORT_REGISTER_MAX
))
863 return KERN_INVALID_ARGUMENT
;
866 * Pad the port rights with nulls.
869 for (i
= 0; i
< portsCnt
; i
++)
870 ports
[i
] = memory
[i
];
871 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
875 if (task
->itk_self
== IP_NULL
) {
877 return KERN_INVALID_ARGUMENT
;
881 * Replace the old send rights with the new.
882 * Release the old rights after unlocking.
885 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
888 old
= task
->itk_registered
[i
];
889 task
->itk_registered
[i
] = ports
[i
];
895 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
896 if (IP_VALID(ports
[i
]))
897 ipc_port_release_send(ports
[i
]);
900 * Now that the operation is known to be successful,
901 * we can free the memory.
906 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
912 * Routine: mach_ports_lookup [kernel call]
914 * Retrieves (clones) the stashed port send rights.
916 * Nothing locked. If successful, the caller gets
919 * KERN_SUCCESS Retrieved the send rights.
920 * KERN_INVALID_ARGUMENT The task is null.
921 * KERN_INVALID_ARGUMENT The task is dead.
922 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
928 mach_port_array_t
*portsp
,
929 mach_msg_type_number_t
*portsCnt
)
936 if (task
== TASK_NULL
)
937 return KERN_INVALID_ARGUMENT
;
939 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
941 memory
= kalloc(size
);
943 return KERN_RESOURCE_SHORTAGE
;
946 if (task
->itk_self
== IP_NULL
) {
950 return KERN_INVALID_ARGUMENT
;
953 ports
= (ipc_port_t
*) memory
;
956 * Clone port rights. Because kalloc'd memory
957 * is wired, we won't fault while holding the task lock.
960 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
961 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
965 *portsp
= (mach_port_array_t
) ports
;
966 *portsCnt
= TASK_PORT_REGISTER_MAX
;
971 * Routine: convert_port_to_locked_task
973 * Internal helper routine to convert from a port to a locked
974 * task. Used by several routines that try to convert from a
975 * task port to a reference on some task related object.
977 * Nothing locked, blocking OK.
980 convert_port_to_locked_task(ipc_port_t port
)
982 while (IP_VALID(port
)) {
986 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
990 task
= (task_t
) port
->ip_kobject
;
991 assert(task
!= TASK_NULL
);
994 * Normal lock ordering puts task_lock() before ip_lock().
995 * Attempt out-of-order locking here.
997 if (task_lock_try(task
)) {
1009 * Routine: convert_port_to_task
1011 * Convert from a port to a task.
1012 * Doesn't consume the port ref; produces a task ref,
1013 * which may be null.
1018 convert_port_to_task(
1021 task_t task
= TASK_NULL
;
1023 if (IP_VALID(port
)) {
1026 if ( ip_active(port
) &&
1027 ip_kotype(port
) == IKOT_TASK
) {
1028 task
= (task_t
)port
->ip_kobject
;
1029 assert(task
!= TASK_NULL
);
1031 task_reference_internal(task
);
1041 * Routine: convert_port_to_task_name
1043 * Convert from a port to a task name.
1044 * Doesn't consume the port ref; produces a task name ref,
1045 * which may be null.
1050 convert_port_to_task_name(
1053 task_name_t task
= TASK_NULL
;
1055 if (IP_VALID(port
)) {
1058 if ( ip_active(port
) &&
1059 (ip_kotype(port
) == IKOT_TASK
||
1060 ip_kotype(port
) == IKOT_TASK_NAME
)) {
1061 task
= (task_name_t
)port
->ip_kobject
;
1062 assert(task
!= TASK_NAME_NULL
);
1064 task_reference_internal(task
);
1074 * Routine: convert_port_to_space
1076 * Convert from a port to a space.
1077 * Doesn't consume the port ref; produces a space ref,
1078 * which may be null.
1083 convert_port_to_space(
1089 task
= convert_port_to_locked_task(port
);
1091 if (task
== TASK_NULL
)
1092 return IPC_SPACE_NULL
;
1094 if (!task
->active
) {
1096 return IPC_SPACE_NULL
;
1099 space
= task
->itk_space
;
1100 is_reference(space
);
1106 * Routine: convert_port_to_map
1108 * Convert from a port to a map.
1109 * Doesn't consume the port ref; produces a map ref,
1110 * which may be null.
1116 convert_port_to_map(
1122 task
= convert_port_to_locked_task(port
);
1124 if (task
== TASK_NULL
)
1127 if (!task
->active
) {
1133 vm_map_reference_swap(map
);
1140 * Routine: convert_port_to_thread
1142 * Convert from a port to a thread.
1143 * Doesn't consume the port ref; produces an thread ref,
1144 * which may be null.
1150 convert_port_to_thread(
1153 thread_t thread
= THREAD_NULL
;
1155 if (IP_VALID(port
)) {
1158 if ( ip_active(port
) &&
1159 ip_kotype(port
) == IKOT_THREAD
) {
1160 thread
= (thread_t
)port
->ip_kobject
;
1161 assert(thread
!= THREAD_NULL
);
1163 thread_reference_internal(thread
);
1173 * Routine: port_name_to_thread
1175 * Convert from a port name to an thread reference
1176 * A name of MACH_PORT_NULL is valid for the null thread.
1181 port_name_to_thread(
1182 mach_port_name_t name
)
1184 thread_t thread
= THREAD_NULL
;
1187 if (MACH_PORT_VALID(name
)) {
1188 if (ipc_object_copyin(current_space(), name
,
1189 MACH_MSG_TYPE_COPY_SEND
,
1190 (ipc_object_t
*)&kport
) != KERN_SUCCESS
)
1191 return (THREAD_NULL
);
1193 thread
= convert_port_to_thread(kport
);
1195 if (IP_VALID(kport
))
1196 ipc_port_release_send(kport
);
1204 mach_port_name_t name
)
1206 ipc_port_t kern_port
;
1208 task_t task
= TASK_NULL
;
1210 if (MACH_PORT_VALID(name
)) {
1211 kr
= ipc_object_copyin(current_space(), name
,
1212 MACH_MSG_TYPE_COPY_SEND
,
1213 (ipc_object_t
*) &kern_port
);
1214 if (kr
!= KERN_SUCCESS
)
1217 task
= convert_port_to_task(kern_port
);
1219 if (IP_VALID(kern_port
))
1220 ipc_port_release_send(kern_port
);
1226 * Routine: convert_task_to_port
1228 * Convert from a task to a port.
1229 * Consumes a task ref; produces a naked send right
1230 * which may be invalid.
1236 convert_task_to_port(
1242 if (task
->itk_self
!= IP_NULL
)
1243 port
= ipc_port_make_send(task
->itk_self
);
1248 task_deallocate(task
);
1253 * Routine: convert_task_name_to_port
1255 * Convert from a task name ref to a port.
1256 * Consumes a task name ref; produces a naked send right
1257 * which may be invalid.
1263 convert_task_name_to_port(
1264 task_name_t task_name
)
1268 itk_lock(task_name
);
1269 if (task_name
->itk_nself
!= IP_NULL
)
1270 port
= ipc_port_make_send(task_name
->itk_nself
);
1273 itk_unlock(task_name
);
1275 task_name_deallocate(task_name
);
1280 * Routine: convert_thread_to_port
1282 * Convert from a thread to a port.
1283 * Consumes an thread ref; produces a naked send right
1284 * which may be invalid.
1290 convert_thread_to_port(
1295 thread_mtx_lock(thread
);
1297 if (thread
->ith_self
!= IP_NULL
)
1298 port
= ipc_port_make_send(thread
->ith_self
);
1302 thread_mtx_unlock(thread
);
1304 thread_deallocate(thread
);
1310 * Routine: space_deallocate
1312 * Deallocate a space ref produced by convert_port_to_space.
1321 if (space
!= IS_NULL
)
1326 * Routine: thread/task_set_exception_ports [kernel call]
1328 * Sets the thread/task exception port, flavor and
1329 * behavior for the exception types specified by the mask.
1330 * There will be one send right per exception per valid
1333 * Nothing locked. If successful, consumes
1334 * the supplied send right.
1336 * KERN_SUCCESS Changed the special port.
1337 * KERN_INVALID_ARGUMENT The thread is null,
1338 * Illegal mask bit set.
1339 * Illegal exception behavior
1340 * KERN_FAILURE The thread is dead.
1344 thread_set_exception_ports(
1346 exception_mask_t exception_mask
,
1347 ipc_port_t new_port
,
1348 exception_behavior_t new_behavior
,
1349 thread_state_flavor_t new_flavor
)
1351 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1354 if (thread
== THREAD_NULL
)
1355 return (KERN_INVALID_ARGUMENT
);
1357 if (exception_mask
& ~EXC_MASK_ALL
)
1358 return (KERN_INVALID_ARGUMENT
);
1360 if (IP_VALID(new_port
)) {
1361 switch (new_behavior
) {
1363 case EXCEPTION_DEFAULT
:
1364 case EXCEPTION_STATE
:
1365 case EXCEPTION_STATE_IDENTITY
:
1369 return (KERN_INVALID_ARGUMENT
);
1374 * Check the validity of the thread_state_flavor by calling the
1375 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1376 * osfmk/mach/ARCHITECTURE/thread_status.h
1378 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
))
1379 return (KERN_INVALID_ARGUMENT
);
1381 thread_mtx_lock(thread
);
1383 if (!thread
->active
) {
1384 thread_mtx_unlock(thread
);
1386 return (KERN_FAILURE
);
1389 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1390 if (exception_mask
& (1 << i
)) {
1391 old_port
[i
] = thread
->exc_actions
[i
].port
;
1392 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1393 thread
->exc_actions
[i
].behavior
= new_behavior
;
1394 thread
->exc_actions
[i
].flavor
= new_flavor
;
1397 old_port
[i
] = IP_NULL
;
1400 thread_mtx_unlock(thread
);
1402 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1403 if (IP_VALID(old_port
[i
]))
1404 ipc_port_release_send(old_port
[i
]);
1406 if (IP_VALID(new_port
)) /* consume send right */
1407 ipc_port_release_send(new_port
);
1409 return (KERN_SUCCESS
);
1413 task_set_exception_ports(
1415 exception_mask_t exception_mask
,
1416 ipc_port_t new_port
,
1417 exception_behavior_t new_behavior
,
1418 thread_state_flavor_t new_flavor
)
1420 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1423 if (task
== TASK_NULL
)
1424 return (KERN_INVALID_ARGUMENT
);
1426 if (exception_mask
& ~EXC_MASK_ALL
)
1427 return (KERN_INVALID_ARGUMENT
);
1429 if (IP_VALID(new_port
)) {
1430 switch (new_behavior
) {
1432 case EXCEPTION_DEFAULT
:
1433 case EXCEPTION_STATE
:
1434 case EXCEPTION_STATE_IDENTITY
:
1438 return (KERN_INVALID_ARGUMENT
);
1444 if (task
->itk_self
== IP_NULL
) {
1447 return (KERN_FAILURE
);
1450 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1451 if (exception_mask
& (1 << i
)) {
1452 old_port
[i
] = task
->exc_actions
[i
].port
;
1453 task
->exc_actions
[i
].port
=
1454 ipc_port_copy_send(new_port
);
1455 task
->exc_actions
[i
].behavior
= new_behavior
;
1456 task
->exc_actions
[i
].flavor
= new_flavor
;
1459 old_port
[i
] = IP_NULL
;
1464 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1465 if (IP_VALID(old_port
[i
]))
1466 ipc_port_release_send(old_port
[i
]);
1468 if (IP_VALID(new_port
)) /* consume send right */
1469 ipc_port_release_send(new_port
);
1471 return (KERN_SUCCESS
);
1475 * Routine: thread/task_swap_exception_ports [kernel call]
1477 * Sets the thread/task exception port, flavor and
1478 * behavior for the exception types specified by the
1481 * The old ports, behavior and flavors are returned
1482 * Count specifies the array sizes on input and
1483 * the number of returned ports etc. on output. The
1484 * arrays must be large enough to hold all the returned
1485 * data, MIG returnes an error otherwise. The masks
1486 * array specifies the corresponding exception type(s).
1489 * Nothing locked. If successful, consumes
1490 * the supplied send right.
1492 * Returns upto [in} CountCnt elements.
1494 * KERN_SUCCESS Changed the special port.
1495 * KERN_INVALID_ARGUMENT The thread is null,
1496 * Illegal mask bit set.
1497 * Illegal exception behavior
1498 * KERN_FAILURE The thread is dead.
1502 thread_swap_exception_ports(
1504 exception_mask_t exception_mask
,
1505 ipc_port_t new_port
,
1506 exception_behavior_t new_behavior
,
1507 thread_state_flavor_t new_flavor
,
1508 exception_mask_array_t masks
,
1509 mach_msg_type_number_t
*CountCnt
,
1510 exception_port_array_t ports
,
1511 exception_behavior_array_t behaviors
,
1512 thread_state_flavor_array_t flavors
)
1514 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1515 unsigned int i
, j
, count
;
1517 if (thread
== THREAD_NULL
)
1518 return (KERN_INVALID_ARGUMENT
);
1520 if (exception_mask
& ~EXC_MASK_ALL
)
1521 return (KERN_INVALID_ARGUMENT
);
1523 if (IP_VALID(new_port
)) {
1524 switch (new_behavior
) {
1526 case EXCEPTION_DEFAULT
:
1527 case EXCEPTION_STATE
:
1528 case EXCEPTION_STATE_IDENTITY
:
1532 return (KERN_INVALID_ARGUMENT
);
1536 thread_mtx_lock(thread
);
1538 if (!thread
->active
) {
1539 thread_mtx_unlock(thread
);
1541 return (KERN_FAILURE
);
1546 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1547 if (exception_mask
& (1 << i
)) {
1548 for (j
= 0; j
< count
; ++j
) {
1550 * search for an identical entry, if found
1551 * set corresponding mask for this exception.
1553 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1554 thread
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1555 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1556 masks
[j
] |= (1 << i
);
1562 masks
[j
] = (1 << i
);
1563 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1565 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1566 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1570 old_port
[i
] = thread
->exc_actions
[i
].port
;
1571 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1572 thread
->exc_actions
[i
].behavior
= new_behavior
;
1573 thread
->exc_actions
[i
].flavor
= new_flavor
;
1574 if (count
> *CountCnt
)
1578 old_port
[i
] = IP_NULL
;
1581 thread_mtx_unlock(thread
);
1583 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1584 if (IP_VALID(old_port
[i
]))
1585 ipc_port_release_send(old_port
[i
]);
1587 if (IP_VALID(new_port
)) /* consume send right */
1588 ipc_port_release_send(new_port
);
1592 return (KERN_SUCCESS
);
1596 task_swap_exception_ports(
1598 exception_mask_t exception_mask
,
1599 ipc_port_t new_port
,
1600 exception_behavior_t new_behavior
,
1601 thread_state_flavor_t new_flavor
,
1602 exception_mask_array_t masks
,
1603 mach_msg_type_number_t
*CountCnt
,
1604 exception_port_array_t ports
,
1605 exception_behavior_array_t behaviors
,
1606 thread_state_flavor_array_t flavors
)
1608 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1609 unsigned int i
, j
, count
;
1611 if (task
== TASK_NULL
)
1612 return (KERN_INVALID_ARGUMENT
);
1614 if (exception_mask
& ~EXC_MASK_ALL
)
1615 return (KERN_INVALID_ARGUMENT
);
1617 if (IP_VALID(new_port
)) {
1618 switch (new_behavior
) {
1620 case EXCEPTION_DEFAULT
:
1621 case EXCEPTION_STATE
:
1622 case EXCEPTION_STATE_IDENTITY
:
1626 return (KERN_INVALID_ARGUMENT
);
1632 if (task
->itk_self
== IP_NULL
) {
1635 return (KERN_FAILURE
);
1640 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1641 if (exception_mask
& (1 << i
)) {
1642 for (j
= 0; j
< count
; j
++) {
1644 * search for an identical entry, if found
1645 * set corresponding mask for this exception.
1647 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1648 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1649 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1650 masks
[j
] |= (1 << i
);
1656 masks
[j
] = (1 << i
);
1657 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1658 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1659 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1663 old_port
[i
] = task
->exc_actions
[i
].port
;
1664 task
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1665 task
->exc_actions
[i
].behavior
= new_behavior
;
1666 task
->exc_actions
[i
].flavor
= new_flavor
;
1667 if (count
> *CountCnt
)
1671 old_port
[i
] = IP_NULL
;
1676 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1677 if (IP_VALID(old_port
[i
]))
1678 ipc_port_release_send(old_port
[i
]);
1680 if (IP_VALID(new_port
)) /* consume send right */
1681 ipc_port_release_send(new_port
);
1685 return (KERN_SUCCESS
);
1689 * Routine: thread/task_get_exception_ports [kernel call]
1691 * Clones a send right for each of the thread/task's exception
1692 * ports specified in the mask and returns the behaviour
1693 * and flavor of said port.
1695 * Returns upto [in} CountCnt elements.
1700 * KERN_SUCCESS Extracted a send right.
1701 * KERN_INVALID_ARGUMENT The thread is null,
1702 * Invalid special port,
1703 * Illegal mask bit set.
1704 * KERN_FAILURE The thread is dead.
1708 thread_get_exception_ports(
1710 exception_mask_t exception_mask
,
1711 exception_mask_array_t masks
,
1712 mach_msg_type_number_t
*CountCnt
,
1713 exception_port_array_t ports
,
1714 exception_behavior_array_t behaviors
,
1715 thread_state_flavor_array_t flavors
)
1717 unsigned int i
, j
, count
;
1719 if (thread
== THREAD_NULL
)
1720 return (KERN_INVALID_ARGUMENT
);
1722 if (exception_mask
& ~EXC_MASK_ALL
)
1723 return (KERN_INVALID_ARGUMENT
);
1725 thread_mtx_lock(thread
);
1727 if (!thread
->active
) {
1728 thread_mtx_unlock(thread
);
1730 return (KERN_FAILURE
);
1735 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1736 if (exception_mask
& (1 << i
)) {
1737 for (j
= 0; j
< count
; ++j
) {
1739 * search for an identical entry, if found
1740 * set corresponding mask for this exception.
1742 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1743 thread
->exc_actions
[i
].behavior
==behaviors
[j
] &&
1744 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1745 masks
[j
] |= (1 << i
);
1751 masks
[j
] = (1 << i
);
1752 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1753 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1754 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1756 if (count
>= *CountCnt
)
1762 thread_mtx_unlock(thread
);
1766 return (KERN_SUCCESS
);
1770 task_get_exception_ports(
1772 exception_mask_t exception_mask
,
1773 exception_mask_array_t masks
,
1774 mach_msg_type_number_t
*CountCnt
,
1775 exception_port_array_t ports
,
1776 exception_behavior_array_t behaviors
,
1777 thread_state_flavor_array_t flavors
)
1779 unsigned int i
, j
, count
;
1781 if (task
== TASK_NULL
)
1782 return (KERN_INVALID_ARGUMENT
);
1784 if (exception_mask
& ~EXC_MASK_ALL
)
1785 return (KERN_INVALID_ARGUMENT
);
1789 if (task
->itk_self
== IP_NULL
) {
1792 return (KERN_FAILURE
);
1797 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1798 if (exception_mask
& (1 << i
)) {
1799 for (j
= 0; j
< count
; ++j
) {
1801 * search for an identical entry, if found
1802 * set corresponding mask for this exception.
1804 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1805 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1806 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1807 masks
[j
] |= (1 << i
);
1813 masks
[j
] = (1 << i
);
1814 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1815 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1816 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1818 if (count
> *CountCnt
)
1828 return (KERN_SUCCESS
);