1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
|
/*
* 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 <stdbool.h>
#include <sys/types.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 */
bool argLongForm; /* overrides argType->itLongForm */
bool argServerCopy;
bool 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 */
bool argByReferenceUser;
bool 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) */
bool rtOneWay; /* true for SimpleRoutine */
bool rtSimpleFixedRequest; /* fixed msg-simple value in request */
bool rtSimpleSendRequest; /* in any case, initial value */
bool rtSimpleCheckRequest; /* check msg-simple in request */
bool rtSimpleReceiveRequest; /* if so, the expected value */
bool rtSimpleFixedReply; /* fixed msg-simple value in reply */
bool rtSimpleSendReply; /* in any case, initial value */
bool rtSimpleCheckReply; /* check msg-simple in reply */
bool 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 */
bool 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 bool rtCheckMask(const argument_t *args, u_int mask);
extern bool rtCheckMaskFunction(const argument_t *args, u_int mask,
bool (*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 */
|