kern_return_t mach_port_insert_member( ipc_space_t space, mach_port_name_t name, mach_port_name_t psname) { ipc_object_t obj; ipc_object_t psobj; kern_return_t kr; if (space == IS_NULL) return KERN_INVALID_TASK; if (!MACH_PORT_VALID(name) || !MACH_PORT_VALID(psname)) return KERN_INVALID_RIGHT; kr = ipc_object_translate_two(space, name, MACH_PORT_RIGHT_RECEIVE, &obj, psname, MACH_PORT_RIGHT_PORT_SET, &psobj); if (kr != KERN_SUCCESS) return kr; /* obj and psobj are locked (and were locked in that order) */ assert(psobj != IO_NULL); assert(obj != IO_NULL); kr = ipc_pset_add((ipc_pset_t)psobj, (ipc_port_t)obj); io_unlock(psobj); io_unlock(obj); return kr; }
kern_return_t mach_port_move_member( ipc_space_t space, mach_port_name_t member, mach_port_name_t after) { ipc_entry_t entry; ipc_port_t port; ipc_pset_t nset; kern_return_t kr; if (space == IS_NULL) return KERN_INVALID_TASK; if (!MACH_PORT_VALID(member)) return KERN_INVALID_RIGHT; if (after == MACH_PORT_DEAD) return KERN_INVALID_RIGHT; kr = ipc_right_lookup_read(space, member, &entry); if (kr != KERN_SUCCESS) return kr; /* space is read-locked and active */ if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) { is_read_unlock(space); return KERN_INVALID_RIGHT; } port = (ipc_port_t) entry->ie_object; assert(port != IP_NULL); if (after == MACH_PORT_NULL) nset = IPS_NULL; else { entry = ipc_entry_lookup(space, after); if (entry == IE_NULL) { is_read_unlock(space); return KERN_INVALID_NAME; } if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) { is_read_unlock(space); return KERN_INVALID_RIGHT; } nset = (ipc_pset_t) entry->ie_object; assert(nset != IPS_NULL); } ip_lock(port); ipc_pset_remove_from_all(port); if (nset != IPS_NULL) { ips_lock(nset); kr = ipc_pset_add(nset, port); ips_unlock(nset); } ip_unlock(port); is_read_unlock(space); return kr; }
kern_return_t ipc_pset_move( ipc_space_t space, ipc_port_t port, ipc_pset_t nset) { ipc_pset_t oset; /* * While we've got the space locked, it holds refs for * the port and nset (because of the entries). Also, * they must be alive. While we've got port locked, it * holds a ref for oset, which might not be alive. */ ip_lock(port); assert(ip_active(port)); oset = port->ip_pset; if (oset == nset) { /* the port is already in the new set: a noop */ is_read_unlock(space); } else if (oset == IPS_NULL) { /* just add port to the new set */ ips_lock(nset); assert(ips_active(nset)); is_read_unlock(space); ipc_pset_add(nset, port); ips_unlock(nset); } else if (nset == IPS_NULL) { /* just remove port from the old set */ is_read_unlock(space); ips_lock(oset); ipc_pset_remove(oset, port); if (ips_active(oset)) ips_unlock(oset); else { ips_check_unlock(oset); oset = IPS_NULL; /* trigger KERN_NOT_IN_SET */ } } else { /* atomically move port from oset to nset */ if (oset < nset) { ips_lock(oset); ips_lock(nset); } else { ips_lock(nset); ips_lock(oset); } is_read_unlock(space); assert(ips_active(nset)); ipc_pset_remove(oset, port); ipc_pset_add(nset, port); ips_unlock(nset); ips_check_unlock(oset); /* KERN_NOT_IN_SET not a possibility */ } ip_unlock(port); return (((nset == IPS_NULL) && (oset == IPS_NULL)) ? KERN_NOT_IN_SET : KERN_SUCCESS); }