void ipc_pset_destroy( ipc_pset_t pset) { spl_t s; assert(ips_active(pset)); pset->ips_object.io_bits &= ~IO_BITS_ACTIVE; /* * remove all the member message queues * AND remove this message queue from any containing sets */ ipc_mqueue_remove_all(&pset->ips_messages); /* * 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); ipc_mqueue_deinit(&pset->ips_messages); ips_unlock(pset); ips_release(pset); /* consume the ref our caller gave us */ }
void ipc_pset_destroy( ipc_pset_t pset) { spl_t s; 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); s = splsched(); imq_lock(&pset->ips_messages); ipc_mqueue_changed(&pset->ips_messages); imq_unlock(&pset->ips_messages); splx(s); /* XXXX Perhaps ought to verify ips_thread_pool is empty */ ips_release(pset); /* consume the ref our caller gave us */ ips_check_unlock(pset); }
static void filt_machportdetach( struct knote *kn) { ipc_pset_t pset = kn->kn_ptr.p_pset; /* * Unlink the portset wait queue from knote/kqueue, * and release our reference on the portset. */ ips_lock(pset); (void)knote_unlink_waitq(kn, &pset->ips_messages.imq_wait_queue); kn->kn_ptr.p_pset = IPS_NULL; ips_unlock(pset); ips_release(pset); }
void ipc_pset_destroy( ipc_pset_t pset) { assert(ips_active(pset)); pset->ips_object.io_bits &= ~IO_BITS_ACTIVE; imq_lock(&pset->ips_messages); ipc_mqueue_changed(&pset->ips_messages, MACH_RCV_PORT_DIED); imq_unlock(&pset->ips_messages); /* Common destruction for the IPC target. */ ipc_target_terminate(&pset->ips_target); ips_release(pset); /* consume the ref our caller gave us */ ips_check_unlock(pset); }
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_port_clear_receiver( ipc_port_t port) { ipc_pset_t pset; assert(ip_active(port)); pset = port->ip_pset; if (pset != IPS_NULL) { ips_lock(pset); ipc_pset_remove(pset, port); ips_unlock(pset); ips_release(pset); } ipc_port_changed(port, MACH_RCV_PORT_DIED); ipc_port_set_mscount(port, 0); port->ip_seqno = 0; }
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); } }
void ipc_port_set_seqno( ipc_port_t port, mach_port_seqno_t seqno) { if (port->ip_pset != IPS_NULL) { ipc_pset_t pset = port->ip_pset; ips_lock(pset); if (!ips_active(pset)) { ipc_pset_remove(pset, port); ips_unlock(pset); ips_release(pset); goto no_port_set; } else { port->ip_seqno = seqno; } } else { no_port_set: port->ip_seqno = seqno; } }
void ipc_pset_remove( ipc_pset_t pset, ipc_port_t port) { assert(ip_active(port)); assert(port->ip_pset == pset); port->ip_pset = IPS_NULL; port->ip_cur_target = &port->ip_target; ips_release(pset); imq_lock(&port->ip_messages); imq_lock(&pset->ips_messages); /* move messages from port set's queue to the port's queue */ ipc_mqueue_move(&port->ip_messages, &pset->ips_messages, port); imq_unlock(&pset->ips_messages); imq_unlock(&port->ip_messages); }
static int filt_machport( struct knote *kn, __unused long hint) { mach_port_name_t name = (mach_port_name_t)kn->kn_kevent.ident; ipc_pset_t pset = IPS_NULL; wait_result_t wresult; thread_t self = current_thread(); kern_return_t kr; mach_msg_option_t option; mach_msg_size_t size; /* never called from below */ assert(hint == 0); /* * called from user context. Have to validate the * name. If it changed, we have an EOF situation. */ kr = ipc_object_translate(current_space(), name, MACH_PORT_RIGHT_PORT_SET, (ipc_object_t *)&pset); if (kr != KERN_SUCCESS || pset != kn->kn_ptr.p_pset || !ips_active(pset)) { kn->kn_data = 0; kn->kn_flags |= (EV_EOF | EV_ONESHOT); if (pset != IPS_NULL) { ips_unlock(pset); } return(1); } /* just use the reference from here on out */ ips_reference(pset); ips_unlock(pset); /* * Only honor supported receive options. If no options are * provided, just force a MACH_RCV_TOO_LARGE to detect the * name of the port and sizeof the waiting message. */ option = kn->kn_sfflags & (MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_LARGE_IDENTITY| MACH_RCV_TRAILER_MASK|MACH_RCV_VOUCHER); if (option & MACH_RCV_MSG) { self->ith_msg_addr = (mach_vm_address_t) kn->kn_ext[0]; size = (mach_msg_size_t)kn->kn_ext[1]; } else { option = MACH_RCV_LARGE; self->ith_msg_addr = 0; size = 0; } /* * Set up to receive a message or the notification of a * too large message. But never allow this call to wait. * If the user provided aditional options, like trailer * options, pass those through here. But we don't support * scatter lists through this interface. */ self->ith_object = (ipc_object_t)pset; self->ith_msize = size; self->ith_option = option; self->ith_receiver_name = MACH_PORT_NULL; self->ith_continuation = NULL; option |= MACH_RCV_TIMEOUT; // never wait self->ith_state = MACH_RCV_IN_PROGRESS; wresult = ipc_mqueue_receive_on_thread( &pset->ips_messages, option, size, /* max_size */ 0, /* immediate timeout */ THREAD_INTERRUPTIBLE, self); assert(wresult == THREAD_NOT_WAITING); assert(self->ith_state != MACH_RCV_IN_PROGRESS); /* * If we timed out, just release the reference on the * portset and return zero. */ if (self->ith_state == MACH_RCV_TIMED_OUT) { ips_release(pset); return 0; } /* * If we weren't attempting to receive a message * directly, we need to return the port name in * the kevent structure. */ if ((option & MACH_RCV_MSG) != MACH_RCV_MSG) { assert(self->ith_state == MACH_RCV_TOO_LARGE); assert(self->ith_kmsg == IKM_NULL); kn->kn_data = self->ith_receiver_name; ips_release(pset); return 1; } /* * Attempt to receive the message directly, returning * the results in the fflags field. */ assert(option & MACH_RCV_MSG); kn->kn_ext[1] = self->ith_msize; kn->kn_data = MACH_PORT_NULL; kn->kn_fflags = mach_msg_receive_results(); /* kmsg and pset reference consumed */ /* * if the user asked for the identity of ports containing a * a too-large message, return it in the data field (as we * do for messages we didn't try to receive). */ if ((kn->kn_fflags == MACH_RCV_TOO_LARGE) && (option & MACH_RCV_LARGE_IDENTITY)) kn->kn_data = self->ith_receiver_name; return 1; }