From 023ccefb1c32b8f79081f6cca03c529f8d38b12c Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Sun, 7 Dec 2014 14:27:23 +0100 Subject: [PATCH gnumach 2/2] Add a new flavor of no-senders notifications The no-senders notifications do not carry a port name. Add a new flavor of no-senders notifications `MACH_NOTIFY_NO_SENDERS2' that does carry the name of the port that lost the last sender. * include/mach/notify.defs (mach_notify_no_senders2): New simple routine. * include/mach/notify.h (MACH_NOTIFY_NO_SENDERS2): New macro. * ipc/ipc_notify.c (ipc_notify_no_senders2_template, ipc_notify_init_no_senders2, ipc_notify_init): Initialize a template. (ipc_notify_no_senders): Test whether a new-style notification has been requested. (ipc_notify_no_senders2): New function. * ipc/ipc_notify.h (ipc_notify_no_senders2): New declaration. (NSREQUEST_FLAG_NO_SENDERS2, NSREQUEST_FLAG_MASK, NSREQUEST_IPC_PORT, NSREQUEST_HAS_FLAG, NSREQUEST_SET_FLAG): Machinery to store flags in the least significant bits of the `nsrequest' field. * ipc/ipc_port.c (ipc_port_nsrequest2): Add `new_style' parameter, rename from `ipc_port_nsrequest', set flag if `new_style' is given, and filter it from the returned `previous' port. (ipc_port_nsrequest): New function. (ipc_port_destroy): Filter out flags from `ip_nsrequest'. * ipc/ipc_port.h (struct ipc_port): Document the use of flags. (ipc_port_nsrequest2): New declaration. * ipc/mach_port.c (mach_port_request_notification): Handle MACH_NOTIFY_NO_SENDERS2. --- include/mach/notify.defs | 9 ++++++ include/mach/notify.h | 11 +++++++ ipc/ipc_notify.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ ipc/ipc_notify.h | 14 ++++++++ ipc/ipc_port.c | 36 ++++++++++++++++++--- ipc/ipc_port.h | 10 +++++- ipc/mach_port.c | 6 ++-- 7 files changed, 162 insertions(+), 8 deletions(-) diff --git a/include/mach/notify.defs b/include/mach/notify.defs index 6ba4cde..06802ce 100644 --- a/include/mach/notify.defs +++ b/include/mach/notify.defs @@ -110,3 +110,12 @@ simpleroutine mach_notify_dead_name( msgseqno seqno : mach_port_seqno_t; #endif name : mach_port_name_t); + +/* MACH_NOTIFY_NO_SENDERS2: 0111 */ +simpleroutine mach_notify_no_senders2( + notify : notify_port_t; +#if SEQNOS + msgseqno seqno : mach_port_seqno_t; +#endif + name : mach_port_name_t; + mscount : mach_port_mscount_t); diff --git a/include/mach/notify.h b/include/mach/notify.h index 6d783dd..d3b4c01 100644 --- a/include/mach/notify.h +++ b/include/mach/notify.h @@ -53,6 +53,9 @@ /* An extant send-once right died */ #define MACH_NOTIFY_DEAD_NAME (MACH_NOTIFY_FIRST + 010) /* Send or send-once right died, leaving a dead-name */ +#define MACH_NOTIFY_NO_SENDERS2 (MACH_NOTIFY_FIRST + 011) + /* Receive right has no extant send rights, + new version. */ #define MACH_NOTIFY_LAST (MACH_NOTIFY_FIRST + 015) typedef struct { @@ -81,6 +84,14 @@ typedef struct { typedef struct { mach_msg_header_t not_header; + mach_msg_type_t not_port_type; /* MACH_MSG_TYPE_PORT_NAME */ + mach_port_t not_port; + mach_msg_type_t not_type; /* MACH_MSG_TYPE_INTEGER_32 */ + unsigned int not_count; +} mach_no_senders_notification2_t; + +typedef struct { + mach_msg_header_t not_header; } mach_send_once_notification_t; typedef struct { diff --git a/ipc/ipc_notify.c b/ipc/ipc_notify.c index df5f68b..8a2c210 100644 --- a/ipc/ipc_notify.c +++ b/ipc/ipc_notify.c @@ -47,6 +47,7 @@ mach_port_deleted_notification_t ipc_notify_port_deleted_template; mach_msg_accepted_notification_t ipc_notify_msg_accepted_template; mach_port_destroyed_notification_t ipc_notify_port_destroyed_template; mach_no_senders_notification_t ipc_notify_no_senders_template; +mach_no_senders_notification2_t ipc_notify_no_senders2_template; mach_send_once_notification_t ipc_notify_send_once_template; mach_dead_name_notification_t ipc_notify_dead_name_template; @@ -175,6 +176,48 @@ ipc_notify_init_no_senders( } /* + * Routine: ipc_notify_init_no_senders2 + * Purpose: + * Initialize a template for no-senders2 notifications. + */ + +void +ipc_notify_init_no_senders2( + mach_no_senders_notification2_t *n) +{ + mach_msg_header_t *m = &n->not_header; + mach_msg_type_t *t; + + m->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0); + m->msgh_size = sizeof *n; + m->msgh_seqno = NOTIFY_MSGH_SEQNO; + m->msgh_local_port = MACH_PORT_NULL; + m->msgh_remote_port = MACH_PORT_NULL; + m->msgh_id = MACH_NOTIFY_NO_SENDERS2; + + t = &n->not_port_type; + t->msgt_name = MACH_MSG_TYPE_PORT_NAME; + t->msgt_size = PORT_T_SIZE_IN_BITS; + t->msgt_number = 1; + t->msgt_inline = TRUE; + t->msgt_longform = FALSE; + t->msgt_deallocate = FALSE; + t->msgt_unused = 0; + + t = &n->not_type; + t->msgt_name = MACH_MSG_TYPE_INTEGER_32; + t->msgt_size = PORT_T_SIZE_IN_BITS; + t->msgt_number = 1; + t->msgt_inline = TRUE; + t->msgt_longform = FALSE; + t->msgt_deallocate = FALSE; + t->msgt_unused = 0; + + n->not_port = MACH_PORT_NULL; + n->not_count = 0; +} + +/* * Routine: ipc_notify_init_send_once * Purpose: * Initialize a template for send-once notifications. @@ -238,6 +281,7 @@ ipc_notify_init(void) ipc_notify_init_msg_accepted(&ipc_notify_msg_accepted_template); ipc_notify_init_port_destroyed(&ipc_notify_port_destroyed_template); ipc_notify_init_no_senders(&ipc_notify_no_senders_template); + ipc_notify_init_no_senders2(&ipc_notify_no_senders2_template); ipc_notify_init_send_once(&ipc_notify_send_once_template); ipc_notify_init_dead_name(&ipc_notify_dead_name_template); } @@ -366,6 +410,11 @@ ipc_notify_no_senders( ipc_kmsg_t kmsg; mach_no_senders_notification_t *n; + if (NSREQUEST_HAS_FLAG (port, NSREQUEST_FLAG_NO_SENDERS2)) { + ipc_notify_no_senders2 (NSREQUEST_IPC_PORT (port), mscount); + return; + } + kmsg = ikm_alloc(sizeof *n); if (kmsg == IKM_NULL) { printf("dropped no-senders (0x%p, %u)\n", port, mscount); @@ -384,6 +433,41 @@ ipc_notify_no_senders( } /* + * Routine: ipc_notify_no_senders2 + * Purpose: + * Send a no-senders2 notification. + * Conditions: + * Nothing locked. + * Consumes a ref/soright for port. + */ + +void +ipc_notify_no_senders2( + ipc_port_t port, + mach_port_mscount_t mscount) +{ + ipc_kmsg_t kmsg; + mach_no_senders_notification2_t *n; + + kmsg = ikm_alloc(sizeof *n); + if (kmsg == IKM_NULL) { + printf("dropped no-senders (0x%p, %u)\n", port, mscount); + ipc_port_release_sonce(port); + return; + } + + ikm_init(kmsg, sizeof *n); + n = (mach_no_senders_notification2_t *) &kmsg->ikm_header; + *n = ipc_notify_no_senders2_template; + + n->not_header.msgh_remote_port = (mach_port_t) port; + n->not_count = mscount; + n->not_port = port->ip_receiver_name; + + ipc_mqueue_send_always(kmsg); +} + +/* * Routine: ipc_notify_send_once * Purpose: * Send a send-once notification. diff --git a/ipc/ipc_notify.h b/ipc/ipc_notify.h index 789bd23..b1fa090 100644 --- a/ipc/ipc_notify.h +++ b/ipc/ipc_notify.h @@ -50,6 +50,20 @@ extern void ipc_notify_no_senders(ipc_port_t, mach_port_mscount_t); extern void +ipc_notify_no_senders2 (ipc_port_t, mach_port_mscount_t); + +/* No-senders notifications come in two flavors. We use the least + significant bit to indicate that the new flavor was requested. */ +#define NSREQUEST_FLAG_NO_SENDERS2 0x1 +#define NSREQUEST_FLAG_MASK 0x1 +#define NSREQUEST_IPC_PORT(X) \ + ((ipc_port_t) ((unsigned long) (X) &~ NSREQUEST_FLAG_MASK)) +#define NSREQUEST_HAS_FLAG(X, F) \ + ((unsigned long) (X) & F) +#define NSREQUEST_SET_FLAG(X, F) \ + ((ipc_port_t) ((unsigned long) (X) | F)) + +extern void ipc_notify_send_once(ipc_port_t); extern void diff --git a/ipc/ipc_port.c b/ipc/ipc_port.c index 89a5d67..8817c49 100644 --- a/ipc/ipc_port.c +++ b/ipc/ipc_port.c @@ -290,7 +290,7 @@ ipc_port_pdrequest( } /* - * Routine: ipc_port_nsrequest + * Routine: ipc_port_nsrequest2 * Purpose: * Make a no-senders request, returning the * previously registered send-once right. @@ -302,8 +302,9 @@ ipc_port_pdrequest( */ void -ipc_port_nsrequest( +ipc_port_nsrequest2( ipc_port_t port, + boolean_t new_style, mach_port_mscount_t sync, ipc_port_t notify, ipc_port_t *previousp) @@ -313,7 +314,7 @@ ipc_port_nsrequest( assert(ip_active(port)); - previous = port->ip_nsrequest; + previous = NSREQUEST_IPC_PORT (port->ip_nsrequest); mscount = port->ip_mscount; if ((port->ip_srights == 0) && @@ -323,7 +324,10 @@ ipc_port_nsrequest( ip_unlock(port); ipc_notify_no_senders(notify, mscount); } else { - port->ip_nsrequest = notify; + port->ip_nsrequest = new_style + ? NSREQUEST_SET_FLAG (notify, + NSREQUEST_FLAG_NO_SENDERS2) + : notify; ip_unlock(port); } @@ -331,6 +335,28 @@ ipc_port_nsrequest( } /* + * Routine: ipc_port_nsrequest + * Purpose: + * Make a no-senders request, returning the + * previously registered send-once right. + * Just cancels the previous request if notify is IP_NULL. + * Conditions: + * The port is locked and active. It is unlocked. + * Consumes a ref for notify (if non-null), and + * returns previous with a ref (if non-null). + */ + +void +ipc_port_nsrequest( + ipc_port_t port, + mach_port_mscount_t sync, + ipc_port_t notify, + ipc_port_t *previousp) +{ + ipc_port_nsrequest2 (port, FALSE, sync, notify, previousp); +} + +/* * Routine: ipc_port_set_qlimit * Purpose: * Changes a port's queue limit; the maximum number @@ -698,7 +724,7 @@ ipc_port_destroy( /* throw away no-senders request */ - nsrequest = port->ip_nsrequest; + nsrequest = NSREQUEST_IPC_PORT (port->ip_nsrequest); if (nsrequest != IP_NULL) ipc_notify_send_once(nsrequest); /* consumes ref */ diff --git a/ipc/ipc_port.h b/ipc/ipc_port.h index 6914c71..e614ae8 100644 --- a/ipc/ipc_port.h +++ b/ipc/ipc_port.h @@ -88,7 +88,7 @@ struct ipc_port { mach_port_rights_t ip_srights; mach_port_rights_t ip_sorights; - struct ipc_port *ip_nsrequest; + struct ipc_port *ip_nsrequest; /* flags in the LSBs */ struct ipc_port *ip_pdrequest; struct ipc_port_request *ip_dnrequests; @@ -245,6 +245,14 @@ extern void ipc_port_nsrequest( ipc_port_t notify, ipc_port_t *previousp); +/* Make a no-senders request, new version. */ +extern void ipc_port_nsrequest2( + ipc_port_t port, + boolean_t new_style, + mach_port_mscount_t sync, + ipc_port_t notify, + ipc_port_t *previousp); + /* Change a port's queue limit */ extern void ipc_port_set_qlimit( ipc_port_t port, diff --git a/ipc/mach_port.c b/ipc/mach_port.c index c7d9b81..ad10cd2 100644 --- a/ipc/mach_port.c +++ b/ipc/mach_port.c @@ -1202,7 +1202,8 @@ mach_port_request_notification( break; } - case MACH_NOTIFY_NO_SENDERS: { + case MACH_NOTIFY_NO_SENDERS: + case MACH_NOTIFY_NO_SENDERS2: { ipc_port_t port; kr = ipc_port_translate_receive(space, name, &port); @@ -1210,7 +1211,8 @@ mach_port_request_notification( return kr; /* port is locked and active */ - ipc_port_nsrequest(port, sync, notify, previousp); + ipc_port_nsrequest2 (port, id == MACH_NOTIFY_NO_SENDERS2, + sync, notify, previousp); /* port is unlocked */ break; } -- 2.1.3