kern_return_t ipc_object_copyin( ipc_space_t space, mach_port_name_t name, mach_msg_type_name_t msgt_name, ipc_object_t *objectp) { ipc_entry_t entry; ipc_port_t soright; ipc_port_t release_port; kern_return_t kr; queue_head_t links_data; queue_t links = &links_data; wait_queue_link_t wql; queue_init(links); /* * Could first try a read lock when doing * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND, * and MACH_MSG_TYPE_MAKE_SEND_ONCE. */ kr = ipc_right_lookup_write(space, name, &entry); if (kr != KERN_SUCCESS) return kr; /* space is write-locked and active */ release_port = IP_NULL; kr = ipc_right_copyin(space, name, entry, msgt_name, TRUE, objectp, &soright, &release_port, links); if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ipc_entry_dealloc(space, name, entry); is_write_unlock(space); while(!queue_empty(links)) { wql = (wait_queue_link_t) dequeue(links); wait_queue_link_free(wql); } if (release_port != IP_NULL) ip_release(release_port); if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) ipc_notify_port_deleted(soright, name); return kr; }
static int filt_machportattach( struct knote *kn) { mach_port_name_t name = (mach_port_name_t)kn->kn_kevent.ident; wait_queue_link_t wql = wait_queue_link_allocate(); ipc_pset_t pset = IPS_NULL; int result = ENOSYS; kern_return_t kr; kr = ipc_object_translate(current_space(), name, MACH_PORT_RIGHT_PORT_SET, (ipc_object_t *)&pset); if (kr != KERN_SUCCESS) { wait_queue_link_free(wql); return (kr == KERN_INVALID_NAME ? ENOENT : ENOTSUP); } /* We've got a lock on pset */ /* * Bind the portset wait queue directly to knote/kqueue. * This allows us to just use wait_queue foo to effect a wakeup, * rather than having to call knote() from the Mach code on each * message. */ result = knote_link_wait_queue(kn, &pset->ips_messages.imq_wait_queue, wql); if (result == 0) { /* keep a reference for the knote */ kn->kn_ptr.p_pset = pset; ips_reference(pset); ips_unlock(pset); return 0; } ips_unlock(pset); wait_queue_link_free(wql); return result; }
static void filt_machportdetach( struct knote *kn) { ipc_pset_t pset = kn->kn_ptr.p_pset; wait_queue_link_t wql = WAIT_QUEUE_LINK_NULL; /* * Unlink the portset wait queue from knote/kqueue, * and release our reference on the portset. */ ips_lock(pset); (void)knote_unlink_wait_queue(kn, &pset->ips_messages.imq_wait_queue, &wql); kn->kn_ptr.p_pset = IPS_NULL; ips_unlock(pset); ips_release(pset); if (wql != WAIT_QUEUE_LINK_NULL) wait_queue_link_free(wql); }
void ipc_pset_destroy( ipc_pset_t pset) { spl_t s; queue_head_t link_data; queue_t links = &link_data; wait_queue_link_t wql; queue_init(links); assert(ips_active(pset)); pset->ips_object.io_bits &= ~IO_BITS_ACTIVE; /* * remove all the member message queues */ ipc_mqueue_remove_all(&pset->ips_messages, links); /* * Set all waiters on the portset running to * discover the change. */ s = splsched(); imq_lock(&pset->ips_messages); ipc_mqueue_changed(&pset->ips_messages); imq_unlock(&pset->ips_messages); splx(s); ips_unlock(pset); ips_release(pset); /* consume the ref our caller gave us */ while(!queue_empty(links)) { wql = (wait_queue_link_t) dequeue(links); wait_queue_link_free(wql); } }