/*
* Define queues and messages
*
* $Log: sessipc.h,v $
* Revision 2.0.1.1 2000/02/25 01:13:50 greyham
* patch42: Add author's regression tests to distribution
*
* Revision 1.6 1993/07/09 16:49:21 leisner
* added inline functions to get/put subvalue
*
* Revision 1.5 1993/06/04 18:10:41 leisner
* *** empty log message ***
*
* Revision 1.4 1993/05/27 15:16:43 leisner
* some changes
*
* Revision 1.3 1993/05/20 15:37:45 leisner
* release
*
* Revision 1.2 1993/05/19 13:36:21 leisner
* Binding queues to sendhandle, making answerback stack part of queue
*
* Revision 1.1 1993/05/17 15:31:22 leisner
* Initial revision
*
*/
#ifndef __SESSIPC_H__
#define __SESSIPC_H__
#define IPC_SOCKET_BASED
#include <sys/types.h>
#include <sys/time.h>
#ifdef RCSID
static char *ipc_rcsid = "$Id: sessipc.h,v 2.0.1.1 2000/02/25 01:13:50 greyham Exp greyham $";
#endif
#ifndef NULL
#define NULL (void *) 0
#endif
/* for the time being, put it here */
#undef TRUE
#undef FALSE
typedef enum { TRUE=1, FALSE=0 } BOOLEAN;
typedef unsigned int MESSAGE_TYPE;
typedef unsigned int QUEUE_ID;
typedef unsigned char FUNC_CODE;
typedef unsigned short MESSAGE_NUMBER;
typedef short MESSAGE_SIZE;
/* Message types are defines as follows:
* types are a 32 bit doubleword, LSB is 0
* bit 31 - FD being passed
* bit 30 - fipc message
* bit 29 - fipc final answer
* bit 28 - fipc interim answer
* for any bits 28-31 set:
* bit 0-15 -- message number
* bit 16-23 -- function ID
* Otherwise, its up to a user
*/
#define IPC_FD (1 << 31)
#define FIPC_MESS (1 << 30)
#define FIPC_FINAL_ANSWER (1 << 29)
#define FIPC_INTERIM_ANSWER (1 << 28)
#define IPC_FUNC_CODE_OFFSET 16
#define IPC_MAX_MESSAGE 512
#define QLIST void
/* Doug McIlroy likes this?? */
enum { LAST_PREDEFINED_QUEUE = 10000 };
typedef struct {
/* when an fd is passed */
int fd;
#define MAGIC_MESSAGE 0xae374256
#ifdef MAGIC_MESSAGE
int magic_message;
#endif
/* can be anything the sender sets, but could be the senders
* QUEUE_ID
*/
QUEUE_ID source_queue_name;
MESSAGE_TYPE type;
/* I don't understand this */
int subtype;
/* how large the message is */
MESSAGE_SIZE size;
} EACH_MESSAGE;
#define NULL_QUEUEID 0
/* this is used to align the message (double? ) */
typedef long ALIGN_TYPE;
typedef struct {
EACH_MESSAGE each_message;
union {
char message_data[IPC_MAX_MESSAGE];
ALIGN_TYPE aligner;
} m_data;
} MESSAGE;
typedef struct queued_message {
/* links to prev and next message, NULL indicates end of list.
* It is sorted in chronological order of message arrival
*/
struct queued_message *prev;
struct queued_message *next;
MESSAGE *message;
} QUEUED_MESSAGE;
/* one of the following is used for each FIPC with an answer sent */
typedef struct answer_block {
/* fipc being used */
FUNC_CODE current_fipc;
/* message number for a particular fipc */
MESSAGE_NUMBER message_number;
/* where the answers go -- nominally a structure */
void *answer_back;
/* answer_block->next = NULL is end of list
* answer_block->next = NULL Is start of list
*/
struct answer_block *next;
struct answer_block *prev;
} ANSWER_BLOCK;
/* Functional IPC needs to have this */
/* one of the following is used for each FIPC registered */
typedef struct fipc {
/* number of fipc (same for all processes) */
FUNC_CODE fipc_number;
/* function used to transmit message if non-null --
* this is only useful on the side which receives
* the message and processes it
*/
void (*server_func)(MESSAGE *);
/* function used for an answer if non-null --
* this is only useful on the side which sends the message and
* waits for an answer
*/
int (*answer_func)(MESSAGE *, ANSWER_BLOCK *);
/* next fipc, NULL terminates list */
struct fipc *next_fipc;
} FIPC;
/* use this for mutexes */
typedef volatile short IPC_MUTEX_VARIABLE;
/* each queue contains initialization information, and pointers to the
* head and tail of the queue
*/
typedef struct {
#define MAGIC_QUEUE 0xabcdef
/* an allocated queue gets a magic when debugging */
#ifdef MAGIC_QUEUE
int magic_queue;
#endif
/* identity assigned to this queue */
QUEUE_ID queue_number;
/* function to indicate message arrival */
void (*message_arrival)(MESSAGE *pmess);
#ifdef IPC_SOCKET_BASED
/* unix domain fd */
int unix_domain_fd;
/* TRUE if this socket blocks for input */
BOOLEAN blocking;
#endif
/* list of queue messages, head is front, tail is rear, NULL means empty */
QUEUED_MESSAGE *head;
QUEUED_MESSAGE *tail;
MESSAGE *message_heap; /* points to array of sizeof(MESSAGE) * number
* of message preallocated */
MESSAGE *message_stack; /* a stack of messages */
/* a stack of available QUEUE_MESSAGE nodes, NULL indicates no
* more nodes are available.
*/
QUEUED_MESSAGE *queue_stack;
/* amount of time to block for when reading queue */
struct timeval blocking_time;
/* block for specified time or if NULL block forever.
* If not NULL, points to blocking_time
*/
struct timeval *pblock;
/* pending answer blocks on this queue */
ANSWER_BLOCK *answer_list;
/* stack of available answers for this queue */
ANSWER_BLOCK *answer_stack;
/* counter for send handles bound to this queue.
* If > 0, can't close queue
* Increment in create_handle, decremented in destroy_handle
* if queue is bound
*/
int num_send_handles;
} IPC_QUEUE;
#ifdef MAGIC_QUEUE
#define TEST_QUEUE(x) assert(x->magic_queue == MAGIC_QUEUE)
#else
#define TEST_QUEUE(x)
#endif
typedef struct {
#ifdef IPC_SOCKET_BASED
/* socket fd to use */
int fd;
#endif
/* if it blocks, this is TRUE */
BOOLEAN blocking;
/* where to answer messages (may be NULL_QUEUEID) */
QUEUE_ID sender_queue;
/* this is only for FIPC answers on the requeuster.
* NULL if no binding */
IPC_QUEUE *pqueue;
MESSAGE_NUMBER mess_number;
/* this can be used to test the integrity */
#define MAGIC_SEND 0x886644ff
#ifdef MAGIC_SEND
int magic_send;
#endif
} SEND_HANDLE;
#define Q_LIST void
#if !defined(MAKE_PROTOS) && !defined(__C2MAN__)
#include "ipcprotos.h"
#endif
#ifdef MAGIC_SEND
#define TEST_SEND_HANDLE(x) (assert(x->magic_send == MAGIC_SEND))
#else
#define TEST_SEND_HANDLE(x)
#endif
/* a static inline function is as fast as a macro
* This technology is preferable to macros, since the compiler will type check,
* and should be as efficient as inline code.
* This allows the actual structures to be opaque to the user
*/
#ifdef __GNUC__
/* this continues to work with -ansi */
#define INLINE __inline__
#else
#define INLINE
#endif
/* Messages involving FIPC or file desriptor passing have
* message numbers
*/
static INLINE MESSAGE_NUMBER get_message_number(MESSAGE *message)
{
return message->each_message.type & 0xffff;
}
static INLINE void set_message_number(MESSAGE *message, MESSAGE_NUMBER number)
{
message->each_message.type |= (message->each_message.type & 0xffff0000) | number;
}
/* get a function code, given a message */
static INLINE FUNC_CODE get_function_code(MESSAGE *pmess)
{
return (pmess->each_message.type >> 16) & 0xff;
}
/* set the function code */
static INLINE void set_function_code(MESSAGE *pmess, FUNC_CODE code)
{
pmess->each_message.type &= 0xff00ffff;
pmess->each_message.type |= (code << 16);
}
static INLINE MESSAGE_TYPE get_message_type(MESSAGE *pmess)
{
return pmess->each_message.type;
}
static INLINE void set_message_type(MESSAGE *pmess, MESSAGE_TYPE type)
{
pmess->each_message.type = type;
}
/* get a pointer to the data of the current message */
static INLINE void *message_data(MESSAGE *pmess)
{
return &(pmess->m_data.message_data);
}
/* get the size of the current message */
static INLINE MESSAGE_SIZE get_message_size(MESSAGE *pmess)
{
return pmess->each_message.size;
}
/* set the size of the current message */
static INLINE void set_message_size(MESSAGE *pmess, MESSAGE_SIZE size)
{
pmess->each_message.size = size;
}
/* get the source of the current message.
*
* Warning: this is only useful when reading messages
*/
static INLINE QUEUE_ID get_message_source(MESSAGE *pmess)
{
return pmess->each_message.source_queue_name;
}
/* set the source of the current message.
*
* Warning: this is only useful when writing messages
*/
static INLINE void set_message_source(MESSAGE *pmess, QUEUE_ID source)
{
pmess->each_message.source_queue_name = source;
}
/* Determine whether a message is functinal IPC
* Returns: TRUE if it is, FALSE if not
*/
static INLINE BOOLEAN is_message_fipc(MESSAGE *pmess)
{
return (pmess->each_message.type & FIPC_MESS) ?
TRUE : FALSE;
}
/* return TRUE if either a final or an interim answer */
static INLINE BOOLEAN is_message_answer(MESSAGE *pmess)
{
return (pmess->each_message.type & (FIPC_FINAL_ANSWER |
FIPC_INTERIM_ANSWER)) ?
TRUE : FALSE;
}
/* is this message involving a file descriptor pass.
* Return TRUE if it is, FALSE if not.
*/
static INLINE BOOLEAN is_message_fd_pass(MESSAGE *pmess)
{
return (pmess->each_message.type & IPC_FD) ? TRUE : FALSE;
}
/* get the file descriptor associated with the message.
*
* WARNING: is_message_fd_pass() must return TRUE before
* this can be useful.
*/
static INLINE int get_message_fd(MESSAGE *pmess)
{
return pmess->each_message.fd;
}
/* Get the next message on the queue.
* Return the message or NULL if it doesn't exist
*/
static INLINE MESSAGE *get_next_message(IPC_QUEUE *pqueue)
{
return ipc_get_message(pqueue, NULL);
}
/* on a previously created send handle,
* set the return address.
* This is nominally the receive queue of the process, but may be
* anything else, include the NULL_QUEUEID
*/
static INLINE void set_send_answer(SEND_HANDLE *phandle, QUEUE_ID id)
{
phandle->sender_queue = id;
}
/* test to see if there is anything present in the queue.
* Return TRUE if there are pending messages, FALSE if there
* are not.
*/
static INLINE BOOLEAN ipc_queue_status(IPC_QUEUE *pqueue)
{
if(pqueue->head)
return TRUE;
else return ipc_test_implementation(pqueue);
}
#ifndef __C2MAN__
/* used internally by the library -- don't generate a man page */
static INLINE MESSAGE_NUMBER get_next_mess_number(SEND_HANDLE *psend)
{
if(!++(psend->mess_number) )
psend->mess_number = 1;
return psend->mess_number;
}
#endif
/* used to get message subtype */
static INLINE int ipc_get_message_subtype(MESSAGE *mess)
{
return mess->each_message.subtype;
}
/* set an ipc message subtype field */
static INLINE void ipc_set_message_subtype(MESSAGE *mess, int i)
{
mess->each_message.subtype = i;
}
/* get the id currently being used in a queue.
* This is normally useful when the systems assigns a QUEUE_ID
*/
static INLINE QUEUE_ID get_queue_id(IPC_QUEUE *pqueue)
{
return pqueue->queue_number;
}
#ifndef EMBEDDED
static void nonembedded_perror(const char *string)
{
perror(string);
}
#else
static void nonembedded_perror(const char *string)
{
}
#endif
#endif
#define COMPILED_AT "$I" "d: " __FILE__ " compiled at " __DATE__ " " __TIME__ " $"
syntax highlighted by Code2HTML, v. 0.9.1