+
+static thread_t
+convert_port_to_thread_locked(
+ ipc_port_t port,
+ port_to_thread_options_t options,
+ boolean_t eval)
+{
+ thread_t thread = THREAD_NULL;
+
+ ip_lock_held(port);
+ require_ip_active(port);
+
+ if (ip_kotype(port) == IKOT_THREAD_CONTROL) {
+ thread = (thread_t) ip_get_kobject(port);
+ assert(thread != THREAD_NULL);
+
+ if (options & PORT_TO_THREAD_NOT_CURRENT_THREAD) {
+ if (thread == current_thread()) {
+ return THREAD_NULL;
+ }
+ }
+
+ if (options & PORT_TO_THREAD_IN_CURRENT_TASK) {
+ if (thread->task != current_task()) {
+ return THREAD_NULL;
+ }
+ } else {
+ /* Use task conversion rules for thread control conversions */
+ if (eval && task_conversion_eval(current_task(), thread->task) != KERN_SUCCESS) {
+ return THREAD_NULL;
+ }
+ }
+
+ thread_reference_internal(thread);
+ }
+
+ return thread;
+}
+
+thread_t
+convert_port_to_thread(
+ ipc_port_t port)
+{
+ thread_t thread = THREAD_NULL;
+
+ if (IP_VALID(port)) {
+ ip_lock(port);
+ if (ip_active(port)) {
+ thread = convert_port_to_thread_locked(port, PORT_TO_THREAD_NONE, TRUE);
+ }
+ ip_unlock(port);
+ }
+
+ return thread;
+}
+
+static thread_t
+convert_port_to_thread_no_eval(
+ ipc_port_t port)
+{
+ thread_t thread = THREAD_NULL;
+
+ if (IP_VALID(port)) {
+ ip_lock(port);
+ if (ip_active(port)) {
+ thread = convert_port_to_thread_locked(port, PORT_TO_THREAD_NONE, FALSE);
+ }
+ ip_unlock(port);
+ }
+
+ return thread;
+}
+
+/*
+ * Routine: convert_port_to_thread_inspect
+ * Purpose:
+ * Convert from a port to a thread inspect right
+ * Doesn't consume the port ref; produces a thread ref,
+ * which may be null.
+ * Conditions:
+ * Nothing locked.
+ */
+static thread_inspect_t
+convert_port_to_thread_inspect_locked(
+ ipc_port_t port)
+{
+ thread_inspect_t thread = THREAD_INSPECT_NULL;
+
+ ip_lock_held(port);
+ require_ip_active(port);
+
+ if (ip_kotype(port) == IKOT_THREAD_CONTROL ||
+ ip_kotype(port) == IKOT_THREAD_READ ||
+ ip_kotype(port) == IKOT_THREAD_INSPECT) {
+ thread = (thread_inspect_t)port->ip_kobject;
+ assert(thread != THREAD_INSPECT_NULL);
+ thread_reference_internal((thread_t)thread);
+ }
+
+ return thread;
+}
+
+thread_inspect_t
+convert_port_to_thread_inspect(
+ ipc_port_t port)
+{
+ thread_inspect_t thread = THREAD_INSPECT_NULL;
+
+ if (IP_VALID(port)) {
+ ip_lock(port);
+ if (ip_active(port)) {
+ thread = convert_port_to_thread_inspect_locked(port);
+ }
+ ip_unlock(port);
+ }
+
+ return thread;
+}
+
+/*
+ * Routine: convert_port_to_thread_read
+ * Purpose:
+ * Convert from a port to a thread read right
+ * Doesn't consume the port ref; produces a thread ref,
+ * which may be null.
+ * Conditions:
+ * Nothing locked.
+ */
+static thread_read_t
+convert_port_to_thread_read_locked(
+ ipc_port_t port)
+{
+ thread_read_t thread = THREAD_READ_NULL;
+
+ ip_lock_held(port);
+ require_ip_active(port);
+
+ if (ip_kotype(port) == IKOT_THREAD_CONTROL ||
+ ip_kotype(port) == IKOT_THREAD_READ) {
+ thread = (thread_read_t) ip_get_kobject(port);
+ assert(thread != THREAD_READ_NULL);
+
+ /* Use task conversion rules for thread control conversions */
+ if (task_conversion_eval(current_task(), thread->task) != KERN_SUCCESS) {
+ return THREAD_READ_NULL;
+ }
+
+ thread_reference_internal((thread_t)thread);
+ }
+
+ return thread;
+}
+
+thread_read_t
+convert_port_to_thread_read(
+ ipc_port_t port)
+{
+ thread_read_t thread = THREAD_READ_NULL;
+
+ if (IP_VALID(port)) {
+ ip_lock(port);
+ if (ip_active(port)) {
+ thread = convert_port_to_thread_read_locked(port);
+ }
+ ip_unlock(port);
+ }
+
+ return thread;
+}
+
+
+/*
+ * Routine: convert_thread_to_port_with_flavor
+ * Purpose:
+ * Convert from a thread to a port of given flavor.
+ * Consumes a thread ref; produces a naked send right
+ * which may be invalid.
+ * Conditions:
+ * Nothing locked.
+ */
+static ipc_port_t
+convert_thread_to_port_with_flavor(
+ thread_t thread,
+ mach_thread_flavor_t flavor)
+{
+ ipc_port_t port = IP_NULL;
+
+ thread_mtx_lock(thread);
+
+ if (thread->ith_self[THREAD_FLAVOR_CONTROL] == IP_NULL) {
+ goto exit;
+ }
+
+ if (flavor == THREAD_FLAVOR_CONTROL) {
+ port = ipc_port_make_send(thread->ith_self[flavor]);
+ } else {
+ if (!thread->active) {
+ goto exit;
+ }
+ ipc_kobject_type_t kotype = (flavor == THREAD_FLAVOR_READ) ? IKOT_THREAD_READ : IKOT_THREAD_INSPECT;
+ /*
+ * Claim a send right on the thread read/inspect port, and request a no-senders
+ * notification on that port (if none outstanding). A thread reference is not
+ * donated here even though the ports are created lazily because it doesn't own the
+ * kobject that it points to. Threads manage their lifetime explicitly and
+ * have to synchronize with each other, between the task/thread terminating and the
+ * send-once notification firing, and this is done under the thread mutex
+ * rather than with atomics.
+ */
+ (void)ipc_kobject_make_send_lazy_alloc_port(&thread->ith_self[flavor], (ipc_kobject_t)thread,
+ kotype, false, 0);
+ port = thread->ith_self[flavor];
+ }
+
+exit:
+ thread_mtx_unlock(thread);
+ thread_deallocate(thread);
+ return port;
+}
+
+ipc_port_t
+convert_thread_to_port(
+ thread_t thread)
+{
+ return convert_thread_to_port_with_flavor(thread, THREAD_FLAVOR_CONTROL);
+}
+
+ipc_port_t
+convert_thread_read_to_port(thread_read_t thread)
+{
+ return convert_thread_to_port_with_flavor(thread, THREAD_FLAVOR_READ);
+}
+
+ipc_port_t
+convert_thread_inspect_to_port(thread_inspect_t thread)
+{
+ return convert_thread_to_port_with_flavor(thread, THREAD_FLAVOR_INSPECT);
+}
+
+
+/*
+ * Routine: port_name_to_thread
+ * Purpose:
+ * Convert from a port name to a thread reference
+ * A name of MACH_PORT_NULL is valid for the null thread.
+ * Conditions:
+ * Nothing locked.
+ */
+thread_t
+port_name_to_thread(
+ mach_port_name_t name,
+ port_to_thread_options_t options)
+{
+ thread_t thread = THREAD_NULL;
+ ipc_port_t kport;
+ kern_return_t kr;
+
+ if (MACH_PORT_VALID(name)) {
+ kr = ipc_port_translate_send(current_space(), name, &kport);
+ if (kr == KERN_SUCCESS) {
+ thread = convert_port_to_thread_locked(kport, options, TRUE);
+ ip_unlock(kport);
+ }
+ }
+
+ return thread;
+}
+
+/*
+ * Routine: port_name_to_task
+ * Purpose:
+ * Convert from a port name to a task reference
+ * A name of MACH_PORT_NULL is valid for the null task.
+ * Conditions:
+ * Nothing locked.
+ */
+task_t
+port_name_to_task(
+ mach_port_name_t name)
+{
+ ipc_port_t kport;
+ kern_return_t kr;
+ task_t task = TASK_NULL;
+
+ if (MACH_PORT_VALID(name)) {
+ kr = ipc_port_translate_send(current_space(), name, &kport);
+ if (kr == KERN_SUCCESS) {
+ task = convert_port_to_task_locked(kport, NULL, TRUE);
+ ip_unlock(kport);
+ }
+ }
+ return task;
+}
+
+/*
+ * Routine: port_name_to_task_read
+ * Purpose:
+ * Convert from a port name to a task reference
+ * A name of MACH_PORT_NULL is valid for the null task.
+ * Conditions:
+ * Nothing locked.
+ */
+task_read_t
+port_name_to_task_read(
+ mach_port_name_t name)
+{
+ ipc_port_t kport;
+ kern_return_t kr;
+ task_read_t tr = TASK_READ_NULL;
+
+ if (MACH_PORT_VALID(name)) {
+ kr = ipc_port_translate_send(current_space(), name, &kport);
+ if (kr == KERN_SUCCESS) {
+ tr = convert_port_to_task_read_locked(kport);
+ ip_unlock(kport);
+ }
+ }
+ return tr;
+}
+
+/*
+ * Routine: port_name_to_task_read_no_eval
+ * Purpose:
+ * Convert from a port name to a task reference
+ * A name of MACH_PORT_NULL is valid for the null task.
+ * It doesnt run the task_conversion_eval check if the port
+ * is of type IKOT_TASK_CONTROL.
+ * Conditions:
+ * Nothing locked.
+ */
+task_read_t
+port_name_to_task_read_no_eval(
+ mach_port_name_t name)
+{
+ ipc_port_t kport;
+ kern_return_t kr;
+ task_read_t tr = TASK_READ_NULL;
+
+ if (MACH_PORT_VALID(name)) {
+ kr = ipc_port_translate_send(current_space(), name, &kport);
+ if (kr == KERN_SUCCESS) {
+ switch (ip_kotype(kport)) {
+ case IKOT_TASK_CONTROL:
+ tr = convert_port_to_task_locked(kport, NULL, FALSE);
+ break;
+ case IKOT_TASK_READ:
+ tr = convert_port_to_task_read_locked(kport);
+ break;
+ default:
+ break;
+ }
+ ip_unlock(kport);
+ }
+ }
+ return tr;
+}
+
+/*
+ * Routine: port_name_to_task_inspect
+ * Purpose:
+ * Convert from a port name to a task reference
+ * A name of MACH_PORT_NULL is valid for the null task.
+ * Conditions:
+ * Nothing locked.
+ */
+task_inspect_t
+port_name_to_task_inspect(
+ mach_port_name_t name)