+/*
+ * Routine: thread_get_special_reply_port [mach trap]
+ * Purpose:
+ * Allocate a special reply port for the calling thread.
+ * Conditions:
+ * Nothing locked.
+ * Returns:
+ * mach_port_name_t: send right & receive right for special reply port.
+ * MACH_PORT_NULL if there are any resource failures
+ * or other errors.
+ */
+
+mach_port_name_t
+thread_get_special_reply_port(
+ __unused struct thread_get_special_reply_port_args *args)
+{
+ ipc_port_t port;
+ mach_port_name_t name;
+ mach_port_name_t send_name;
+ kern_return_t kr;
+ thread_t thread = current_thread();
+
+ /* unbind the thread special reply port */
+ if (IP_VALID(thread->ith_special_reply_port)) {
+ kr = ipc_port_unbind_special_reply_port(thread, TRUE);
+ if (kr != KERN_SUCCESS) {
+ return MACH_PORT_NULL;
+ }
+ }
+
+ kr = ipc_port_alloc(current_task()->itk_space, &name, &port);
+ if (kr == KERN_SUCCESS) {
+ ipc_port_bind_special_reply_port_locked(port);
+
+ /* Make a send right and insert it in the space at specified name */
+ ipc_port_make_send_locked(port);
+ ip_unlock(port);
+ send_name = ipc_port_copyout_name_send(port, current_task()->itk_space, name);
+ /*
+ * If insertion of send right failed, userland is doing something bad, error out.
+ * The space was marked inactive or the receive right just inserted above at the
+ * given name was moved, in either case do not try to deallocate the receive right.
+ */
+ if (send_name == MACH_PORT_NULL || send_name == MACH_PORT_DEAD) {
+ if (IP_VALID(thread->ith_special_reply_port)) {
+ ipc_port_unbind_special_reply_port(thread, TRUE);
+ }
+ name = MACH_PORT_NULL;
+ }
+ } else {
+ name = MACH_PORT_NULL;
+ }
+ return name;
+}
+
+/*
+ * Routine: ipc_port_bind_special_reply_port_locked
+ * Purpose:
+ * Bind the given port to current thread as a special reply port.
+ * Conditions:
+ * Port locked.
+ * Returns:
+ * None.
+ */
+
+static void
+ipc_port_bind_special_reply_port_locked(
+ ipc_port_t port)
+{
+ thread_t thread = current_thread();
+ assert(thread->ith_special_reply_port == NULL);
+
+ ip_reference(port);
+ thread->ith_special_reply_port = port;
+ port->ip_specialreply = 1;
+ port->ip_sync_link_state = PORT_SYNC_LINK_ANY;
+
+ reset_ip_srp_bits(port);
+}
+
+/*
+ * Routine: ipc_port_unbind_special_reply_port
+ * Purpose:
+ * Unbind the thread's special reply port.
+ * If the special port has threads waiting on turnstile,
+ * update it's inheritor.
+ * Condition:
+ * Nothing locked.
+ * Returns:
+ * None.
+ */
+static kern_return_t
+ipc_port_unbind_special_reply_port(
+ thread_t thread,
+ boolean_t unbind_active_port)
+{
+ ipc_port_t special_reply_port = thread->ith_special_reply_port;
+
+ ip_lock(special_reply_port);
+
+ /* Return error if port active and unbind_active_port set to FALSE */
+ if (unbind_active_port == FALSE && ip_active(special_reply_port)) {
+ ip_unlock(special_reply_port);
+ return KERN_FAILURE;
+ }
+
+ thread->ith_special_reply_port = NULL;
+ ipc_port_adjust_special_reply_port_locked(special_reply_port, NULL,
+ IPC_PORT_ADJUST_SR_CLEAR_SPECIAL_REPLY, FALSE);
+ /* port unlocked */
+
+ ip_release(special_reply_port);
+ return KERN_SUCCESS;
+}
+