void ipc_port_set_qlimit( ipc_port_t port, mach_port_msgcount_t qlimit) { assert(ip_active(port)); /* wake up senders allowed by the new qlimit */ if (qlimit > port->ip_qlimit) { mach_port_msgcount_t i, wakeup; /* caution: wakeup, qlimit are unsigned */ wakeup = qlimit - port->ip_qlimit; for (i = 0; i < wakeup; i++) { ipc_thread_t th; th = ipc_thread_dequeue(&port->ip_blocked); if (th == ITH_NULL) break; th->ith_state = MACH_MSG_SUCCESS; thread_go(th); } } port->ip_qlimit = qlimit; }
void ipc_mqueue_move( ipc_mqueue_t dest, ipc_mqueue_t source, const ipc_port_t port) { ipc_kmsg_queue_t oldq, newq; ipc_thread_queue_t blockedq; ipc_kmsg_t kmsg, next; ipc_thread_t th; oldq = &source->imq_messages; newq = &dest->imq_messages; blockedq = &dest->imq_threads; for (kmsg = ipc_kmsg_queue_first(oldq); kmsg != IKM_NULL; kmsg = next) { next = ipc_kmsg_queue_next(oldq, kmsg); /* only move messages sent to port */ if (kmsg->ikm_header.msgh_remote_port != (mach_port_t) port) continue; ipc_kmsg_rmqueue(oldq, kmsg); /* before adding kmsg to newq, check for a blocked receiver */ while ((th = ipc_thread_dequeue(blockedq)) != ITH_NULL) { assert(ipc_kmsg_queue_empty(newq)); thread_go(th); /* check if the receiver can handle the message */ if (kmsg->ikm_header.msgh_size <= th->ith_msize) { th->ith_state = MACH_MSG_SUCCESS; th->ith_kmsg = kmsg; th->ith_seqno = port->ip_seqno++; goto next_kmsg; } th->ith_state = MACH_RCV_TOO_LARGE; th->ith_msize = kmsg->ikm_header.msgh_size; } /* didn't find a receiver to handle the message */ ipc_kmsg_enqueue(newq, kmsg); next_kmsg:; } }
void ipc_mqueue_changed( ipc_mqueue_t mqueue, mach_msg_return_t mr) { ipc_thread_t th; while ((th = ipc_thread_dequeue(&mqueue->imq_threads)) != ITH_NULL) { th->ith_state = mr; thread_go(th); } }
void ipc_mqueue_move( ipc_mqueue_t dest, ipc_mqueue_t source, ipc_port_t port) { ipc_kmsg_queue_t oldq, newq; ipc_thread_queue_t blockedq; ipc_kmsg_t kmsg, next; ipc_thread_t th; oldq = &source->imq_messages; newq = &dest->imq_messages; blockedq = &dest->imq_threads; for (kmsg = ipc_kmsg_queue_first(oldq); kmsg != IKM_NULL; kmsg = next) { next = ipc_kmsg_queue_next(oldq, kmsg); /* only move messages sent to port */ if (kmsg->ikm_header.msgh_remote_port != (mach_port_t) port) continue; ipc_kmsg_rmqueue(oldq, kmsg); /* before adding kmsg to newq, check for a blocked receiver */ if ((th = ipc_thread_dequeue(blockedq)) != ITH_NULL) { assert(ipc_kmsg_queue_empty(newq)); /* * Got a receiver. Hand the receiver the message * and process the next one. */ th->ith_state = MACH_MSG_SUCCESS; th->ith_kmsg = kmsg; th->ith_seqno = port->ip_seqno++; thread_go(th); } else { /* didn't find a receiver; enqueue the message */ ipc_kmsg_enqueue(newq, kmsg); } } }
void ipc_port_destroy( ipc_port_t port) { ipc_port_t pdrequest, nsrequest; ipc_mqueue_t mqueue; ipc_kmsg_queue_t kmqueue; ipc_kmsg_t kmsg; ipc_thread_t sender; ipc_port_request_t dnrequests; thread_pool_t thread_pool; assert(ip_active(port)); /* port->ip_receiver_name is garbage */ /* port->ip_receiver/port->ip_destination is garbage */ assert(io_otype((ipc_object_t)port) == IOT_PORT); assert(port->ip_pset == IPS_NULL); assert(port->ip_mscount == 0); assert(port->ip_seqno == 0); /* first check for a backup port */ pdrequest = port->ip_pdrequest; if (pdrequest != IP_NULL) { /* we assume the ref for pdrequest */ port->ip_pdrequest = IP_NULL; /* make port be in limbo */ port->ip_receiver_name = MACH_PORT_NAME_NULL; port->ip_destination = IP_NULL; ip_unlock(port); if (!ipc_port_check_circularity(port, pdrequest)) { /* consumes our refs for port and pdrequest */ ipc_notify_port_destroyed(pdrequest, port); return; } else { /* consume pdrequest and destroy port */ ipc_port_release_sonce(pdrequest); } ip_lock(port); assert(ip_active(port)); assert(port->ip_pset == IPS_NULL); assert(port->ip_mscount == 0); assert(port->ip_seqno == 0); assert(port->ip_pdrequest == IP_NULL); assert(port->ip_receiver_name == MACH_PORT_NAME_NULL); assert(port->ip_destination == IP_NULL); /* fall through and destroy the port */ } /* * rouse all blocked senders * * This must be done with the port locked, because * ipc_mqueue_send can play with the ip_blocked queue * of a dead port. */ while ((sender = ipc_thread_dequeue(&port->ip_blocked)) != ITH_NULL) { sender->ith_state = MACH_MSG_SUCCESS; thread_go(sender); } /* once port is dead, we don't need to keep it locked */ port->ip_object.io_bits &= ~IO_BITS_ACTIVE; port->ip_timestamp = ipc_port_timestamp(); /* save for later */ dnrequests = port->ip_dnrequests; port->ip_dnrequests = IPR_NULL; ip_unlock(port); /* wakeup any threads waiting on this pool port for an activation */ if ((thread_pool = &port->ip_thread_pool) != THREAD_POOL_NULL) thread_pool_wakeup(thread_pool); /* throw away no-senders request */ nsrequest = port->ip_nsrequest; if (nsrequest != IP_NULL) ipc_notify_send_once(nsrequest); /* consumes ref */ /* destroy any queued messages */ mqueue = &port->ip_messages; kmqueue = &mqueue->imq_messages; while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL) { assert(kmsg->ikm_header->msgh_remote_port == (mach_port_t) port); port->ip_msgcount--; ipc_port_release(port); kmsg->ikm_header->msgh_remote_port = MACH_PORT_NULL; ipc_kmsg_destroy(kmsg); } /* generate dead-name notifications */ if (dnrequests != IPR_NULL) { ipc_port_dnnotify(port, dnrequests); } if (ip_kotype(port) != IKOT_NONE) ipc_kobject_destroy(port); /* XXXX Perhaps should verify that ip_thread_pool is empty! */ ipc_port_release(port); /* consume caller's ref */ }