X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..a1c7dba18ef36983396c282fe85292db066e39db:/osfmk/ipc/ipc_pset.c diff --git a/osfmk/ipc/ipc_pset.c b/osfmk/ipc/ipc_pset.c index 462527119..533ee3f08 100644 --- a/osfmk/ipc/ipc_pset.c +++ b/osfmk/ipc/ipc_pset.c @@ -72,7 +72,6 @@ #include #include #include -#include #include #include @@ -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 */ @@ -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; @@ -521,57 +557,5 @@ 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 -#if MACH_KDB - -#include - -#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 */