]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/ipc/ipc_pset.c
xnu-2782.10.72.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_pset.c
index 4e0dd2b68812b8fcd027a61183c7db48102fb719..533ee3f08a67453003d642e7566d171bca6dfb65 100644 (file)
@@ -72,7 +72,6 @@
 #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>
@@ -108,10 +107,11 @@ ipc_pset_alloc(
                              &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;
@@ -186,15 +186,16 @@ ipc_pset_member(
 
 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++;
@@ -216,8 +217,9 @@ ipc_pset_add(
 
 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;
 
@@ -226,7 +228,7 @@ ipc_pset_remove(
        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--;
@@ -244,7 +246,8 @@ ipc_pset_remove(
 
 kern_return_t
 ipc_pset_remove_from_all(
-       ipc_port_t      port)
+       ipc_port_t      port,
+       queue_t         links)
 {
        assert(ip_active(port));
        
@@ -254,7 +257,7 @@ ipc_pset_remove_from_all(
        /* 
         * 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;
 }
@@ -275,6 +278,11 @@ 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));
 
@@ -283,7 +291,7 @@ ipc_pset_destroy(
        /*
         * 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
@@ -295,8 +303,14 @@ ipc_pset_destroy(
        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 */
@@ -307,7 +321,7 @@ static int      filt_machportattach(struct knote *kn);
 static void    filt_machportdetach(struct knote *kn);
 static int     filt_machport(struct knote *kn, long hint);
 static void     filt_machporttouch(struct knote *kn, struct kevent64_s *kev, long type);
-static int     filt_machportpeek(struct knote *kn);
+static unsigned filt_machportpeek(struct knote *kn);
 struct filterops machport_filtops = {
         .f_attach = filt_machportattach,
         .f_detach = filt_machportdetach,
@@ -321,6 +335,7 @@ 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;
@@ -329,24 +344,28 @@ filt_machportattach(
                                   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;
 }
 
@@ -355,16 +374,19 @@ 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);
-       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
@@ -393,8 +415,9 @@ filt_machport(
        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);
         }
 
@@ -407,7 +430,8 @@ filt_machport(
         * 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];
@@ -431,7 +455,7 @@ filt_machport(
        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,
@@ -448,7 +472,7 @@ filt_machport(
         * portset and return zero.
         */
        if (self->ith_state == MACH_RCV_TIMED_OUT) {
-               ipc_pset_release(pset);
+               ips_release(pset);
                return 0;
        }
 
@@ -461,7 +485,7 @@ filt_machport(
                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;
        }
 
@@ -470,10 +494,20 @@ filt_machport(
         * 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;
 }
 
@@ -484,6 +518,8 @@ filt_machporttouch(struct knote *kn, struct kevent64_s *kev, long type)
         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;
@@ -515,63 +551,11 @@ filt_machporttouch(struct knote *kn, struct kevent64_s *kev, long type)
  * will catch changes in this status when the event gets posted
  * up to the knote's kqueue).
  */
-static int
+static unsigned
 filt_machportpeek(struct knote *kn)
 {
         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 */