#ifndef _IPC_IPC_KMSG_H_
#define _IPC_IPC_KMSG_H_
#include <cpus.h>
#include <mach/vm_types.h>
#include <mach/message.h>
#include <kern/assert.h>
#include <kern/cpu_number.h>
#include <kern/macro_help.h>
#include <kern/kalloc.h>
#include <ipc/ipc_object.h>
typedef struct ipc_kmsg {
struct ipc_kmsg *ikm_next;
struct ipc_kmsg *ikm_prev;
ipc_port_t ikm_prealloc;
mach_msg_size_t ikm_size;
mach_msg_header_t ikm_header;
} *ipc_kmsg_t;
#define IKM_NULL ((ipc_kmsg_t) 0)
#define IKM_OVERHEAD \
(sizeof(struct ipc_kmsg) - sizeof(mach_msg_header_t))
#define ikm_plus_overhead(size) ((mach_msg_size_t)((size) + IKM_OVERHEAD))
#define ikm_less_overhead(size) ((mach_msg_size_t)((size) - IKM_OVERHEAD))
#define IKM_BOGUS ((ipc_kmsg_t) 0xffffff10)
#define IKM_SAVED_MSG_SIZE ikm_less_overhead(256)
#define ikm_prealloc_inuse_port(kmsg) \
((kmsg)->ikm_prealloc)
#define ikm_prealloc_inuse(kmsg) \
((kmsg)->ikm_prealloc != IP_NULL)
#define ikm_prealloc_set_inuse(kmsg, port) \
MACRO_BEGIN \
assert(port != IP_NULL); \
(kmsg)->ikm_prealloc = port; \
MACRO_END
#define ikm_prealloc_clear_inuse(kmsg, port) \
MACRO_BEGIN \
(kmsg)->ikm_prealloc = IP_NULL; \
MACRO_END
#define ikm_init(kmsg, size) \
MACRO_BEGIN \
(kmsg)->ikm_size = (size); \
(kmsg)->ikm_prealloc = IP_NULL; \
assert((kmsg)->ikm_prev = (kmsg)->ikm_next = IKM_BOGUS); \
MACRO_END
#define ikm_check_init(kmsg, size) \
MACRO_BEGIN \
assert((kmsg)->ikm_size == (size)); \
assert((kmsg)->ikm_prev == IKM_BOGUS); \
assert((kmsg)->ikm_next == IKM_BOGUS); \
MACRO_END
struct ipc_kmsg_queue {
struct ipc_kmsg *ikmq_base;
};
typedef struct ipc_kmsg_queue *ipc_kmsg_queue_t;
#define IKMQ_NULL ((ipc_kmsg_queue_t) 0)
#define ipc_kmsg_queue_init(queue) \
MACRO_BEGIN \
(queue)->ikmq_base = IKM_NULL; \
MACRO_END
#define ipc_kmsg_queue_empty(queue) ((queue)->ikmq_base == IKM_NULL)
extern void ipc_kmsg_enqueue(
ipc_kmsg_queue_t queue,
ipc_kmsg_t kmsg);
extern ipc_kmsg_t ipc_kmsg_dequeue(
ipc_kmsg_queue_t queue);
extern void ipc_kmsg_rmqueue(
ipc_kmsg_queue_t queue,
ipc_kmsg_t kmsg);
#define ipc_kmsg_queue_first(queue) ((queue)->ikmq_base)
extern ipc_kmsg_t ipc_kmsg_queue_next(
ipc_kmsg_queue_t queue,
ipc_kmsg_t kmsg);
#define ipc_kmsg_rmqueue_first_macro(queue, kmsg) \
MACRO_BEGIN \
register ipc_kmsg_t _next; \
\
assert((queue)->ikmq_base == (kmsg)); \
\
_next = (kmsg)->ikm_next; \
if (_next == (kmsg)) { \
assert((kmsg)->ikm_prev == (kmsg)); \
(queue)->ikmq_base = IKM_NULL; \
} else { \
register ipc_kmsg_t _prev = (kmsg)->ikm_prev; \
\
(queue)->ikmq_base = _next; \
_next->ikm_prev = _prev; \
_prev->ikm_next = _next; \
} \
\
assert(kmsg->ikm_next = IKM_BOGUS); \
assert(kmsg->ikm_prev = IKM_BOGUS); \
MACRO_END
#define ipc_kmsg_enqueue_macro(queue, kmsg) \
MACRO_BEGIN \
register ipc_kmsg_t _first = (queue)->ikmq_base; \
\
if (_first == IKM_NULL) { \
(queue)->ikmq_base = (kmsg); \
(kmsg)->ikm_next = (kmsg); \
(kmsg)->ikm_prev = (kmsg); \
} else { \
register ipc_kmsg_t _last = _first->ikm_prev; \
\
(kmsg)->ikm_next = _first; \
(kmsg)->ikm_prev = _last; \
_first->ikm_prev = (kmsg); \
_last->ikm_next = (kmsg); \
} \
MACRO_END
#define SKIP_PORT_DESCRIPTORS(s, e) \
MACRO_BEGIN \
if ((s) != MACH_MSG_DESCRIPTOR_NULL) { \
while ((s) < (e)) { \
if ((s)->type.type != MACH_MSG_PORT_DESCRIPTOR) \
break; \
(s)++; \
} \
if ((s) >= (e)) \
(s) = MACH_MSG_DESCRIPTOR_NULL; \
} \
MACRO_END
#define INCREMENT_SCATTER(s) \
MACRO_BEGIN \
if ((s) != MACH_MSG_DESCRIPTOR_NULL) { \
(s)++; \
} \
MACRO_END
#if MACH_ASSERT
#define ipc_kmsg_send_always(kmsg) \
MACRO_BEGIN \
mach_msg_return_t mr; \
\
mr = ipc_kmsg_send((kmsg), MACH_SEND_ALWAYS, \
MACH_MSG_TIMEOUT_NONE); \
assert(mr == MACH_MSG_SUCCESS); \
MACRO_END
#else
#define ipc_kmsg_send_always(kmsg) \
MACRO_BEGIN \
(void) ipc_kmsg_send((kmsg), MACH_SEND_ALWAYS, \
MACH_MSG_TIMEOUT_NONE); \
MACRO_END
#endif
extern ipc_kmsg_t ipc_kmsg_alloc(
mach_msg_size_t size);
extern void ipc_kmsg_free(
ipc_kmsg_t kmsg);
extern void ipc_kmsg_destroy(
ipc_kmsg_t kmsg);
extern void ipc_kmsg_set_prealloc(
ipc_kmsg_t kmsg,
ipc_port_t port);
extern void ipc_kmsg_clear_prealloc(
ipc_kmsg_t kmsg,
ipc_port_t port);
extern mach_msg_return_t ipc_kmsg_get(
mach_msg_header_t *msg,
mach_msg_size_t size,
ipc_kmsg_t *kmsgp);
extern mach_msg_return_t ipc_kmsg_get_from_kernel(
mach_msg_header_t *msg,
mach_msg_size_t size,
ipc_kmsg_t *kmsgp);
extern mach_msg_return_t ipc_kmsg_send(
ipc_kmsg_t kmsg,
mach_msg_option_t option,
mach_msg_timeout_t timeout);
extern mach_msg_return_t ipc_kmsg_put(
mach_msg_header_t *msg,
ipc_kmsg_t kmsg,
mach_msg_size_t size);
extern void ipc_kmsg_put_to_kernel(
mach_msg_header_t *msg,
ipc_kmsg_t kmsg,
mach_msg_size_t size);
extern mach_msg_return_t ipc_kmsg_copyin_header(
mach_msg_header_t *msg,
ipc_space_t space,
mach_port_name_t notify);
extern mach_msg_return_t ipc_kmsg_copyin(
ipc_kmsg_t kmsg,
ipc_space_t space,
vm_map_t map,
mach_port_name_t notify);
extern void ipc_kmsg_copyin_from_kernel(
ipc_kmsg_t kmsg);
extern mach_msg_return_t ipc_kmsg_copyout_header(
mach_msg_header_t *msg,
ipc_space_t space,
mach_port_name_t notify);
extern mach_msg_return_t ipc_kmsg_copyout_object(
ipc_space_t space,
ipc_object_t object,
mach_msg_type_name_t msgt_name,
mach_port_name_t *namep);
extern mach_msg_return_t ipc_kmsg_copyout(
ipc_kmsg_t kmsg,
ipc_space_t space,
vm_map_t map,
mach_port_name_t notify,
mach_msg_body_t *slist);
extern mach_msg_return_t ipc_kmsg_copyout_body(
ipc_kmsg_t kmsg,
ipc_space_t space,
vm_map_t map,
mach_msg_body_t *slist);
extern mach_msg_return_t ipc_kmsg_copyout_pseudo(
ipc_kmsg_t kmsg,
ipc_space_t space,
vm_map_t map,
mach_msg_body_t *slist);
extern void ipc_kmsg_copyout_dest(
ipc_kmsg_t kmsg,
ipc_space_t space);
extern void ipc_kmsg_copyout_to_kernel(
ipc_kmsg_t kmsg,
ipc_space_t space);
extern mach_msg_body_t *ipc_kmsg_copyin_scatter(
mach_msg_header_t *msg,
mach_msg_size_t slist_size,
ipc_kmsg_t kmsg);
extern void ipc_kmsg_free_scatter(
mach_msg_body_t *slist,
mach_msg_size_t slist_size);
#include <mach_kdb.h>
#if MACH_KDB
extern void ipc_kmsg_print(
ipc_kmsg_t kmsg);
extern void ipc_msg_print(
mach_msg_header_t *msgh);
#endif
#endif