/* * 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 #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 { 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, etc. These are what code generation should * use. It is bad Form for code generation to test rtKind. */ typedef enum { rkRoutine, rkSimpleRoutine, } 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) */ boolean_t rtOneWay; /* TRUE for SimpleRoutine */ 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 */ 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 void rtPrintRoutine(const routine_t *rt); extern void rtCheckRoutine(routine_t *rt); extern const char *rtRoutineKindToStr(routine_kind_t rk); #endif /* _ROUTINE_H */