/*
* Copyright (c) 1995, 1996, 1999 The University of Utah and
* the Computer Systems Laboratory at the University of Utah (CSL).
*
* This file is part of Flick, the Flexible IDL Compiler Kit.
*
* Flick is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Flick is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Flick; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place #330, Boston, MA 02111, USA.
*/
/*
* Mach Operating System
* Copyright (c) 1991,1990 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.
*/
#ifndef _ROUTINE_H
#define _ROUTINE_H
#include <sys/types.h>
#include "boolean.h"
#include "type.h"
/* base kind arg */
#define akeNone (0U)
#define akeNormal (1U) /* a normal, user-defined argument */
#define akeRequestPort (2U) /* pointed at by rtRequestPort */
#define akeWaitTime (3U) /* pointed at by rtWaitTime */
#define akeReplyPort (4U) /* pointed at by rtReplyPort */
#define akeMsgOption (5U) /* pointed at by rtMsgOption */
#define akeMsgSeqno (6U) /* pointed at by rtMsgSeqno */
#define akeRetCode (7U) /* pointed at by rtRetCode/rtReturn */
#define akeReturn (8U) /* pointed at by rtReturn */
#define akeCount (9U) /* a count arg for argParent */
#define akePoly (10U) /* a poly arg for argParent */
#define akeDealloc (11U) /* a deallocate arg for argParent */
#define akeServerCopy (12U) /* a server-copy arg for argParent */
#define akeCountInOut (13U) /* a count-in-out arg */
#define akeBITS (0x0000003fU)
#define akbRequest (0x00000040U) /* has a msg_type in request */
#define akbReply (0x00000080U) /* has a msg_type in reply */
#define akbUserArg (0x00000100U) /* an arg on user-side */
#define akbServerArg (0x00000200U) /* an arg on server-side */
#define akbSend (0x00000400U) /* value carried in request */
#define akbSendBody (0x00000800U) /* value carried in request body */
#define akbSendSnd (0x00001000U) /* value stuffed into request */
#define akbSendRcv (0x00002000U) /* value grabbed from request */
#define akbReturn (0x00004000U) /* value carried in reply */
#define akbReturnBody (0x00008000U) /* value carried in reply body */
#define akbReturnSnd (0x00010000U) /* value stuffed into reply */
#define akbReturnRcv (0x00020000U) /* value grabbed from reply */
#define akbReplyInit (0x00040000U) /* reply msg-type must be init'ed */
#define akbRequestQC (0x00080000U) /* msg_type can be checked quickly */
#define akbReplyQC (0x00100000U) /* msg_type can be checked quickly */
#define akbReplyCopy (0x00200000U) /* copy reply value from request */
#define akbVarNeeded (0x00400000U) /* may need local var in server */
#define akbDestroy (0x00800000U) /* call destructor function */
#define akbVariable (0x01000000U) /* variable size inline data */
#define akbIndefinite (0x02000000U) /* variable size, inline or out */
#define akbPointer (0x04000000U) /* server gets a pointer to the
real buffer */
/* be careful, there aren't many bits left */
typedef u_int arg_kind_t;
/*
* akbRequest means msg_type/data fields are allocated in the request
* msg. akbReply means msg_type/data fields are allocated in the
* reply msg. These bits (with akbReplyInit, akbRequestQC, akbReplyQC)
* control msg structure declarations packing, and checking of
* mach_msg_type_t fields.
*
* akbUserArg means this argument is an argument to the user-side stub.
* akbServerArg means this argument is an argument to
* the server procedure called by the server-side stub.
*
* The akbSend* and akbReturn* bits control packing/extracting values
* in the request and reply messages.
*
* akbSend means the argument's value is carried in the request msg.
* akbSendBody implies akbSend; the value is carried in the msg body.
* akbSendSnd implies akbSend; the value is stuffed into the request.
* akbSendRcv implies akbSend; the value is pulled out of the request.
*
* akbReturn, akbReturnBody, akbReturnSnd, akbReturnRcv are defined
* similarly but apply to the reply message.
*
* User-side code generation (header.c, user.c) and associated code
* should use akbSendSnd and akbReturnRcv, but not akbSendRcv and
* akbReturnSnd. Server-side code generation (server.c) is reversed.
* Code generation should use the more specific akb{Send,Return}{Snd,Rcv}
* bits when possible, instead of akb{Send,Return}.
*
* Note that akRetCode and akReturn lack any Return bits, although
* there is a value in the msg. These guys are packed/unpacked
* with special code, unlike other arguments.
*
* akbReplyInit implies akbReply. It means the server-side stub
* should initialize the argument's msg_type field in the reply msg.
* Some special arguments (RetCode, Dummy, Tid) have their msg_type
* fields in the reply message initialized by the server demux
* function; these arguments have akbReply but not akbReplyInit.
*
* akbRequestQC implies akbRequest. If it's on, then the
* mach_msg_type_t value in the request message can be checked quickly
* (by casting to an int and checking with a single comparison).
* akbReplyQC has the analogous meaning with respect to akbReply.
*
* akbVariable means the argument has variable-sized inline data.
* It isn't currently used for code generation, but routine.c
* does use it internally. It is added in rtAugmentArgKind.
*
* akbReplyCopy and akbVarNeeded help control code generation in the
* server-side stub. The preferred method of handling data in the
* server-side stub avoids copying into/out-of local variables. In
* arguments get passed directly to the server proc from the request msg.
* Out arguments get stuffed directly into the reply msg by the server proc.
* For InOut arguments, the server proc gets the address of the data in
* the request msg, and the resulting data gets copied to the reply msg.
* Some arguments need a local variable in the server-side stub. The
* code extracts the data from the request msg into the variable, and
* stuff the reply msg from the variable.
*
* akbReplyCopy implies akbReply. It means the data should get copied
* from the request msg to the reply msg after the server proc is called.
* It is only used by akInOut. akTid doesn't need it because the tid
* data in the reply msg is initialized in the server demux function.
*
* akbVarNeeded means the argument needs a local variable in the
* server-side stub. It is added in rtAugmentArgKind and
* rtCheckVariable. An argument shouldn't have all three of
* akbReturnSnd, akbVarNeeded and akbReplyCopy, because this indicates
* the reply msg should be stuffed both ways.
*
* akbDestroy helps control code generation in the server-side stub.
* It means this argument has a destructor function which should be called.
*
* Header file generation (header.c) uses:
* akbUserArg
*
* User stub generation (user.c) uses:
* akbUserArg, akbRequest, akbReply, akbSendSnd,
* akbSendBody, akbReturnRcv, akbReplyQC
*
* Server stub generation (server.c) uses:
* akbServerArg, akbRequest, akbReply, akbSendRcv, akbReturnSnd,
* akbReplyInit, akbReplyCopy, akbVarNeeded, akbSendBody, akbRequestQC
*
*
* During code generation, the routine, argument, and type data structures
* are read-only. The code generation functions' output is their only
* side-effect.
*
*
* Style note:
* Code can use logical operators (|, &, ~) on akb values.
* ak values should be manipulated with the ak functions.
*/
/* various useful combinations */
#define akbNone (0U)
#define akbAll (~akbNone)
#define akbAllBits (~akeBITS)
#define akbSendBits (akbSend|akbSendBody|akbSendSnd|akbSendRcv)
#define akbReturnBits (akbReturn|akbReturnBody|akbReturnSnd|akbReturnRcv)
#define akbSendReturnBits (akbSendBits|akbReturnBits)
#define akNone akeNone
#define akIn akAddFeature(akeNormal, \
akbUserArg|akbServerArg|akbRequest|akbSendBits)
#define akOut akAddFeature(akeNormal, \
akbUserArg|akbServerArg|akbReply|akbReturnBits|akbReplyInit)
#define akInOut akAddFeature(akeNormal, \
akbUserArg|akbServerArg|akbRequest|akbReply| \
akbSendBits|akbReturnBits|akbReplyInit|akbReplyCopy)
/* These are to accomodate poly args as well as others */
#define akInTest akbSend | akbSendBody
#define akOutTest akbReturn | akbReturnBody
#define akInOutTest akAddFeature(akIn, akOut)
#define akRequestPort akAddFeature(akeRequestPort, \
akbUserArg|akbServerArg|akbSend|akbSendSnd|akbSendRcv)
#define akWaitTime akAddFeature(akeWaitTime, akbUserArg)
#define akMsgOption akAddFeature(akeMsgOption, akbUserArg)
#define akMsgSeqno akAddFeature(akeMsgSeqno, \
akbServerArg|akbSend|akbSendRcv)
#define akReplyPort akAddFeature(akeReplyPort, \
akbUserArg|akbServerArg|akbSend|akbSendSnd|akbSendRcv)
#define akUReplyPort akAddFeature(akeReplyPort, \
akbUserArg|akbSend|akbSendSnd|akbSendRcv)
#define akSReplyPort akAddFeature(akeReplyPort, \
akbServerArg|akbSend|akbSendSnd|akbSendRcv)
#define akRetCode akAddFeature(akeRetCode, akbReply)
#define akReturn akAddFeature(akeReturn, \
akbReply|akbReplyInit)
#define akCount akAddFeature(akeCount, \
akbUserArg|akbServerArg)
#define akPoly akePoly
#define akDealloc akAddFeature(akeDealloc, akbUserArg)
#define akServerCopy akAddFeature(akeServerCopy, akbServerArg|akbSendRcv)
#define akCountInOut akAddFeature(akeCountInOut, akbRequest|akbSendBits)
#define akCheck(ak, bits) ((ak) & (bits))
#define akCheckAll(ak, bits) (akCheck(ak, bits) == (bits))
#define akAddFeature(ak, bits) ((ak)|(bits))
#define akRemFeature(ak, bits) ((ak)&~(bits))
#define akIdent(ak) ((ak) & akeBITS)
/*
* The arguments to a routine/function are linked in left-to-right order.
* argName is used for error messages and pretty-printing,
* not code generation. Code generation shouldn't make any assumptions
* about the order of arguments, esp. count and poly arguments.
* (Unfortunately, code generation for inline variable-sized arguments
* does make such assumptions.)
*
* argVarName is the name used in generated code for function arguments
* and local variable names. argMsgField is the name used in generated
* code for the field in msgs where the argument's value lives.
* argTTName is the name used in generated code for msg-type fields and
* static variables used to initialize those fields. argPadName is the
* name used in generated code for a padding field in msgs.
*
* argFlags can be used to override the deallocate and longform bits
* in the argument's type. rtProcessArgFlags sets argDeallocate and
* argLongForm from it and the type. Code generation shouldn't use
* argFlags.
*
* argCount, argPoly, and argDealloc get to the implicit count, poly,
* and dealloc arguments associated with the argument; they should be
* used instead of argNext. In these implicit arguments, argParent is
* a pointer to the "real" arg.
*
* In count arguments, argMultiplier is a scaling factor applied to
* the count arg's value to get msg-type-number. It is equal to
* argParent->argType->itElement->itNumber
*/
typedef struct argument
{
/* if argKind == akReturn, then argName is name of the function */
identifier_t argName;
struct argument *argNext;
arg_kind_t argKind;
ipc_type_t *argType;
const_string_t argVarName; /* local variable and argument names */
const_string_t argMsgField; /* message field's name */
const_string_t argTTName; /* name for msg_type fields, static vars */
const_string_t argPadName; /* name for pad field in msg */
ipc_flags_t argFlags;
dealloc_t argDeallocate; /* overrides argType->itDeallocate */
mig_boolean_t argLongForm; /* overrides argType->itLongForm */
mig_boolean_t argServerCopy;
mig_boolean_t argCountInOut;
struct routine *argRoutine; /* routine we are part of */
struct argument *argCount; /* our count arg, if present */
struct argument *argCInOut; /* our CountInOut arg, if present */
struct argument *argPoly; /* our poly arg, if present */
struct argument *argDealloc;/* our dealloc arg, if present */
struct argument *argSCopy; /* our serverCopy arg, if present */
struct argument *argParent; /* in a count or poly arg, the base arg */
int argMultiplier; /* for Count argument: parent is a multiple
of a basic IPC type. Argument must be
multiplied by Multiplier to get IPC
number-of-elements. */
/* how variable/inline args precede this one, in request and reply */
int argRequestPos;
int argReplyPos;
/* whether argument is by reference, on user and server side */
mig_boolean_t argByReferenceUser;
mig_boolean_t argByReferenceServer;
} argument_t;
/*
* The various routine kinds' peculiarities are abstracted by rtCheckRoutine
* into attributes like rtOneWay, rtProcedure, etc. These are what
* code generation should use. It is Bad Form for code generation to
* test rtKind.
*/
typedef enum
{
rkRoutine,
rkSimpleRoutine,
rkSimpleProcedure,
rkProcedure,
rkFunction
} routine_kind_t;
typedef struct routine
{
identifier_t rtName;
routine_kind_t rtKind;
argument_t *rtArgs;
u_int rtNumber; /* used for making msg ids */
identifier_t rtUserName; /* user-visible name (UserPrefix + Name) */
identifier_t rtServerName; /* server-side name (ServerPrefix + Name) */
/* rtErrorName is only used for Procs, SimpleProcs, & Functions */
identifier_t rtErrorName; /* error-handler name */
mig_boolean_t rtOneWay; /* SimpleProcedure or SimpleRoutine */
mig_boolean_t rtProcedure; /* Procedure or SimpleProcedure */
mig_boolean_t rtUseError; /* Procedure or Function */
mig_boolean_t rtSimpleFixedRequest; /* fixed msg-simple value in request */
mig_boolean_t rtSimpleSendRequest; /* in any case, initial value */
mig_boolean_t rtSimpleCheckRequest; /* check msg-simple in request */
mig_boolean_t rtSimpleReceiveRequest; /* if so, the expected value */
mig_boolean_t rtSimpleFixedReply; /* fixed msg-simple value in reply */
mig_boolean_t rtSimpleSendReply; /* in any case, initial value */
mig_boolean_t rtSimpleCheckReply; /* check msg-simple in reply */
mig_boolean_t rtSimpleReceiveReply; /* if so, the expected value */
u_int rtRequestSize; /* minimal size of a legal request msg */
u_int rtReplySize; /* minimal size of a legal reply msg */
int rtNumRequestVar; /* number of variable/inline args in request */
int rtNumReplyVar; /* number of variable/inline args in reply */
int rtMaxRequestPos; /* maximum of argRequestPos */
int rtMaxReplyPos; /* maximum of argReplyPos */
mig_boolean_t rtNoReplyArgs;/* if so, no reply message arguments beyond
what the server dispatch routine inserts */
/* distinguished arguments */
argument_t *rtRequestPort; /* always non-NULL, defaults to first arg */
argument_t *rtReplyPort; /* always non-NULL, defaults to Mig-supplied */
argument_t *rtReturn; /* non-NULL unless rtProcedure */
argument_t *rtServerReturn; /* NULL or rtReturn */
argument_t *rtRetCode; /* always non-NULL */
argument_t *rtWaitTime; /* if non-NULL, will use MACH_RCV_TIMEOUT */
argument_t *rtMsgOption; /* always non-NULL, defaults to NONE */
argument_t *rtMsgSeqno; /* if non-NULL, server gets passed seqno */
} routine_t;
#define rtNULL ((routine_t *) 0)
#define argNULL ((argument_t *) 0)
extern u_int rtNumber;
/* rt->rtNumber will be initialized */
extern routine_t *rtAlloc(void);
/* skip a number */
extern void rtSkip(int);
extern argument_t *argAlloc(void);
extern mig_boolean_t rtCheckMask(const argument_t *args, u_int mask);
extern mig_boolean_t rtCheckMaskFunction(const argument_t *args, u_int mask,
mig_boolean_t (*func)(const argument_t *arg));
extern routine_t *rtMakeRoutine(identifier_t name, argument_t *args);
extern routine_t *rtMakeSimpleRoutine(identifier_t name, argument_t *args);
extern routine_t *rtMakeProcedure(identifier_t name, argument_t *args);
extern routine_t *rtMakeSimpleProcedure(identifier_t name, argument_t *args);
extern routine_t *rtMakeFunction(identifier_t name, argument_t *args,
ipc_type_t *type);
extern void rtPrintRoutine(const routine_t *rt);
extern void rtCheckRoutine(routine_t *rt);
extern const char *rtRoutineKindToStr(routine_kind_t rk);
#endif /* _ROUTINE_H */
syntax highlighted by Code2HTML, v. 0.9.1