/*
- * Copyright (c) 2000-2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2016 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#ifndef _IPC_IPC_PORT_H_
#define _IPC_IPC_PORT_H_
-#if MACH_KERNEL_PRIVATE
+#ifdef MACH_KERNEL_PRIVATE
-#include <mach_rt.h>
#include <mach_assert.h>
#include <mach_debug.h>
#include <kern/assert.h>
#include <kern/kern_types.h>
+#include <kern/turnstile.h>
#include <ipc/ipc_types.h>
#include <ipc/ipc_object.h>
union {
ipc_kobject_t kobject;
ipc_importance_task_t imp_task;
- uintptr_t alias;
+ ipc_port_t sync_inheritor_port;
+ struct knote *sync_inheritor_knote;
+ struct turnstile *sync_inheritor_ts;
} kdata;
-
+
struct ipc_port *ip_nsrequest;
struct ipc_port *ip_pdrequest;
struct ipc_port_request *ip_requests;
- struct ipc_kmsg *ip_premsg;
+ union {
+ struct ipc_kmsg *premsg;
+ struct turnstile *send_turnstile;
+ SLIST_ENTRY(ipc_port) dealloc_elm;
+ } kdata2;
- mach_port_mscount_t ip_mscount;
- mach_port_rights_t ip_srights;
- mach_port_rights_t ip_sorights;
+ mach_vm_address_t ip_context;
natural_t ip_sprequests:1, /* send-possible requests outstanding */
ip_spimportant:1, /* ... at least one is importance donating */
ip_tempowner:1, /* dont give donations to current receiver */
ip_guarded:1, /* port guarded (use context value as guard) */
ip_strict_guard:1, /* Strict guarding; Prevents user manipulation of context values directly */
- ip_reserved:2,
- ip_impcount:24; /* number of importance donations in nested queue */
-
- mach_vm_address_t ip_context;
+ ip_specialreply:1, /* port is a special reply port */
+ ip_sync_link_state:3, /* link the special reply port to destination port/ Workloop */
+ ip_impcount:22; /* number of importance donations in nested queue */
+ mach_port_mscount_t ip_mscount;
+ mach_port_rights_t ip_srights;
+ mach_port_rights_t ip_sorights;
#if MACH_ASSERT
#define IP_NSPARES 4
#define IP_CALLSTACK_MAX 16
- queue_chain_t ip_port_links; /* all allocated ports */
+/* queue_chain_t ip_port_links;*//* all allocated ports */
thread_t ip_thread; /* who made me? thread context */
unsigned long ip_timetrack; /* give an idea of "when" created */
uintptr_t ip_callstack[IP_CALLSTACK_MAX]; /* stack trace */
unsigned long ip_spares[IP_NSPARES]; /* for debugging */
#endif /* MACH_ASSERT */
+#if DEVELOPMENT || DEBUG
+ uint8_t ip_srp_lost_link:1, /* special reply port turnstile link chain broken */
+ ip_srp_msg_sent:1; /* special reply port msg sent */
+#endif
};
#define ip_bits ip_object.io_bits
#define ip_receiver_name ip_messages.imq_receiver_name
-#define ip_pset_count ip_messages.imq_pset_count
+#define ip_in_pset ip_messages.imq_in_pset
#define ip_receiver data.receiver
#define ip_destination data.destination
#define ip_kobject kdata.kobject
#define ip_imp_task kdata.imp_task
-#define ip_alias kdata.alias
+#define ip_sync_inheritor_port kdata.sync_inheritor_port
+#define ip_sync_inheritor_knote kdata.sync_inheritor_knote
+#define ip_sync_inheritor_ts kdata.sync_inheritor_ts
+
+#define ip_premsg kdata2.premsg
+#define ip_send_turnstile kdata2.send_turnstile
+#define ip_dealloc_elm kdata2.dealloc_elm
+
+#define port_send_turnstile(port) (IP_PREALLOC(port) ? (port)->ip_premsg->ikm_turnstile : (port)->ip_send_turnstile)
+
+#define set_port_send_turnstile(port, value) \
+MACRO_BEGIN \
+if (IP_PREALLOC(port)) { \
+ (port)->ip_premsg->ikm_turnstile = (value); \
+} else { \
+ (port)->ip_send_turnstile = (value); \
+} \
+MACRO_END
+
+#define port_send_turnstile_address(port) \
+(IP_PREALLOC(port) ? &((port)->ip_premsg->ikm_turnstile) : &((port)->ip_send_turnstile))
+
+#define port_rcv_turnstile_address(port) (NULL)
+
+
+/*
+ * SYNC IPC state flags for special reply port.
+ *
+ * PORT_SYNC_LINK_ANY
+ * Special reply port is not linked to any other port
+ * or WL and linkage should be allowed.
+ *
+ * PORT_SYNC_LINK_PORT
+ * Special reply port is linked to the port and
+ * ip_sync_inheritor_port contains the inheritor
+ * port.
+ *
+ * PORT_SYNC_LINK_WORKLOOP_KNOTE
+ * Special reply port is linked to a WL (via a knote).
+ * ip_sync_inheritor_knote contains a pointer to the knote
+ * the port is stashed on.
+ *
+ * PORT_SYNC_LINK_WORKLOOP_STASH
+ * Special reply port is linked to a WL (via a knote stash).
+ * ip_sync_inheritor_ts contains a pointer to the turnstile with a +1
+ * the port is stashed on.
+ *
+ * PORT_SYNC_LINK_NO_LINKAGE
+ * Message sent to special reply port, do
+ * not allow any linkages till receive is
+ * complete.
+ */
+#define PORT_SYNC_LINK_ANY (0)
+#define PORT_SYNC_LINK_PORT (0x1)
+#define PORT_SYNC_LINK_WORKLOOP_KNOTE (0x2)
+#define PORT_SYNC_LINK_WORKLOOP_STASH (0x3)
+#define PORT_SYNC_LINK_NO_LINKAGE (0x4)
#define IP_NULL IPC_PORT_NULL
#define IP_DEAD IPC_PORT_DEAD
#define ip_lock_init(port) io_lock_init(&(port)->ip_object)
#define ip_lock(port) io_lock(&(port)->ip_object)
#define ip_lock_try(port) io_lock_try(&(port)->ip_object)
+#define ip_lock_held_kdp(port) io_lock_held_kdp(&(port)->ip_object)
#define ip_unlock(port) io_unlock(&(port)->ip_object)
#define ip_reference(port) io_reference(&(port)->ip_object)
#define ip_release(port) io_release(&(port)->ip_object)
+/* get an ipc_port pointer from an ipc_mqueue pointer */
+#define ip_from_mq(mq) \
+ __container_of(mq, struct ipc_port, ip_messages)
+
+#define ip_reference_mq(mq) ip_reference(ip_from_mq(mq))
+#define ip_release_mq(mq) ip_release(ip_from_mq(mq))
+
#define ip_kotype(port) io_kotype(&(port)->ip_object)
#define ip_full_kernel(port) imq_full_kernel(&(port)->ip_messages)
ipc_port_request_index_t index);
/* Arm any delayed send-possible notification */
-#if IMPORTANCE_INHERITANCE
extern boolean_t ipc_port_request_sparm(
- ipc_port_t port,
- mach_port_name_t name,
- ipc_port_request_index_t index,
- mach_msg_option_t option);
-#else
-extern boolean_t ipc_port_request_sparm(
- ipc_port_t port,
- mach_port_name_t name,
- ipc_port_request_index_t index);
-#endif /* IMPORTANCE_INHERITANCE */
+ ipc_port_t port,
+ mach_port_name_t name,
+ ipc_port_request_index_t index,
+ mach_msg_option_t option,
+ mach_msg_priority_t override);
/* Macros for manipulating a port's dead name notificaiton requests */
#define ipc_port_request_rename(port, index, oname, nname) \
MACRO_END
/* Prepare a receive right for transmission/destruction */
-extern void ipc_port_clear_receiver(
+extern boolean_t ipc_port_clear_receiver(
ipc_port_t port,
- queue_t links);
+ boolean_t should_destroy);
/* Initialize a newly-allocated port */
extern void ipc_port_init(
ipc_port_t dest);
#if IMPORTANCE_INHERITANCE
+
+enum {
+ IPID_OPTION_NORMAL = 0, /* normal boost */
+ IPID_OPTION_SENDPOSSIBLE = 1, /* send-possible induced boost */
+};
+
+/* link the destination port with special reply port */
+void
+ipc_port_link_special_reply_port(
+ ipc_port_t special_reply_port,
+ ipc_port_t dest_port);
+
+#define IPC_PORT_ADJUST_SR_NONE 0
+#define IPC_PORT_ADJUST_SR_CLEAR_SPECIAL_REPLY 0x1
+#define IPC_PORT_ADJUST_SR_ALLOW_SYNC_LINKAGE 0x2
+#define IPC_PORT_ADJUST_SR_LINK_WORKLOOP 0x4
+
+#define IPC_PORT_ADJUST_SR_RECEIVED_MSG 0x8
+#define IPC_PORT_ADJUST_SR_ENABLE_EVENT 0x10
+
+void
+reset_ip_srp_bits(ipc_port_t special_reply_port);
+
+void
+reset_ip_srp_msg_sent(ipc_port_t special_reply_port);
+
+void
+set_ip_srp_msg_sent(ipc_port_t special_reply_port);
+
+void
+set_ip_srp_lost_link(ipc_port_t special_reply_port);
+
+/* Adjust special reply port linkage */
+void ipc_port_adjust_special_reply_port_locked(
+ ipc_port_t special_reply_port,
+ struct knote *kn,
+ uint8_t flags,
+ boolean_t get_turnstile);
+
+/* Adjust special reply port linkage */
+void
+ipc_port_adjust_special_reply_port(
+ ipc_port_t special_reply_port,
+ uint8_t flags,
+ boolean_t get_turnstile);
+
+turnstile_inheritor_t
+ipc_port_get_special_reply_port_inheritor(
+ ipc_port_t special_reply_port);
+
+void
+ipc_port_send_turnstile_prepare(ipc_port_t port);
+
+void
+ipc_port_send_turnstile_complete(ipc_port_t port);
+
+struct waitq *
+ipc_port_rcv_turnstile_waitq(struct waitq *waitq);
+
+struct turnstile *
+ipc_port_rcv_turnstile(ipc_port_t port);
+
/* apply importance delta to port only */
extern mach_port_delta_t
ipc_port_impcount_delta(
extern boolean_t
ipc_port_importance_delta_internal(
ipc_port_t port,
- mach_port_delta_t *delta,
+ natural_t options,
+ mach_port_delta_t *deltap,
ipc_importance_task_t *imp_task);
/* Apply an importance delta to a port and reflect change in receiver task */
extern boolean_t
ipc_port_importance_delta(
ipc_port_t port,
+ natural_t options,
mach_port_delta_t delta);
#endif /* IMPORTANCE_INHERITANCE */
ipc_port_t sright,
ipc_space_t space);
+/* Copyout a naked send right to given name */
+extern mach_port_name_t ipc_port_copyout_name_send(
+ ipc_port_t sright,
+ ipc_space_t space,
+ mach_port_name_t name);
+
#endif /* MACH_KERNEL_PRIVATE */
#if KERNEL_PRIVATE
#endif /* KERNEL_PRIVATE */
-#if MACH_KERNEL_PRIVATE
+#ifdef MACH_KERNEL_PRIVATE
/* Make a naked send-once right from a locked and active receive right */
extern ipc_port_t ipc_port_make_sonce_locked(
extern void ipc_port_debug_init(void);
#endif /* MACH_ASSERT */
+extern struct turnstile *ipc_port_get_inheritor(
+ ipc_port_t port);
+
#define ipc_port_alloc_kernel() \
ipc_port_alloc_special(ipc_space_kernel)
#define ipc_port_dealloc_kernel(port) \