From 5e0b8d508ed51004bd836384293be00950ee62c9 Mon Sep 17 00:00:00 2001 From: Pasha Date: Tue, 20 Feb 2024 18:49:50 +0000 Subject: init gnumach copy --- kern/ipc_tt.c | 1113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1113 insertions(+) create mode 100644 kern/ipc_tt.c (limited to 'kern/ipc_tt.c') diff --git a/kern/ipc_tt.c b/kern/ipc_tt.c new file mode 100644 index 0000000..7c9a0b8 --- /dev/null +++ b/kern/ipc_tt.c @@ -0,0 +1,1113 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: ipc_tt.c + * Purpose: + * Task and thread related IPC functions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/* + * Routine: ipc_task_init + * Purpose: + * Initialize a task's IPC state. + * + * If non-null, some state will be inherited from the parent. + * The parent must be appropriately initialized. + * Conditions: + * Nothing locked. + */ + +void +ipc_task_init( + task_t task, + task_t parent) +{ + ipc_space_t space; + ipc_port_t kport; + kern_return_t kr; + int i; + + + kr = ipc_space_create(&space); + if (kr != KERN_SUCCESS) + panic("ipc_task_init"); + + + kport = ipc_port_alloc_kernel(); + if (kport == IP_NULL) + panic("ipc_task_init"); + + itk_lock_init(task); + task->itk_self = kport; + task->itk_sself = ipc_port_make_send(kport); + task->itk_space = space; + + if (parent == TASK_NULL) { + task->itk_exception = IP_NULL; + task->itk_bootstrap = IP_NULL; + for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) + task->itk_registered[i] = IP_NULL; + } else { + itk_lock(parent); + assert(parent->itk_self != IP_NULL); + + /* inherit registered ports */ + + for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) + task->itk_registered[i] = + ipc_port_copy_send(parent->itk_registered[i]); + + /* inherit exception and bootstrap ports */ + + task->itk_exception = + ipc_port_copy_send(parent->itk_exception); + task->itk_bootstrap = + ipc_port_copy_send(parent->itk_bootstrap); + + itk_unlock(parent); + } +} + +/* + * Routine: ipc_task_enable + * Purpose: + * Enable a task for IPC access. + * Conditions: + * Nothing locked. + */ + +void +ipc_task_enable( + task_t task) +{ + ipc_port_t kport; + + itk_lock(task); + kport = task->itk_self; + if (kport != IP_NULL) + ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK); + itk_unlock(task); +} + +/* + * Routine: ipc_task_disable + * Purpose: + * Disable IPC access to a task. + * Conditions: + * Nothing locked. + */ + +void +ipc_task_disable( + task_t task) +{ + ipc_port_t kport; + + itk_lock(task); + kport = task->itk_self; + if (kport != IP_NULL) + ipc_kobject_set(kport, IKO_NULL, IKOT_NONE); + itk_unlock(task); +} + +/* + * Routine: ipc_task_terminate + * Purpose: + * Clean up and destroy a task's IPC state. + * Conditions: + * Nothing locked. The task must be suspended. + * (Or the current thread must be in the task.) + */ + +void +ipc_task_terminate( + task_t task) +{ + ipc_port_t kport; + int i; + + itk_lock(task); + kport = task->itk_self; + + if (kport == IP_NULL) { + /* the task is already terminated (can this happen?) */ + itk_unlock(task); + return; + } + + task->itk_self = IP_NULL; + itk_unlock(task); + + /* release the naked send rights */ + + if (IP_VALID(task->itk_sself)) + ipc_port_release_send(task->itk_sself); + if (IP_VALID(task->itk_exception)) + ipc_port_release_send(task->itk_exception); + if (IP_VALID(task->itk_bootstrap)) + ipc_port_release_send(task->itk_bootstrap); + + for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) + if (IP_VALID(task->itk_registered[i])) + ipc_port_release_send(task->itk_registered[i]); + + /* destroy the space, leaving just a reference for it */ + + ipc_space_destroy(task->itk_space); + + /* destroy the kernel port */ + + ipc_port_dealloc_kernel(kport); +} + +/* + * Routine: ipc_thread_init + * Purpose: + * Initialize a thread's IPC state. + * Conditions: + * Nothing locked. + */ + +void +ipc_thread_init(thread_t thread) +{ + ipc_port_t kport; + + kport = ipc_port_alloc_kernel(); + if (kport == IP_NULL) + panic("ipc_thread_init"); + + ipc_thread_links_init(thread); + ipc_kmsg_queue_init(&thread->ith_messages); + + ith_lock_init(thread); + thread->ith_self = kport; + thread->ith_sself = ipc_port_make_send(kport); + thread->ith_exception = IP_NULL; + + thread->ith_mig_reply = MACH_PORT_NULL; + thread->ith_rpc_reply = IP_NULL; +} + +/* + * Routine: ipc_thread_enable + * Purpose: + * Enable a thread for IPC access. + * Conditions: + * Nothing locked. + */ + +void +ipc_thread_enable(thread_t thread) +{ + ipc_port_t kport; + + ith_lock(thread); + kport = thread->ith_self; + if (kport != IP_NULL) + ipc_kobject_set(kport, (ipc_kobject_t) thread, IKOT_THREAD); + ith_unlock(thread); +} + +/* + * Routine: ipc_thread_disable + * Purpose: + * Disable IPC access to a thread. + * Conditions: + * Nothing locked. + */ + +void +ipc_thread_disable(thread_t thread) +{ + ipc_port_t kport; + + ith_lock(thread); + kport = thread->ith_self; + if (kport != IP_NULL) + ipc_kobject_set(kport, IKO_NULL, IKOT_NONE); + ith_unlock(thread); +} + +/* + * Routine: ipc_thread_terminate + * Purpose: + * Clean up and destroy a thread's IPC state. + * Conditions: + * Nothing locked. The thread must be suspended. + * (Or be the current thread.) + */ + +void +ipc_thread_terminate(thread_t thread) +{ + ipc_port_t kport; + + ith_lock(thread); + kport = thread->ith_self; + + if (kport == IP_NULL) { + /* the thread is already terminated (can this happen?) */ + ith_unlock(thread); + return; + } + + thread->ith_self = IP_NULL; + ith_unlock(thread); + + assert(ipc_kmsg_queue_empty(&thread->ith_messages)); + + /* release the naked send rights */ + + if (IP_VALID(thread->ith_sself)) + ipc_port_release_send(thread->ith_sself); + if (IP_VALID(thread->ith_exception)) + ipc_port_release_send(thread->ith_exception); + + /* destroy the kernel port */ + + ipc_port_dealloc_kernel(kport); +} + +#if 0 +/* + * Routine: retrieve_task_self + * Purpose: + * Return a send right (possibly null/dead) + * for the task's user-visible self port. + * Conditions: + * Nothing locked. + */ + +ipc_port_t +retrieve_task_self(task) + task_t task; +{ + ipc_port_t port; + + assert(task != TASK_NULL); + + itk_lock(task); + if (task->itk_self != IP_NULL) + port = ipc_port_copy_send(task->itk_sself); + else + port = IP_NULL; + itk_unlock(task); + + return port; +} + +/* + * Routine: retrieve_thread_self + * Purpose: + * Return a send right (possibly null/dead) + * for the thread's user-visible self port. + * Conditions: + * Nothing locked. + */ + +ipc_port_t +retrieve_thread_self(thread) + thread_t thread; +{ + ipc_port_t port; + + assert(thread != ITH_NULL); + + ith_lock(thread); + if (thread->ith_self != IP_NULL) + port = ipc_port_copy_send(thread->ith_sself); + else + port = IP_NULL; + ith_unlock(thread); + + return port; +} +#endif /* 0 */ + +/* + * Routine: retrieve_task_self_fast + * Purpose: + * Optimized version of retrieve_task_self, + * that only works for the current task. + * + * Return a send right (possibly null/dead) + * for the task's user-visible self port. + * Conditions: + * Nothing locked. + */ + +ipc_port_t +retrieve_task_self_fast( + task_t task) +{ + ipc_port_t port; + + assert(task == current_task()); + + itk_lock(task); + assert(task->itk_self != IP_NULL); + + if ((port = task->itk_sself) == task->itk_self) { + /* no interposing */ + + ip_lock(port); + assert(ip_active(port)); + ip_reference(port); + port->ip_srights++; + ip_unlock(port); + } else + port = ipc_port_copy_send(port); + itk_unlock(task); + + return port; +} + +/* + * Routine: retrieve_thread_self_fast + * Purpose: + * Optimized version of retrieve_thread_self, + * that only works for the current thread. + * + * Return a send right (possibly null/dead) + * for the thread's user-visible self port. + * Conditions: + * Nothing locked. + */ + +ipc_port_t +retrieve_thread_self_fast(thread_t thread) +{ + ipc_port_t port; + + assert(thread == current_thread()); + + ith_lock(thread); + assert(thread->ith_self != IP_NULL); + + if ((port = thread->ith_sself) == thread->ith_self) { + /* no interposing */ + + ip_lock(port); + assert(ip_active(port)); + ip_reference(port); + port->ip_srights++; + ip_unlock(port); + } else + port = ipc_port_copy_send(port); + ith_unlock(thread); + + return port; +} + +#if 0 +/* + * Routine: retrieve_task_exception + * Purpose: + * Return a send right (possibly null/dead) + * for the task's exception port. + * Conditions: + * Nothing locked. + */ + +ipc_port_t +retrieve_task_exception(task) + task_t task; +{ + ipc_port_t port; + + assert(task != TASK_NULL); + + itk_lock(task); + if (task->itk_self != IP_NULL) + port = ipc_port_copy_send(task->itk_exception); + else + port = IP_NULL; + itk_unlock(task); + + return port; +} + +/* + * Routine: retrieve_thread_exception + * Purpose: + * Return a send right (possibly null/dead) + * for the thread's exception port. + * Conditions: + * Nothing locked. + */ + +ipc_port_t +retrieve_thread_exception(thread) + thread_t thread; +{ + ipc_port_t port; + + assert(thread != ITH_NULL); + + ith_lock(thread); + if (thread->ith_self != IP_NULL) + port = ipc_port_copy_send(thread->ith_exception); + else + port = IP_NULL; + ith_unlock(thread); + + return port; +} +#endif /* 0 */ + +/* + * Routine: mach_task_self [mach trap] + * Purpose: + * Give the caller send rights for his own task port. + * Conditions: + * Nothing locked. + * Returns: + * MACH_PORT_NULL if there are any resource failures + * or other errors. + */ + +mach_port_name_t +mach_task_self(void) +{ + task_t task = current_task(); + ipc_port_t sright; + + sright = retrieve_task_self_fast(task); + return ipc_port_copyout_send(sright, task->itk_space); +} + +/* + * Routine: mach_thread_self [mach trap] + * Purpose: + * Give the caller send rights for his own thread port. + * Conditions: + * Nothing locked. + * Returns: + * MACH_PORT_NULL if there are any resource failures + * or other errors. + */ + +mach_port_name_t +mach_thread_self(void) +{ + thread_t thread = current_thread(); + task_t task = thread->task; + ipc_port_t sright; + + sright = retrieve_thread_self_fast(thread); + return ipc_port_copyout_send(sright, task->itk_space); +} + +/* + * Routine: mach_reply_port [mach trap] + * Purpose: + * Allocate a port for the caller. + * Conditions: + * Nothing locked. + * Returns: + * MACH_PORT_NULL if there are any resource failures + * or other errors. + */ + +mach_port_name_t +mach_reply_port(void) +{ + ipc_port_t port; + mach_port_name_t name; + kern_return_t kr; + + kr = ipc_port_alloc(current_task()->itk_space, &name, &port); + if (kr == KERN_SUCCESS) + ip_unlock(port); + else + name = MACH_PORT_NULL; + + return name; +} + +/* + * Routine: task_get_special_port [kernel call] + * Purpose: + * Clones a send right for one of the task's + * special ports. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Extracted a send right. + * KERN_INVALID_ARGUMENT The task is null. + * KERN_FAILURE The task/space is dead. + * KERN_INVALID_ARGUMENT Invalid special port. + */ + +kern_return_t +task_get_special_port( + task_t task, + int which, + ipc_port_t *portp) +{ + ipc_port_t *whichp; + ipc_port_t port; + + if (task == TASK_NULL) + return KERN_INVALID_ARGUMENT; + + switch (which) { + case TASK_KERNEL_PORT: + whichp = &task->itk_sself; + break; + + case TASK_EXCEPTION_PORT: + whichp = &task->itk_exception; + break; + + case TASK_BOOTSTRAP_PORT: + whichp = &task->itk_bootstrap; + break; + + default: + return KERN_INVALID_ARGUMENT; + } + + itk_lock(task); + if (task->itk_self == IP_NULL) { + itk_unlock(task); + return KERN_FAILURE; + } + + port = ipc_port_copy_send(*whichp); + itk_unlock(task); + + *portp = port; + return KERN_SUCCESS; +} + +/* + * Routine: task_set_special_port [kernel call] + * Purpose: + * Changes one of the task's special ports, + * setting it to the supplied send right. + * Conditions: + * Nothing locked. If successful, consumes + * the supplied send right. + * Returns: + * KERN_SUCCESS Changed the special port. + * KERN_INVALID_ARGUMENT The task is null. + * KERN_FAILURE The task/space is dead. + * KERN_INVALID_ARGUMENT Invalid special port. + */ + +kern_return_t +task_set_special_port( + task_t task, + int which, + const ipc_port_t port) +{ + ipc_port_t *whichp; + ipc_port_t old; + + if (task == TASK_NULL) + return KERN_INVALID_ARGUMENT; + + switch (which) { + case TASK_KERNEL_PORT: + whichp = &task->itk_sself; + break; + + case TASK_EXCEPTION_PORT: + whichp = &task->itk_exception; + break; + + case TASK_BOOTSTRAP_PORT: + whichp = &task->itk_bootstrap; + break; + + default: + return KERN_INVALID_ARGUMENT; + } + + itk_lock(task); + if (task->itk_self == IP_NULL) { + itk_unlock(task); + return KERN_FAILURE; + } + + old = *whichp; + *whichp = port; + itk_unlock(task); + + if (IP_VALID(old)) + ipc_port_release_send(old); + return KERN_SUCCESS; +} + +/* + * Routine: thread_get_special_port [kernel call] + * Purpose: + * Clones a send right for one of the thread's + * special ports. + * Conditions: + * Nothing locked. + * Returns: + * KERN_SUCCESS Extracted a send right. + * KERN_INVALID_ARGUMENT The thread is null. + * KERN_FAILURE The thread is dead. + * KERN_INVALID_ARGUMENT Invalid special port. + */ + +kern_return_t +thread_get_special_port( + thread_t thread, + int which, + ipc_port_t *portp) +{ + ipc_port_t *whichp; + ipc_port_t port; + + if (thread == ITH_NULL) + return KERN_INVALID_ARGUMENT; + + switch (which) { + case THREAD_KERNEL_PORT: + whichp = &thread->ith_sself; + break; + + case THREAD_EXCEPTION_PORT: + whichp = &thread->ith_exception; + break; + + default: + return KERN_INVALID_ARGUMENT; + } + + ith_lock(thread); + if (thread->ith_self == IP_NULL) { + ith_unlock(thread); + return KERN_FAILURE; + } + + port = ipc_port_copy_send(*whichp); + ith_unlock(thread); + + *portp = port; + return KERN_SUCCESS; +} + +/* + * Routine: thread_set_special_port [kernel call] + * Purpose: + * Changes one of the thread's special ports, + * setting it to the supplied send right. + * Conditions: + * Nothing locked. If successful, consumes + * the supplied send right. + * Returns: + * KERN_SUCCESS Changed the special port. + * KERN_INVALID_ARGUMENT The thread is null. + * KERN_FAILURE The thread is dead. + * KERN_INVALID_ARGUMENT Invalid special port. + */ + +kern_return_t +thread_set_special_port( + thread_t thread, + int which, + ipc_port_t port) +{ + ipc_port_t *whichp; + ipc_port_t old; + + if (thread == ITH_NULL) + return KERN_INVALID_ARGUMENT; + + switch (which) { + case THREAD_KERNEL_PORT: + whichp = &thread->ith_sself; + break; + + case THREAD_EXCEPTION_PORT: + whichp = &thread->ith_exception; + break; + + default: + return KERN_INVALID_ARGUMENT; + } + + ith_lock(thread); + if (thread->ith_self == IP_NULL) { + ith_unlock(thread); + return KERN_FAILURE; + } + + old = *whichp; + *whichp = port; + ith_unlock(thread); + + if (IP_VALID(old)) + ipc_port_release_send(old); + return KERN_SUCCESS; +} + +/* + * Routine: mach_ports_register [kernel call] + * Purpose: + * Stash a handful of port send rights in the task. + * Child tasks will inherit these rights, but they + * must use mach_ports_lookup to acquire them. + * + * The rights are supplied in a (wired) kalloc'd segment. + * Rights which aren't supplied are assumed to be null. + * Conditions: + * Nothing locked. If successful, consumes + * the supplied rights and memory. + * Returns: + * KERN_SUCCESS Stashed the port rights. + * KERN_INVALID_ARGUMENT The task is null. + * KERN_INVALID_ARGUMENT The task is dead. + * KERN_INVALID_ARGUMENT Too many port rights supplied. + */ + +kern_return_t +mach_ports_register( + task_t task, + mach_port_array_t memory, + mach_msg_type_number_t portsCnt) +{ + ipc_port_t ports[TASK_PORT_REGISTER_MAX]; + unsigned i; + + if ((task == TASK_NULL) || + (portsCnt > TASK_PORT_REGISTER_MAX)) + return KERN_INVALID_ARGUMENT; + + /* + * Pad the port rights with nulls. + */ + + for (i = 0; i < portsCnt; i++) + ports[i] = (ipc_port_t)memory[i]; + for (; i < TASK_PORT_REGISTER_MAX; i++) + ports[i] = IP_NULL; + + itk_lock(task); + if (task->itk_self == IP_NULL) { + itk_unlock(task); + return KERN_INVALID_ARGUMENT; + } + + /* + * Replace the old send rights with the new. + * Release the old rights after unlocking. + */ + + for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) { + ipc_port_t old; + + old = task->itk_registered[i]; + task->itk_registered[i] = ports[i]; + ports[i] = old; + } + + itk_unlock(task); + + for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) + if (IP_VALID(ports[i])) + ipc_port_release_send(ports[i]); + + /* + * Now that the operation is known to be successful, + * we can free the memory. + */ + + if (portsCnt != 0) + kfree((vm_offset_t) memory, + (vm_size_t) (portsCnt * sizeof(mach_port_t))); + + return KERN_SUCCESS; +} + +/* + * Routine: mach_ports_lookup [kernel call] + * Purpose: + * Retrieves (clones) the stashed port send rights. + * Conditions: + * Nothing locked. If successful, the caller gets + * rights and memory. + * Returns: + * KERN_SUCCESS Retrieved the send rights. + * KERN_INVALID_ARGUMENT The task is null. + * KERN_INVALID_ARGUMENT The task is dead. + * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. + */ + +kern_return_t +mach_ports_lookup( + task_t task, + mach_port_t **portsp, + mach_msg_type_number_t *portsCnt) +{ + vm_offset_t memory; + vm_size_t size; + ipc_port_t *ports; + int i; + + if (task == TASK_NULL) + return KERN_INVALID_ARGUMENT; + + size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t)); + + memory = kalloc(size); + if (memory == 0) + return KERN_RESOURCE_SHORTAGE; + + itk_lock(task); + if (task->itk_self == IP_NULL) { + itk_unlock(task); + + kfree(memory, size); + return KERN_INVALID_ARGUMENT; + } + + ports = (ipc_port_t *) memory; + + /* + * Clone port rights. Because kalloc'd memory + * is wired, we won't fault while holding the task lock. + */ + + for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) + ports[i] = ipc_port_copy_send(task->itk_registered[i]); + + itk_unlock(task); + + *portsp = (mach_port_t *)ports; + *portsCnt = TASK_PORT_REGISTER_MAX; + return KERN_SUCCESS; +} + +/* + * Routine: convert_port_to_task + * Purpose: + * Convert from a port to a task. + * Doesn't consume the port ref; produces a task ref, + * which may be null. + * Conditions: + * Nothing locked. + */ + +task_t +convert_port_to_task( + ipc_port_t port) +{ + task_t task = TASK_NULL; + + if (IP_VALID(port)) { + ip_lock(port); + if (ip_active(port) && + (ip_kotype(port) == IKOT_TASK)) { + task = (task_t) port->ip_kobject; + task_reference(task); + } + ip_unlock(port); + } + + return task; +} + +/* + * Routine: convert_port_to_space + * Purpose: + * Convert from a port to a space. + * Doesn't consume the port ref; produces a space ref, + * which may be null. + * Conditions: + * Nothing locked. + */ + +ipc_space_t +convert_port_to_space( + ipc_port_t port) +{ + ipc_space_t space = IS_NULL; + + if (IP_VALID(port)) { + ip_lock(port); + if (ip_active(port) && + (ip_kotype(port) == IKOT_TASK)) { + space = ((task_t) port->ip_kobject)->itk_space; + is_reference(space); + } + ip_unlock(port); + } + + return space; +} + +/* + * Routine: convert_port_to_map + * Purpose: + * Convert from a port to a map. + * Doesn't consume the port ref; produces a map ref, + * which may be null. + * Conditions: + * Nothing locked. + */ + +vm_map_t +convert_port_to_map(ipc_port_t port) +{ + vm_map_t map = VM_MAP_NULL; + + if (IP_VALID(port)) { + ip_lock(port); + if (ip_active(port) && + (ip_kotype(port) == IKOT_TASK)) { + map = ((task_t) port->ip_kobject)->map; + vm_map_reference(map); + } + ip_unlock(port); + } + + return map; +} + +/* + * Routine: convert_port_to_thread + * Purpose: + * Convert from a port to a thread. + * Doesn't consume the port ref; produces a thread ref, + * which may be null. + * Conditions: + * Nothing locked. + */ + +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) && + (ip_kotype(port) == IKOT_THREAD)) { + thread = (thread_t) port->ip_kobject; + thread_reference(thread); + } + ip_unlock(port); + } + + return thread; +} + +/* + * Routine: convert_task_to_port + * Purpose: + * Convert from a task to a port. + * Consumes a task ref; produces a naked send right + * which may be invalid. + * Conditions: + * Nothing locked. + */ + +ipc_port_t +convert_task_to_port(task_t task) +{ + ipc_port_t port; + + itk_lock(task); + if (task->itk_self != IP_NULL) + port = ipc_port_make_send(task->itk_self); + else + port = IP_NULL; + itk_unlock(task); + + task_deallocate(task); + return port; +} + +/* + * Routine: convert_thread_to_port + * Purpose: + * Convert from a thread to a port. + * Consumes a thread ref; produces a naked send right + * which may be invalid. + * Conditions: + * Nothing locked. + */ + +ipc_port_t +convert_thread_to_port(thread_t thread) +{ + ipc_port_t port; + + ith_lock(thread); + if (thread->ith_self != IP_NULL) + port = ipc_port_make_send(thread->ith_self); + else + port = IP_NULL; + ith_unlock(thread); + + thread_deallocate(thread); + return port; +} + +/* + * Routine: space_deallocate + * Purpose: + * Deallocate a space ref produced by convert_port_to_space. + * Conditions: + * Nothing locked. + */ + +void +space_deallocate(ipc_space_t space) +{ + if (space != IS_NULL) + is_release(space); +} -- cgit v1.2.1