diff options
author | Thomas Bushnell <thomas@gnu.org> | 1997-04-14 20:29:05 +0000 |
---|---|---|
committer | Thomas Bushnell <thomas@gnu.org> | 1997-04-14 20:29:05 +0000 |
commit | a646a7a564d263b503692fb007bac6a512571793 (patch) | |
tree | bd598587a1f4267e917fa046a5a75f1ff17f2865 /mig/routine.h | |
parent | 30b32d2ccbf95436b642e6208d6829dcf68981fa (diff) |
Baseline.
Diffstat (limited to 'mig/routine.h')
-rw-r--r-- | mig/routine.h | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/mig/routine.h b/mig/routine.h new file mode 100644 index 0000000..f80a174 --- /dev/null +++ b/mig/routine.h @@ -0,0 +1,401 @@ +/* + * 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 (0) +#define akeNormal (1) /* a normal, user-defined argument */ +#define akeRequestPort (2) /* pointed at by rtRequestPort */ +#define akeWaitTime (3) /* pointed at by rtWaitTime */ +#define akeReplyPort (4) /* pointed at by rtReplyPort */ +#define akeMsgOption (5) /* pointed at by rtMsgOption */ +#define akeMsgSeqno (6) /* pointed at by rtMsgSeqno */ +#define akeRetCode (7) /* pointed at by rtRetCode/rtReturn */ +#define akeReturn (8) /* pointed at by rtReturn */ +#define akeCount (9) /* a count arg for argParent */ +#define akePoly (10) /* a poly arg for argParent */ +#define akeDealloc (11) /* a deallocate arg for argParent */ +#define akeServerCopy (12) /* a server-copy arg for argParent */ +#define akeCountInOut (13) /* a count-in-out arg */ + +#define akeBITS (0x0000003f) +#define akbRequest (0x00000040) /* has a msg_type in request */ +#define akbReply (0x00000080) /* has a msg_type in reply */ +#define akbUserArg (0x00000100) /* an arg on user-side */ +#define akbServerArg (0x00000200) /* an arg on server-side */ +#define akbSend (0x00000400) /* value carried in request */ +#define akbSendBody (0x00000800) /* value carried in request body */ +#define akbSendSnd (0x00001000) /* value stuffed into request */ +#define akbSendRcv (0x00002000) /* value grabbed from request */ +#define akbReturn (0x00004000) /* value carried in reply */ +#define akbReturnBody (0x00008000) /* value carried in reply body */ +#define akbReturnSnd (0x00010000) /* value stuffed into reply */ +#define akbReturnRcv (0x00020000) /* value grabbed from reply */ +#define akbReplyInit (0x00040000) /* reply msg-type must be init'ed */ +#define akbRequestQC (0x00080000) /* msg_type can be checked quickly */ +#define akbReplyQC (0x00100000) /* msg_type can be checked quickly */ +#define akbReplyCopy (0x00200000) /* copy reply value from request */ +#define akbVarNeeded (0x00400000) /* may need local var in server */ +#define akbDestroy (0x00800000) /* call destructor function */ +#define akbVariable (0x01000000) /* variable size inline data */ +#define akbIndefinite (0x02000000) /* variable size, inline or out */ +#define akbPointer (0x04000000) /* 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 (0) +#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) + +#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 */ + boolean_t argLongForm; /* overrides argType->itLongForm */ + boolean_t argServerCopy; + 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 */ + boolean_t argByReferenceUser; + 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 */ + + boolean_t rtOneWay; /* SimpleProcedure or SimpleRoutine */ + boolean_t rtProcedure; /* Procedure or SimpleProcedure */ + boolean_t rtUseError; /* Procedure or Function */ + + boolean_t rtSimpleFixedRequest; /* fixed msg-simple value in request */ + boolean_t rtSimpleSendRequest; /* in any case, initial value */ + boolean_t rtSimpleCheckRequest; /* check msg-simple in request */ + boolean_t rtSimpleReceiveRequest; /* if so, the expected value */ + + boolean_t rtSimpleFixedReply; /* fixed msg-simple value in reply */ + boolean_t rtSimpleSendReply; /* in any case, initial value */ + boolean_t rtSimpleCheckReply; /* check msg-simple in reply */ + 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 */ + + 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 *rtUReplyPort; /* always non-NULL, defaults to Mig-supplied */ + argument_t *rtSReplyPort; /* 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 boolean_t rtCheckMask(const argument_t *args, u_int mask); + +extern boolean_t rtCheckMaskFunction(const argument_t *args, u_int mask, + 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 */ |