/* * Mach Operating System * Copyright (c) 1991,1990,1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* * File: ipc/ipc_kmsg.h * Author: Rich Draves * Date: 1989 * * Definitions for kernel messages. */ #ifndef _IPC_IPC_KMSG_H_ #define _IPC_IPC_KMSG_H_ #include #include #include #include #include #include #include #include #include #include /* * This structure is only the header for a kmsg buffer; * the actual buffer is normally larger. The rest of the buffer * holds the body of the message. * * In a kmsg, the port fields hold pointers to ports instead * of port names. These pointers hold references. * * The ikm_header.msgh_remote_port field is the destination * of the message. */ typedef struct ipc_kmsg { struct ipc_kmsg *ikm_next, *ikm_prev; vm_size_t ikm_size; ipc_marequest_t ikm_marequest; 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) ((vm_size_t)((size) + IKM_OVERHEAD)) #define ikm_less_overhead(size) ((mach_msg_size_t)((size) - IKM_OVERHEAD)) #if MACH_IPC_TEST /* * For debugging. */ #define IKM_BOGUS ((ipc_kmsg_t) 0xffffff10) #define ikm_mark_bogus(kmsg) \ MACRO_BEGIN \ (kmsg)->ikm_next = IKM_BOGUS; \ (kmsg)->ikm_prev = IKM_BOGUS; \ MACRO_END #else /* MACH_IPC_TEST */ #define ikm_mark_bogus(kmsg) ; #endif /* MACH_IPC_TEST */ /* * We keep a per-processor cache of kernel message buffers. * The cache saves the overhead/locking of using kalloc/kfree. * The per-processor cache seems to miss less than a per-thread cache, * and it also uses less memory. Access to the cache doesn't * require locking. */ extern ipc_kmsg_t ipc_kmsg_cache[NCPUS]; #define ikm_cache() ipc_kmsg_cache[cpu_number()] /* * The size of the kernel message buffers that will be cached. * IKM_SAVED_KMSG_SIZE includes overhead; IKM_SAVED_MSG_SIZE doesn't. * * We use the page size for IKM_SAVED_KMSG_SIZE to make sure the * page is pinned to a single processor. */ #define IKM_SAVED_KMSG_SIZE PAGE_SIZE #define IKM_SAVED_MSG_SIZE ikm_less_overhead(IKM_SAVED_KMSG_SIZE) #define ikm_alloc(size) \ ((ipc_kmsg_t) kalloc(ikm_plus_overhead(size))) #define ikm_init(kmsg, size) \ MACRO_BEGIN \ ikm_init_special((kmsg), ikm_plus_overhead(size)); \ MACRO_END #define ikm_init_special(kmsg, size) \ MACRO_BEGIN \ (kmsg)->ikm_size = (size); \ (kmsg)->ikm_marequest = IMAR_NULL; \ MACRO_END #define ikm_check_initialized(kmsg, size) \ MACRO_BEGIN \ assert((kmsg)->ikm_size == (size)); \ assert((kmsg)->ikm_marequest == IMAR_NULL); \ MACRO_END /* * Non-positive message sizes are special. They indicate that * the message buffer doesn't come from ikm_alloc and * requires some special handling to free. * * ipc_kmsg_free is the non-macro form of ikm_free. * It frees kmsgs of all varieties. */ #define IKM_SIZE_NORMA 0 #define IKM_SIZE_NETWORK -1 #define ikm_free(kmsg) \ MACRO_BEGIN \ vm_size_t _size = (kmsg)->ikm_size; \ \ if ((integer_t)_size > 0) \ kfree((vm_offset_t) (kmsg), _size); \ else \ ipc_kmsg_free(kmsg); \ MACRO_END /* * struct ipc_kmsg_queue is defined in ipc/ipc_kmsg_queue.h */ #include 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) /* Enqueue a kmsg */ extern void ipc_kmsg_enqueue( ipc_kmsg_queue_t queue, ipc_kmsg_t kmsg); /* Dequeue and return a kmsg */ extern ipc_kmsg_t ipc_kmsg_dequeue( ipc_kmsg_queue_t queue); /* Pull a kmsg out of a queue */ extern void ipc_kmsg_rmqueue( ipc_kmsg_queue_t queue, ipc_kmsg_t kmsg); #define ipc_kmsg_queue_first(queue) ((queue)->ikmq_base) /* Return the kmsg following the given kmsg */ 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 \ 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 { \ ipc_kmsg_t _prev = (kmsg)->ikm_prev; \ \ (queue)->ikmq_base = _next; \ _next->ikm_prev = _prev; \ _prev->ikm_next = _next; \ } \ ikm_mark_bogus (kmsg); \ MACRO_END #define ipc_kmsg_enqueue_macro(queue, kmsg) \ MACRO_BEGIN \ ipc_kmsg_t _first = (queue)->ikmq_base; \ \ if (_first == IKM_NULL) { \ (queue)->ikmq_base = (kmsg); \ (kmsg)->ikm_next = (kmsg); \ (kmsg)->ikm_prev = (kmsg); \ } else { \ 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 extern void ipc_kmsg_destroy(ipc_kmsg_t); extern void ipc_kmsg_clean(ipc_kmsg_t); extern void ipc_kmsg_free(ipc_kmsg_t); extern mach_msg_return_t ipc_kmsg_get(mach_msg_header_t *, mach_msg_size_t, ipc_kmsg_t *); extern mach_msg_return_t ipc_kmsg_get_from_kernel(mach_msg_header_t *, mach_msg_size_t, ipc_kmsg_t *); extern mach_msg_return_t ipc_kmsg_put(mach_msg_header_t *, ipc_kmsg_t, mach_msg_size_t); extern void ipc_kmsg_put_to_kernel(mach_msg_header_t *, ipc_kmsg_t, mach_msg_size_t); extern mach_msg_return_t ipc_kmsg_copyin_header(mach_msg_header_t *, ipc_space_t, mach_port_t); extern mach_msg_return_t ipc_kmsg_copyin(ipc_kmsg_t, ipc_space_t, vm_map_t, mach_port_t); extern void ipc_kmsg_copyin_from_kernel(ipc_kmsg_t); extern mach_msg_return_t ipc_kmsg_copyout_header(mach_msg_header_t *, ipc_space_t, mach_port_t); extern mach_msg_return_t ipc_kmsg_copyout_object(ipc_space_t, ipc_object_t, mach_msg_type_name_t, mach_port_t *); extern mach_msg_return_t ipc_kmsg_copyout_body(vm_offset_t, vm_offset_t, ipc_space_t, vm_map_t); extern mach_msg_return_t ipc_kmsg_copyout(ipc_kmsg_t, ipc_space_t, vm_map_t, mach_port_t); extern mach_msg_return_t ipc_kmsg_copyout_pseudo(ipc_kmsg_t, ipc_space_t, vm_map_t); extern void ipc_kmsg_copyout_dest(ipc_kmsg_t, ipc_space_t); #endif /* _IPC_IPC_KMSG_H_ */