/* * Generate dead name notifications. Called from ipc_port_destroy. * Port is unlocked but still has reference(s); * dnrequests was taken from port while the port * was locked but the port now has port->ip_dnrequests set to IPR_NULL. */ void ipc_port_dnnotify( __unused ipc_port_t port, ipc_port_request_t dnrequests) { ipc_table_size_t its = dnrequests->ipr_size; ipc_table_elems_t size = its->its_size; ipc_port_request_index_t index; for (index = 1; index < size; index++) { ipc_port_request_t ipr = &dnrequests[index]; mach_port_name_t name = ipr->ipr_name; ipc_port_t soright; if (name == MACH_PORT_NULL) continue; soright = ipr->ipr_soright; assert(soright != IP_NULL); ipc_notify_dead_name(soright, name); } it_dnrequests_free(its, dnrequests); }
/* * Routine: ipc_port_dnnotify * Purpose: * Generate dead name notifications for * all outstanding dead-name and send- * possible requests. * Conditions: * Nothing locked. * Port must be inactive. * Reference held on port. */ void ipc_port_dnnotify( ipc_port_t port) { ipc_port_request_t requests = port->ip_requests; assert(!ip_active(port)); if (requests != IPR_NULL) { ipc_table_size_t its = requests->ipr_size; ipc_table_elems_t size = its->its_size; ipc_port_request_index_t index; for (index = 1; index < size; index++) { ipc_port_request_t ipr = &requests[index]; mach_port_name_t name = ipr->ipr_name; ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright); if (MACH_PORT_VALID(name) && IP_VALID(soright)) { ipc_notify_dead_name(soright, name); } } } }
kern_return_t ipc_right_dnrequest( ipc_space_t space, mach_port_t name, boolean_t immediate, ipc_port_t notify, ipc_port_t *previousp) { ipc_port_t previous; for (;;) { ipc_entry_t entry; ipc_entry_bits_t bits; kern_return_t kr; kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ bits = entry->ie_bits; if (bits & MACH_PORT_TYPE_PORT_RIGHTS) { ipc_port_t port; ipc_port_request_index_t request; port = (ipc_port_t) entry->ie_object; assert(port != IP_NULL); if (!ipc_right_check(space, port, name, entry)) { /* port is locked and active */ if (notify == IP_NULL) { previous = ipc_right_dncancel_macro( space, port, name, entry); ip_unlock(port); is_write_unlock(space); break; } /* * If a registered soright exists, * want to atomically switch with it. * If ipc_port_dncancel finds us a * soright, then the following * ipc_port_dnrequest will reuse * that slot, so we are guaranteed * not to unlock and retry. */ previous = ipc_right_dncancel_macro(space, port, name, entry); kr = ipc_port_dnrequest(port, name, notify, &request); if (kr != KERN_SUCCESS) { assert(previous == IP_NULL); is_write_unlock(space); kr = ipc_port_dngrow(port); /* port is unlocked */ if (kr != KERN_SUCCESS) return kr; continue; } assert(request != 0); ip_unlock(port); entry->ie_request = request; is_write_unlock(space); break; } bits = entry->ie_bits; assert(bits & MACH_PORT_TYPE_DEAD_NAME); } if ((bits & MACH_PORT_TYPE_DEAD_NAME) && immediate && (notify != IP_NULL)) { mach_port_urefs_t urefs = IE_BITS_UREFS(bits); assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); assert(urefs > 0); if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) { is_write_unlock(space); return KERN_UREFS_OVERFLOW; } entry->ie_bits = bits + 1; /* increment urefs */ is_write_unlock(space); ipc_notify_dead_name(notify, name); previous = IP_NULL; break; } is_write_unlock(space); if (bits & MACH_PORT_TYPE_PORT_OR_DEAD) return KERN_INVALID_ARGUMENT; else return KERN_INVALID_RIGHT; } *previousp = previous; return KERN_SUCCESS; }