#include <ipc/ipc_right.h>
#include <ipc/ipc_space.h>
#include <ipc/ipc_port.h>
-#include <ipc/ipc_print.h>
#include <kern/kern_types.h>
#include <kern/spl.h>
&name, (ipc_object_t *) &pset);
if (kr != KERN_SUCCESS)
return kr;
- /* pset is locked */
+ /* pset and space are locked */
pset->ips_local_name = name;
ipc_mqueue_init(&pset->ips_messages, TRUE /* set */);
+ is_write_unlock(space);
*namep = name;
*psetp = pset;
kern_return_t
ipc_pset_add(
- ipc_pset_t pset,
- ipc_port_t port)
+ ipc_pset_t pset,
+ ipc_port_t port,
+ wait_queue_link_t wql)
{
kern_return_t kr;
assert(ips_active(pset));
assert(ip_active(port));
- kr = ipc_mqueue_add(&port->ip_messages, &pset->ips_messages);
+ kr = ipc_mqueue_add(&port->ip_messages, &pset->ips_messages, wql);
if (kr == KERN_SUCCESS)
port->ip_pset_count++;
kern_return_t
ipc_pset_remove(
- ipc_pset_t pset,
- ipc_port_t port)
+ ipc_pset_t pset,
+ ipc_port_t port,
+ wait_queue_link_t *wqlp)
{
kern_return_t kr;
if (port->ip_pset_count == 0)
return KERN_NOT_IN_SET;
- kr = ipc_mqueue_remove(&port->ip_messages, &pset->ips_messages);
+ kr = ipc_mqueue_remove(&port->ip_messages, &pset->ips_messages, wqlp);
if (kr == KERN_SUCCESS)
port->ip_pset_count--;
kern_return_t
ipc_pset_remove_from_all(
- ipc_port_t port)
+ ipc_port_t port,
+ queue_t links)
{
assert(ip_active(port));
/*
* Remove the port's mqueue from all sets
*/
- ipc_mqueue_remove_from_all(&port->ip_messages);
+ ipc_mqueue_remove_from_all(&port->ip_messages, links);
port->ip_pset_count = 0;
return KERN_SUCCESS;
}
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));
/*
* remove all the member message queues
*/
- ipc_mqueue_remove_all(&pset->ips_messages);
+ ipc_mqueue_remove_all(&pset->ips_messages, links);
/*
* Set all waiters on the portset running to
imq_unlock(&pset->ips_messages);
splx(s);
- ips_release(pset); /* consume the ref our caller gave us */
- ips_check_unlock(pset);
+ 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);
+ }
+
}
/* Kqueue EVFILT_MACHPORT support */
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;
MACH_PORT_RIGHT_PORT_SET,
(ipc_object_t *)&pset);
if (kr != KERN_SUCCESS) {
- result = (kr == KERN_INVALID_NAME ? ENOENT : ENOTSUP);
- goto done;
+ wait_queue_link_free(wql);
+ return (kr == KERN_INVALID_NAME ? ENOENT : ENOTSUP);
}
/* We've got a lock on pset */
- /* keep a reference for the knote */
- kn->kn_ptr.p_pset = pset;
- ips_reference(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);
+ 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);
-done:
+ wait_queue_link_free(wql);
return result;
}
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);
- knote_unlink_wait_queue(kn, &pset->ips_messages.imq_wait_queue);
- ips_release(kn->kn_ptr.p_pset);
- kn->kn_ptr.p_pset = IPS_NULL;
- ips_check_unlock(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);
}
static int
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_check_unlock(pset);
+ if (pset != IPS_NULL) {
+ ips_unlock(pset);
+ }
return(1);
}
* 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_TRAILER_MASK);
+ 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];
self->ith_receiver_name = MACH_PORT_NULL;
self->ith_continuation = NULL;
option |= MACH_RCV_TIMEOUT; // never wait
- assert((self->ith_state = MACH_RCV_IN_PROGRESS) == MACH_RCV_IN_PROGRESS);
+ self->ith_state = MACH_RCV_IN_PROGRESS;
wresult = ipc_mqueue_receive_on_thread(
&pset->ips_messages,
* portset and return zero.
*/
if (self->ith_state == MACH_RCV_TIMED_OUT) {
- ipc_pset_release(pset);
+ ips_release(pset);
return 0;
}
assert(self->ith_state == MACH_RCV_TOO_LARGE);
assert(self->ith_kmsg == IKM_NULL);
kn->kn_data = self->ith_receiver_name;
- ipc_pset_release(pset);
+ ips_release(pset);
return 1;
}
* the results in the fflags field.
*/
assert(option & MACH_RCV_MSG);
- kn->kn_data = MACH_PORT_NULL;
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;
}
case EVENT_REGISTER:
kn->kn_sfflags = kev->fflags;
kn->kn_sdata = kev->data;
+ kn->kn_ext[0] = kev->ext[0];
+ kn->kn_ext[1] = kev->ext[1];
break;
case EVENT_PROCESS:
*kev = kn->kn_kevent;
ipc_pset_t pset = kn->kn_ptr.p_pset;
ipc_mqueue_t set_mq = &pset->ips_messages;
- return (ipc_mqueue_peek(set_mq));
+ return (ipc_mqueue_set_peek(set_mq));
}
-
-
-#include <mach_kdb.h>
-#if MACH_KDB
-
-#include <ddb/db_output.h>
-
-#define printf kdbprintf
-
-int
-ipc_list_count(
- struct ipc_kmsg *base)
-{
- register int count = 0;
-
- if (base) {
- struct ipc_kmsg *kmsg = base;
-
- ++count;
- while (kmsg && kmsg->ikm_next != base
- && kmsg->ikm_next != IKM_BOGUS){
- kmsg = kmsg->ikm_next;
- ++count;
- }
- }
- return(count);
-}
-
-/*
- * Routine: ipc_pset_print
- * Purpose:
- * Pretty-print a port set for kdb.
- */
-void
-ipc_pset_print(
- ipc_pset_t pset)
-{
- printf("pset 0x%x\n", pset);
-
- db_indent += 2;
-
- ipc_object_print(&pset->ips_object);
- iprintf("local_name = 0x%x\n", pset->ips_local_name);
- iprintf("%d kmsgs => 0x%x",
- ipc_list_count(pset->ips_messages.imq_messages.ikmq_base),
- pset->ips_messages.imq_messages.ikmq_base);
- printf(",rcvrs queue= 0x%x\n", &pset->ips_messages.imq_wait_queue);
-
- db_indent -=2;
-}
-
-#endif /* MACH_KDB */