kern_return_t mach_port_set_attributes( ipc_space_t space, mach_port_name_t name, int flavor, mach_port_info_t info, mach_msg_type_number_t count) { ipc_port_t port; kern_return_t kr; if (space == IS_NULL) return KERN_INVALID_TASK; switch (flavor) { case MACH_PORT_LIMITS_INFO: { mach_port_limits_t *mplp = (mach_port_limits_t *)info; if (count < MACH_PORT_LIMITS_INFO_COUNT) return KERN_FAILURE; if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX) return KERN_INVALID_VALUE; if (!MACH_PORT_VALID(name)) return KERN_INVALID_RIGHT; kr = ipc_port_translate_receive(space, name, &port); if (kr != KERN_SUCCESS) return kr; /* port is locked and active */ ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit); ip_unlock(port); break; } case MACH_PORT_DNREQUESTS_SIZE: { if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT) return KERN_FAILURE; if (!MACH_PORT_VALID(name)) return KERN_INVALID_RIGHT; kr = ipc_port_translate_receive(space, name, &port); if (kr != KERN_SUCCESS) return kr; /* port is locked and active */ kr = ipc_port_dngrow(port, *(int *)info); if (kr != KERN_SUCCESS) return kr; break; } default: return KERN_INVALID_ARGUMENT; /*NOTREACHED*/ } return KERN_SUCCESS; }
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; }