diff options
Diffstat (limited to 'mig/routine.c')
-rw-r--r-- | mig/routine.c | 1334 |
1 files changed, 0 insertions, 1334 deletions
diff --git a/mig/routine.c b/mig/routine.c deleted file mode 100644 index 70707bd..0000000 --- a/mig/routine.c +++ /dev/null @@ -1,1334 +0,0 @@ -/* - * Mach Operating System - * Copyright (c) 1992,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. - */ - -/* - * ABSTRACT: - * Provides the routine used by parser.c to generate - * routine structures for each routine statement. - * The parser generates a threaded list of statements - * of which the most interesting are the various kinds - * routine statments. The routine structure is defined - * in routine.h which includes it name, kind of routine - * and other information, - * a pointer to an argument list which contains the name - * and type information for each argument, and a list - * of distinguished arguments, eg. Request and Reply - * ports, waittime, retcode etc. - */ - -#include <stdio.h> -#include <stdlib.h> - -#include "error.h" -#include "global.h" -#include "routine.h" -#include "message.h" - -u_int rtNumber = 0; - -routine_t * -rtAlloc(void) -{ - register routine_t *new; - - new = (routine_t *) calloc(1, sizeof *new); - if (new == rtNULL) - fatal("rtAlloc(): %s", unix_error_string(errno)); - new->rtNumber = rtNumber++; - new->rtName = strNULL; - new->rtErrorName = strNULL; - new->rtUserName = strNULL; - new->rtServerName = strNULL; - - return new; -} - -void -rtSkip(int n) -{ - rtNumber += n; -} - -argument_t * -argAlloc(void) -{ - static const argument_t prototype = - { - strNULL, /* identifier_t argName */ - argNULL, /* argument_t *argNext */ - akNone, /* arg_kind_t argKind */ - itNULL, /* ipc_type_t *argType */ - strNULL, /* string_t argVarName */ - strNULL, /* string_t argMsgField */ - strNULL, /* string_t argTTName */ - strNULL, /* string_t argPadName */ - flNone, /* ipc_flags_t argFlags */ - d_NO, /* dealloc_t argDeallocate */ - FALSE, /* boolean_t argLongForm */ - FALSE, /* boolean_t argServerCopy */ - FALSE, /* boolean_t argCountInOut */ - rtNULL, /* routine_t *argRoutine */ - argNULL, /* argument_t *argCount */ - argNULL, /* argument_t *argCInOut */ - argNULL, /* argument_t *argPoly */ - argNULL, /* argument_t *argDealloc */ - argNULL, /* argument_t *argSCopy */ - argNULL, /* argument_t *argParent */ - 1, /* int argMultiplier */ - 0, /* int argRequestPos */ - 0, /* int argReplyPos */ - FALSE, /* boolean_t argByReferenceUser */ - FALSE /* boolean_t argByReferenceServer */ - }; - register argument_t *new; - - new = malloc(sizeof *new); - if (new == argNULL) - fatal("argAlloc(): %s", unix_error_string(errno)); - *new = prototype; - return new; -} - -routine_t * -rtMakeRoutine(identifier_t name, argument_t *args) -{ - register routine_t *rt = rtAlloc(); - - rt->rtName = name; - rt->rtKind = rkRoutine; - rt->rtArgs = args; - - return rt; -} - -routine_t * -rtMakeSimpleRoutine(identifier_t name, argument_t *args) -{ - register routine_t *rt = rtAlloc(); - - rt->rtName = name; - rt->rtKind = rkSimpleRoutine; - rt->rtArgs = args; - - return rt; -} - -routine_t * -rtMakeProcedure(identifier_t name, argument_t *args) -{ - register routine_t *rt = rtAlloc(); - - rt->rtName = name; - rt->rtKind = rkProcedure; - rt->rtArgs = args; - - warn("Procedure %s: obsolete routine kind", name); - - return rt; -} - -routine_t * -rtMakeSimpleProcedure(identifier_t name, argument_t *args) -{ - register routine_t *rt = rtAlloc(); - - rt->rtName = name; - rt->rtKind = rkSimpleProcedure; - rt->rtArgs = args; - - warn("SimpleProcedure %s: obsolete routine kind", name); - - return rt; -} - -routine_t * -rtMakeFunction(identifier_t name, argument_t *args, ipc_type_t *type) -{ - register routine_t *rt = rtAlloc(); - register argument_t *ret = argAlloc(); - - ret->argName = name; - ret->argKind = akReturn; - ret->argType = type; - ret->argNext = args; - - rt->rtName = name; - rt->rtKind = rkFunction; - rt->rtArgs = ret; - - warn("Function %s: obsolete routine kind", name); - - return rt; -} - -const char * -rtRoutineKindToStr(routine_kind_t rk) -{ - switch (rk) - { - case rkRoutine: - return "Routine"; - case rkSimpleRoutine: - return "SimpleRoutine"; - case rkProcedure: - return "Procedure"; - case rkSimpleProcedure: - return "SimpleProcedure"; - case rkFunction: - return "Function"; - default: - fatal("rtRoutineKindToStr(%d): not a routine_kind_t", rk); - /*NOTREACHED*/ - } -} - -static void -rtPrintArg(register const argument_t *arg) -{ - register const ipc_type_t *it = arg->argType; - - if (!akCheck(arg->argKind, akbUserArg|akbServerArg) || - (akIdent(arg->argKind) == akeCount) || - (akIdent(arg->argKind) == akePoly)) - return; - - printf("\n\t"); - - switch (akIdent(arg->argKind)) - { - case akeRequestPort: - printf("RequestPort"); - break; - case akeReplyPort: - printf("ReplyPort"); - break; - case akeWaitTime: - printf("WaitTime"); - break; - case akeMsgOption: - printf("MsgOption"); - break; - case akeMsgSeqno: - printf("MsgSeqno\t"); - break; - default: - if (akCheck(arg->argKind, akbRequest)) - if (akCheck(arg->argKind, akbSend)) - printf("In"); - else - printf("(In)"); - if (akCheck(arg->argKind, akbReply)) - if (akCheck(arg->argKind, akbReturn)) - printf("Out"); - else - printf("(Out)"); - printf("\t"); - } - - printf("\t%s: %s", arg->argName, it->itName); - - if (arg->argDeallocate != it->itDeallocate) - if (arg->argDeallocate == d_YES) - printf(", Dealloc"); - else if (arg->argDeallocate == d_MAYBE) - printf(", Dealloc[]"); - else - printf(", NotDealloc"); - - if (arg->argLongForm != it->itLongForm) - if (arg->argLongForm) - printf(", IsLong"); - else - printf(", IsNotLong"); - - if (arg->argServerCopy) - printf(", ServerCopy"); - - if (arg->argCountInOut) - printf(", CountInOut"); -} - -void -rtPrintRoutine(register const routine_t *rt) -{ - register const argument_t *arg; - - printf("%s (%d) %s(", rtRoutineKindToStr(rt->rtKind), - rt->rtNumber, rt->rtName); - - for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) - rtPrintArg(arg); - - if (rt->rtKind == rkFunction) - printf("): %s\n", rt->rtReturn->argType->itName); - else - printf(")\n"); - - printf("\n"); -} - -/* - * Determines appropriate value of msg-simple for the message, - * and whether this value can vary at runtime. (If it can vary, - * then the simple value is optimistically returned as TRUE.) - * Uses itInName values, so useful when sending messages. - */ - -static void -rtCheckSimpleIn(const argument_t *args, u_int mask, boolean_t *fixed, - boolean_t *simple) -{ - register const argument_t *arg; - boolean_t MayBeComplex = FALSE; - boolean_t MustBeComplex = FALSE; - - for (arg = args; arg != argNULL; arg = arg->argNext) - if (akCheck(arg->argKind, mask)) - { - register const ipc_type_t *it = arg->argType; - - if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC) - MayBeComplex = TRUE; - - if (it->itIndefinite) - MayBeComplex = TRUE; - - if (MACH_MSG_TYPE_PORT_ANY(it->itInName) || - !it->itInLine) - MustBeComplex = TRUE; - } - - *fixed = MustBeComplex || !MayBeComplex; - *simple = !MustBeComplex; -} - -/* - * Determines appropriate value of msg-simple for the message, - * and whether this value can vary at runtime. (If it can vary, - * then the simple value is optimistically returned as TRUE.) - * Uses itOutName values, so useful when receiving messages - * (and sending reply messages in KernelServer interfaces). - */ - -static void -rtCheckSimpleOut(const argument_t *args, u_int mask, boolean_t *fixed, - boolean_t *simple) -{ - register const argument_t *arg; - boolean_t MayBeComplex = FALSE; - boolean_t MustBeComplex = FALSE; - - for (arg = args; arg != argNULL; arg = arg->argNext) - if (akCheck(arg->argKind, mask)) - { - register const ipc_type_t *it = arg->argType; - - if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC) - MayBeComplex = TRUE; - - if (it->itIndefinite) - MayBeComplex = TRUE; - - if (MACH_MSG_TYPE_PORT_ANY(it->itOutName) || - !it->itInLine) - MustBeComplex = TRUE; - } - - *fixed = MustBeComplex || !MayBeComplex; - *simple = !MustBeComplex; -} - -static u_int -rtFindSize(const argument_t *args, u_int mask) -{ - register const argument_t *arg; - u_int size = sizeof_mach_msg_header_t; - - for (arg = args; arg != argNULL; arg = arg->argNext) - if (akCheck(arg->argKind, mask)) - { - register ipc_type_t *it = arg->argType; - - if (arg->argLongForm) { - /* might need proper alignment on 64bit archies */ - size = (size + word_size-1) & ~(word_size-1); - size += sizeof_mach_msg_type_long_t; - } else { - register bs = (it->itSize / 8); /* in bytes */ - size += (bs > sizeof_mach_msg_type_t) ? bs : sizeof_mach_msg_type_t; - } - - size += it->itMinTypeSize; - } - - return size; -} - -boolean_t -rtCheckMask(const argument_t *args, u_int mask) -{ - register const argument_t *arg; - - for (arg = args; arg != argNULL; arg = arg->argNext) - if (akCheckAll(arg->argKind, mask)) - return TRUE; - return FALSE; -} - -boolean_t -rtCheckMaskFunction(const argument_t *args, u_int mask, - boolean_t (*func)(const argument_t *)) -{ - register const argument_t *arg; - - for (arg = args; arg != argNULL; arg = arg->argNext) - if (akCheckAll(arg->argKind, mask)) - if ((*func)(arg)) - return TRUE; - return FALSE; -} - -/* arg->argType may be NULL in this function */ - -static void -rtDefaultArgKind(const routine_t *rt, argument_t *arg) -{ - if ((arg->argKind == akNone) && - (rt->rtRequestPort == argNULL)) - arg->argKind = akRequestPort; - - if (arg->argKind == akNone) - arg->argKind = akIn; -} - -/* - * Initializes arg->argDeallocate, arg->argLongForm, - * arg->argServerCopy, arg->argCountInOut from arg->argFlags. - */ - -static void -rtProcessArgFlags(register argument_t *arg) -{ - register const ipc_type_t *it = arg->argType; - - arg->argFlags = itCheckFlags(arg->argFlags, arg->argName); - - if (((IsKernelServer && akCheck(arg->argKind, akbReturn)) || - (IsKernelUser && akCheck(arg->argKind, akbSend))) && - (arg->argFlags & flDealloc) && - (it->itDeallocate == d_NO)) { - /* - * For a KernelServer interface and an Out argument, - * or a KernelUser interface and an In argument, - * we avoid a possible spurious warning about the deallocate bit. - * For compatibility with Mach 2.5, the deallocate bit - * may need to be enabled on some inline arguments. - */ - - arg->argDeallocate = d_YES; - } else - arg->argDeallocate = itCheckDeallocate(it, arg->argFlags, - it->itDeallocate, arg->argName); - - arg->argLongForm = itCheckIsLong(it, arg->argFlags, - it->itLongForm, arg->argName); - - if (arg->argFlags & flServerCopy) { - if (it->itIndefinite && akCheck(arg->argKind, akbSend)) - arg->argServerCopy = TRUE; - else - warn("%s: ServerCopy on argument is meaningless", arg->argName); - } - - if (arg->argFlags & flCountInOut) { - if (it->itVarArray && it->itInLine && - akCheck(arg->argKind, akbReply)) - arg->argCountInOut = TRUE; - else - warn("%s: CountInOut on argument is meaningless", arg->argName); - } -} - -static void -rtAugmentArgKind(argument_t *arg) -{ - register ipc_type_t *it = arg->argType; - - /* akbVariable means variable-sized inline. */ - - if (it->itVarArray && it->itInLine) - { - if (akCheckAll(arg->argKind, akbRequest|akbReply)) - error("%s: Inline variable-sized arguments can't be InOut", - arg->argName); - arg->argKind = akAddFeature(arg->argKind, akbVariable); - - /* akbIndefinite means inline or out-of-line */ - - if (it->itIndefinite) - arg->argKind = akAddFeature(arg->argKind, akbIndefinite); - } - - /* - * Kernel servers can't do quick-checking of request arguments - * which are out-of-line or ports, because the deallocate bit isn't - * predictable. This is because the deallocate bit is preserved - * at message copyin time and normalized during message copyout. - * This accomodates old IPC programs which expect the deallocate - * bit to be preserved. - */ - - if (akCheck(arg->argKind, akbRequest) && - !arg->argLongForm && - (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC) && - !it->itVarArray && - !(IsKernelServer && (!it->itInLine || - MACH_MSG_TYPE_PORT_ANY(it->itOutName)))) - arg->argKind = akAddFeature(arg->argKind, akbRequestQC); - - if (akCheck(arg->argKind, akbReply) && - !arg->argLongForm && - (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC) && - !it->itVarArray) - arg->argKind = akAddFeature(arg->argKind, akbReplyQC); - - /* - * Need to use a local variable in the following cases: - * 1) There is a translate-out function & the argument is being - * returned. We need to translate it before it hits the message. - * 2) There is a translate-in function & the argument is - * sent and returned. We need a local variable for its address. - * 3) There is a destructor function, which will be used - * (SendRcv and not ReturnSnd), and there is a translate-in - * function whose value must be saved for the destructor. - * 4) This is a count arg, getting returned. The count can't get - * stored directly into the msg-type, because the msg-type won't - * get initialized until later, and that would trash the count. - * 5) This is a poly arg, getting returned. The name can't get - * stored directly into the msg-type, because the msg-type won't - * get initialized until later, and that would trash the name. - * 6) This is a dealloc arg, being returned. The name can't be - * stored directly into the msg_type, because the msg-type - * field is a bit-field. - */ - - if (((it->itOutTrans != strNULL) && - akCheck(arg->argKind, akbReturnSnd)) || - ((it->itInTrans != strNULL) && - akCheckAll(arg->argKind, akbSendRcv|akbReturnSnd)) || - ((it->itDestructor != strNULL) && - akCheck(arg->argKind, akbSendRcv) && - !akCheck(arg->argKind, akbReturnSnd) && - (it->itInTrans != strNULL)) || - ((akIdent(arg->argKind) == akeCount) && - akCheck(arg->argKind, akbReturnSnd)) || - ((akIdent(arg->argKind) == akePoly) && - akCheck(arg->argKind, akbReturnSnd)) || - ((akIdent(arg->argKind) == akeDealloc) && - akCheck(arg->argKind, akbReturnSnd))) - { - arg->argKind = akRemFeature(arg->argKind, akbReplyCopy); - arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); - } - - /* - * If the argument is a variable-length array that can be passed in-line - * or out-of-line, and is being returned, the server procedure - * is passed a pointer to the buffer, which it can change. - */ - if (it->itIndefinite && - akCheck(arg->argKind, akbReturnSnd)) - { - arg->argKind = akAddFeature(arg->argKind, akbPointer); - } -} - -/* arg->argType may be NULL in this function */ - -static void -rtCheckRoutineArg(routine_t *rt, argument_t *arg) -{ - switch (akIdent(arg->argKind)) - { - case akeRequestPort: - if (rt->rtRequestPort != argNULL) - warn("multiple RequestPort args in %s; %s won't be used", - rt->rtName, rt->rtRequestPort->argName); - rt->rtRequestPort = arg; - break; - - case akeReplyPort: - if (akCheck (arg->argKind, akbUserArg)) - { - if (rt->rtUReplyPort != argNULL) - warn("multiple UserReplyPort args in %s; %s won't be used", - rt->rtName, rt->rtUReplyPort->argName); - rt->rtUReplyPort = arg; - } - if (akCheck (arg->argKind, akbServerArg)) - { - if (rt->rtSReplyPort != argNULL) - warn("multiple ServerReplyPort args in %s; %s won't be used", - rt->rtName, rt->rtSReplyPort->argName); - rt->rtSReplyPort = arg; - } - break; - - case akeWaitTime: - if (rt->rtWaitTime != argNULL) - warn("multiple WaitTime args in %s; %s won't be used", - rt->rtName, rt->rtWaitTime->argName); - rt->rtWaitTime = arg; - break; - - case akeMsgOption: - if (rt->rtMsgOption != argNULL) - warn("multiple MsgOption args in %s; %s won't be used", - rt->rtName, rt->rtMsgOption->argName); - rt->rtMsgOption = arg; - break; - - case akeMsgSeqno: - if (rt->rtMsgSeqno != argNULL) - warn("multiple MsgSeqno args in %s; %s won't be used", - rt->rtName, rt->rtMsgSeqno->argName); - rt->rtMsgSeqno = arg; - break; - - case akeReturn: - if (rt->rtReturn != argNULL) - warn("multiple Return args in %s; %s won't be used", - rt->rtName, rt->rtReturn->argName); - rt->rtReturn = arg; - break; - - default: - break; - } -} - -/* arg->argType may be NULL in this function */ - -static void -rtSetArgDefaults(routine_t *rt, register argument_t *arg) -{ - arg->argRoutine = rt; - if (arg->argVarName == strNULL) - arg->argVarName = arg->argName; - if (arg->argMsgField == strNULL) - switch(akIdent(arg->argKind)) - { - case akeRequestPort: - arg->argMsgField = "Head.msgh_request_port"; - break; - case akeReplyPort: - arg->argMsgField = "Head.msgh_reply_port"; - break; - case akeMsgSeqno: - arg->argMsgField = "Head.msgh_seqno"; - break; - default: - arg->argMsgField = arg->argName; - break; - } - if (arg->argTTName == strNULL) - arg->argTTName = strconcat(arg->argName, "Type"); - if (arg->argPadName == strNULL) - arg->argPadName = strconcat(arg->argName, "Pad"); - - /* - * The poly args for the request and reply ports have special defaults, - * because their msg-type-name values aren't stored in normal fields. - */ - - if ((rt->rtRequestPort != argNULL) && - (rt->rtRequestPort->argPoly == arg) && - (arg->argType != itNULL)) { - arg->argMsgField = "Head.msgh_bits"; - arg->argType->itInTrans = "MACH_MSGH_BITS_REQUEST"; - } - - if ((rt->rtUReplyPort != argNULL) && - (rt->rtUReplyPort->argPoly == arg) && - (arg->argType != itNULL)) { - arg->argMsgField = "Head.msgh_bits"; - arg->argType->itInTrans = "MACH_MSGH_BITS_REPLY"; - } - if ((rt->rtSReplyPort != argNULL) && - (rt->rtSReplyPort->argPoly == arg) && - (arg->argType != itNULL)) { - arg->argMsgField = "Head.msgh_bits"; - arg->argType->itInTrans = "MACH_MSGH_BITS_REPLY"; - } -} - -static void -rtAddCountArg(register argument_t *arg) -{ - register argument_t *count; - - count = argAlloc(); - count->argName = strconcat(arg->argName, "Cnt"); - count->argType = itMakeCountType(); - count->argParent = arg; - count->argMultiplier = arg->argType->itElement->itNumber; - count->argNext = arg->argNext; - arg->argNext = count; - arg->argCount = count; - - if (arg->argType->itString) { - /* C String gets no Count argument on either side. - There is no explicit field in the message - - the count is passed as part of the descriptor. */ - count->argKind = akeCount; - count->argVarName = (char *)0; - } else - count->argKind = akAddFeature(akCount, - akCheck(arg->argKind, akbSendReturnBits)); - - if (arg->argLongForm) - count->argMsgField = strconcat(arg->argTTName, - ".msgtl_number"); - else - count->argMsgField = strconcat(arg->argTTName, ".msgt_number"); -} - -static void -rtAddCountInOutArg(register argument_t *arg) -{ - register argument_t *count; - - /* - * The user sees a single count variable. However, to get the - * count passed from user to server for variable-sized inline OUT - * arrays, we need two count arguments internally. This is - * because the count value lives in different message fields (and - * is scaled differently) in the request and reply messages. - * - * The two variables have the same name to simplify code generation. - * - * This variable has a null argParent field because it has akbRequest. - * For example, see rtCheckVariable. - */ - - count = argAlloc(); - count->argName = strconcat(arg->argName, "Cnt"); - count->argType = itMakeCountType(); - count->argParent = argNULL; - count->argNext = arg->argNext; - arg->argNext = count; - (count->argCInOut = arg->argCount)->argCInOut = count; - count->argKind = akCountInOut; -} - -static void -rtAddPolyArg(register argument_t *arg) -{ - register const ipc_type_t *it = arg->argType; - register argument_t *poly; - arg_kind_t akbsend, akbreturn; - - poly = argAlloc(); - poly->argName = strconcat(arg->argName, "Poly"); - poly->argType = itMakePolyType(); - poly->argParent = arg; - poly->argNext = arg->argNext; - arg->argNext = poly; - arg->argPoly = poly; - - /* - * akbsend is bits added if the arg is In; - * akbreturn is bits added if the arg is Out. - * The mysterious business with KernelServer subsystems: - * when packing Out arguments, they use OutNames instead - * of InNames, and the OutName determines if they are poly-in - * as well as poly-out. - */ - - akbsend = akbSend|akbSendBody; - akbreturn = akbReturn|akbReturnBody; - - if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC) - { - akbsend |= akbUserArg|akbSendSnd; - if (!IsKernelServer) - akbreturn |= akbServerArg|akbReturnSnd; - } - if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC) - { - akbsend |= akbServerArg|akbSendRcv; - akbreturn |= akbUserArg|akbReturnRcv; - if (IsKernelServer) - akbreturn |= akbServerArg|akbReturnSnd; - } - - poly->argKind = akPoly; - if (akCheck(arg->argKind, akbSend)) - poly->argKind = akAddFeature(poly->argKind, - akCheck(arg->argKind, akbsend)); - if (akCheck(arg->argKind, akbReturn)) - poly->argKind = akAddFeature(poly->argKind, - akCheck(arg->argKind, akbreturn)); - - if (arg->argLongForm) - poly->argMsgField = strconcat(arg->argTTName, - ".msgtl_name"); - else - poly->argMsgField = strconcat(arg->argTTName, ".msgt_name"); -} - -static void -rtAddDeallocArg(register argument_t *arg) -{ - register argument_t *dealloc; - - dealloc = argAlloc(); - dealloc->argName = strconcat(arg->argName, "Dealloc"); - dealloc->argType = itMakeDeallocType(); - dealloc->argParent = arg; - dealloc->argNext = arg->argNext; - arg->argNext = dealloc; - arg->argDealloc = dealloc; - - /* - * For Indefinite types, we leave out akbSendSnd and akbReturnSnd - * so that the normal argument-packing is bypassed. The special code - * generated for the Indefinite argument handles the deallocate bit. - * (It can only be enabled if the data is actually out-of-line.) - */ - - dealloc->argKind = akeDealloc; - if (akCheck(arg->argKind, akbSend)) - dealloc->argKind = akAddFeature(dealloc->argKind, - akCheck(arg->argKind, - akbUserArg|akbSend|akbSendBody| - (arg->argType->itIndefinite ? 0 : akbSendSnd))); - if (akCheck(arg->argKind, akbReturn)) { - dealloc->argKind = akAddFeature(dealloc->argKind, - akCheck(arg->argKind, - akbServerArg|akbReturn|akbReturnBody| - (arg->argType->itIndefinite ? 0 : akbReturnSnd))); - - /* - * Without akbReturnSnd, rtAugmentArgKind will not add - * akbVarNeeded and rtAddByReference will not set - * argByReferenceServer. So we do it here. - */ - - if (arg->argType->itIndefinite) { - dealloc->argKind = akAddFeature(dealloc->argKind, akbVarNeeded); - dealloc->argByReferenceServer = TRUE; - } - } - - if (arg->argLongForm) - dealloc->argMsgField = strconcat(arg->argTTName, - ".msgtl_header.msgt_deallocate"); - else - dealloc->argMsgField = strconcat(arg->argTTName, ".msgt_deallocate"); - -} - -static void -rtAddSCopyArg(register argument_t *arg) -{ - register argument_t *scopy; - - scopy = argAlloc(); - scopy->argName = strconcat(arg->argName, "SCopy"); - scopy->argType = itMakeDeallocType(); - scopy->argParent = arg; - scopy->argNext = arg->argNext; - arg->argNext = scopy; - arg->argSCopy = scopy; - - scopy->argKind = akServerCopy; - - if (arg->argLongForm) - scopy->argMsgField = strconcat(arg->argTTName, - ".msgtl_header.msgt_inline"); - else - scopy->argMsgField = strconcat(arg->argTTName, ".msgt_inline"); -} - -static void -rtCheckRoutineArgs(routine_t *rt) -{ - register argument_t *arg; - - for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) - { - register const ipc_type_t *it = arg->argType; - - rtDefaultArgKind(rt, arg); - rtCheckRoutineArg(rt, arg); - - /* need to set argTTName before adding implicit args */ - rtSetArgDefaults(rt, arg); - - /* the arg may not have a type (if there was some error in parsing it), - in which case we don't want to do these steps. */ - - if (it != itNULL) - { - /* need to set argLongForm before adding implicit args */ - rtProcessArgFlags(arg); - rtAugmentArgKind(arg); - - /* args added here will get processed in later iterations */ - /* order of args is 'arg poly countinout count dealloc scopy' */ - - if (arg->argServerCopy) - rtAddSCopyArg(arg); - if (arg->argDeallocate == d_MAYBE) - rtAddDeallocArg(arg); - if (it->itVarArray) - rtAddCountArg(arg); - if (arg->argCountInOut) - rtAddCountInOutArg(arg); - if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) || - (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) - rtAddPolyArg(arg); - } - } -} - -static void -rtCheckArgTypes(routine_t *rt) -{ - if (rt->rtRequestPort == argNULL) - error("%s %s doesn't have a server port argument", - rtRoutineKindToStr(rt->rtKind), rt->rtName); - - if ((rt->rtKind == rkFunction) && - (rt->rtReturn == argNULL)) - error("Function %s doesn't have a return arg", rt->rtName); - - if ((rt->rtKind != rkFunction) && - (rt->rtReturn != argNULL)) - error("non-function %s has a return arg", rt->rtName); - - if ((rt->rtReturn == argNULL) && !rt->rtProcedure) - rt->rtReturn = rt->rtRetCode; - - rt->rtServerReturn = rt->rtReturn; - - if ((rt->rtReturn != argNULL) && - (rt->rtReturn->argType != itNULL)) - itCheckReturnType(rt->rtReturn->argName, - rt->rtReturn->argType); - - if ((rt->rtRequestPort != argNULL) && - (rt->rtRequestPort->argType != itNULL)) - itCheckRequestPortType(rt->rtRequestPort->argName, - rt->rtRequestPort->argType); - - if ((rt->rtUReplyPort != argNULL) && - (rt->rtUReplyPort->argType != itNULL)) - itCheckReplyPortType(rt->rtUReplyPort->argName, - rt->rtUReplyPort->argType); - if ((rt->rtSReplyPort != argNULL) && - (rt->rtSReplyPort->argType != itNULL)) - itCheckReplyPortType(rt->rtSReplyPort->argName, - rt->rtSReplyPort->argType); - - if ((rt->rtWaitTime != argNULL) && - (rt->rtWaitTime->argType != itNULL)) - itCheckIntType(rt->rtWaitTime->argName, - rt->rtWaitTime->argType); - - if ((rt->rtMsgOption != argNULL) && - (rt->rtMsgOption->argType != itNULL)) - itCheckIntType(rt->rtMsgOption->argName, - rt->rtMsgOption->argType); - - if ((rt->rtMsgSeqno != argNULL) && - (rt->rtMsgSeqno->argType != itNULL)) - itCheckNaturalType(rt->rtMsgSeqno->argName, - rt->rtMsgSeqno->argType); -} - -/* - * Check for arguments which are missing seemingly needed functions. - * We make this check here instead of in itCheckDecl, because here - * we can take into account what kind of argument the type is - * being used with. - * - * These are warnings, not hard errors, because mig will generate - * reasonable code in any case. The generated code will work fine - * if the ServerType and TransType are really the same, even though - * they have different names. - */ - -static void -rtCheckArgTrans(const routine_t *rt) -{ - register const argument_t *arg; - - /* the arg may not have a type (if there was some error in parsing it) */ - - for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) - { - register const ipc_type_t *it = arg->argType; - - if ((it != itNULL) && - !streql(it->itServerType, it->itTransType)) - { - if (akCheck(arg->argKind, akbSendRcv) && - (it->itInTrans == strNULL)) - warn("%s: argument has no in-translation function", - arg->argName); - - if (akCheck(arg->argKind, akbReturnSnd) && - (it->itOutTrans == strNULL)) - warn("%s: argument has no out-translation function", - arg->argName); - } - } -} - -/* - * Adds an implicit return-code argument. It exists in the reply message, - * where it is the first piece of data. Even if there is no reply - * message (rtOneWay is true), we generate the argument because - * the server-side stub needs a dummy reply msg to return error codes - * back to the server loop. - */ - -static void -rtAddRetCode(routine_t *rt) -{ - register argument_t *arg = argAlloc(); - - arg->argName = "RetCode"; - arg->argType = itRetCodeType; - arg->argKind = akRetCode; - rt->rtRetCode = arg; - - /* add at beginning, so return-code is first in the reply message */ - arg->argNext = rt->rtArgs; - rt->rtArgs = arg; -} - -/* - * Adds a dummy WaitTime argument to the function. - * This argument doesn't show up in any C argument lists; - * it implements the global WaitTime statement. - */ - -static void -rtAddWaitTime(routine_t *rt, identifier_t name) -{ - register argument_t *arg = argAlloc(); - argument_t **loc; - - arg->argName = "dummy WaitTime arg"; - arg->argVarName = name; - arg->argType = itWaitTimeType; - arg->argKind = akeWaitTime; - rt->rtWaitTime = arg; - - /* add wait-time after msg-option, if possible */ - - if (rt->rtMsgOption != argNULL) - loc = &rt->rtMsgOption->argNext; - else - loc = &rt->rtArgs; - - arg->argNext = *loc; - *loc = arg; - - rtSetArgDefaults(rt, arg); -} - -/* - * Adds a dummy MsgOption argument to the function. - * This argument doesn't show up in any C argument lists; - * it implements the global MsgOption statement. - */ - -static void -rtAddMsgOption(routine_t *rt, identifier_t name) -{ - register argument_t *arg = argAlloc(); - argument_t **loc; - - arg->argName = "dummy MsgOption arg"; - arg->argVarName = name; - arg->argType = itMsgOptionType; - arg->argKind = akeMsgOption; - rt->rtMsgOption = arg; - - /* add msg-option after msg-seqno */ - - if (rt->rtMsgSeqno != argNULL) - loc = &rt->rtMsgSeqno->argNext; - else - loc = &rt->rtArgs; - - arg->argNext = *loc; - *loc = arg; - - rtSetArgDefaults(rt, arg); -} - -/* - * Adds a dummy reply port argument to the function. If USER is true, the - * user reply port is set, otherwise the server. - */ - -static void -rtAddDummyReplyPort(routine_t *rt, ipc_type_t *type, int user) -{ - register argument_t *arg = argAlloc(); - argument_t **loc; - - arg->argName = "dummy ReplyPort arg"; - arg->argVarName = "dummy ReplyPort arg"; - arg->argType = type; - arg->argKind = akeReplyPort; - if (user) - rt->rtUReplyPort = arg; - else - rt->rtSReplyPort = arg; - - /* add the reply port after the request port */ - - if (rt->rtRequestPort != argNULL) - loc = &rt->rtRequestPort->argNext; - else - loc = &rt->rtArgs; - - arg->argNext = *loc; - *loc = arg; - - rtSetArgDefaults(rt, arg); -} - -/* - * Initializes argRequestPos, argReplyPos, rtMaxRequestPos, rtMaxReplyPos, - * rtNumRequestVar, rtNumReplyVar, and adds akbVarNeeded to those arguments - * that need it because of variable-sized inline considerations. - * - * argRequestPos and argReplyPos get -1 if the value shouldn't be used. - */ -static void -rtCheckVariable(register routine_t *rt) -{ - register argument_t *arg; - int NumRequestVar = 0; - int NumReplyVar = 0; - int MaxRequestPos = 0; - int MaxReplyPos = 0; - - for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { - register argument_t *parent = arg->argParent; - - if (parent == argNULL) { - if (akCheck(arg->argKind, akbRequest|akbSend)) { - arg->argRequestPos = NumRequestVar; - MaxRequestPos = NumRequestVar; - if (akCheck(arg->argKind, akbVariable)) - NumRequestVar++; - } else - arg->argRequestPos = -1; - - if (akCheck(arg->argKind, akbReply|akbReturn)) { - arg->argReplyPos = NumReplyVar; - MaxReplyPos = NumReplyVar; - if (akCheck(arg->argKind, akbVariable)) - NumReplyVar++; - } else - arg->argReplyPos = -1; - } else { - arg->argRequestPos = parent->argRequestPos; - arg->argReplyPos = parent->argReplyPos; - } - - /* Out variables that follow a variable-sized field - need VarNeeded or ReplyCopy; they can't be stored - directly into the reply message. */ - - if (akCheck(arg->argKind, akbReturnSnd) && - !akCheck(arg->argKind, akbReplyCopy|akbVarNeeded) && - (arg->argReplyPos > 0)) - arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); - } - - rt->rtNumRequestVar = NumRequestVar; - rt->rtNumReplyVar = NumReplyVar; - rt->rtMaxRequestPos = MaxRequestPos; - rt->rtMaxReplyPos = MaxReplyPos; -} - -/* - * Adds akbDestroy where needed. - */ - -static void -rtCheckDestroy(register routine_t *rt) -{ - register argument_t *arg; - - for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { - register const ipc_type_t *it = arg->argType; - - if(akCheck(arg->argKind, akbSendRcv) && - !akCheck(arg->argKind, akbReturnSnd)) { - if ((it->itDestructor != strNULL) || - (akCheck(arg->argKind, akbIndefinite) && !arg->argServerCopy)) - arg->argKind = akAddFeature(arg->argKind, akbDestroy); - } - } -} - -/* - * Sets ByReferenceUser and ByReferenceServer. - */ - -static void -rtAddByReference(register routine_t *rt) -{ - register argument_t *arg; - - for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { - register const ipc_type_t *it = arg->argType; - - if (akCheck(arg->argKind, akbReturnRcv) && - (it->itStruct || it->itIndefinite)) { - arg->argByReferenceUser = TRUE; - - /* - * A CountInOut arg itself is not akbReturnRcv, - * so we need to set argByReferenceUser specially. - */ - - if (arg->argCInOut != argNULL) - arg->argCInOut->argByReferenceUser = TRUE; - } - - if (akCheck(arg->argKind, akbReturnSnd) && - (it->itStruct || it->itIndefinite)) - arg->argByReferenceServer = TRUE; - } -} - -void -rtCheckRoutine(register routine_t *rt) -{ - /* Initialize random fields. */ - - rt->rtErrorName = ErrorProc; - rt->rtOneWay = ((rt->rtKind == rkSimpleProcedure) || - (rt->rtKind == rkSimpleRoutine)); - rt->rtProcedure = ((rt->rtKind == rkProcedure) || - (rt->rtKind == rkSimpleProcedure)); - rt->rtUseError = rt->rtProcedure || (rt->rtKind == rkFunction); - rt->rtServerName = strconcat(ServerPrefix, rt->rtName); - rt->rtServerName = strconcat(RoutinePrefix, rt->rtServerName); - rt->rtUserName = strconcat(UserPrefix, rt->rtName); - rt->rtUserName = strconcat(RoutinePrefix, rt->rtUserName); - - /* Add implicit arguments. */ - - rtAddRetCode(rt); - - /* Check out the arguments and their types. Add count, poly - implicit args. Any arguments added after rtCheckRoutineArgs - should have rtSetArgDefaults called on them. */ - - rtCheckRoutineArgs(rt); - - /* Add dummy WaitTime and MsgOption arguments, if the routine - doesn't have its own args and the user specified global values. */ - - if (rt->rtUReplyPort == argNULL) - if (rt->rtOneWay) - rtAddDummyReplyPort(rt, itZeroReplyPortType, 1); - else - rtAddDummyReplyPort(rt, itRealReplyPortType, 1); - if (rt->rtSReplyPort == argNULL) - if (rt->rtOneWay) - rtAddDummyReplyPort(rt, itZeroReplyPortType, 0); - else - rtAddDummyReplyPort(rt, itRealReplyPortType, 0); - - if (rt->rtMsgOption == argNULL) - if (MsgOption == strNULL) - rtAddMsgOption(rt, "MACH_MSG_OPTION_NONE"); - else - rtAddMsgOption(rt, MsgOption); - - if ((rt->rtWaitTime == argNULL) && - (WaitTime != strNULL)) - rtAddWaitTime(rt, WaitTime); - - /* Now that all the arguments are in place, do more checking. */ - - rtCheckArgTypes(rt); - rtCheckArgTrans(rt); - - if (rt->rtOneWay && rtCheckMask(rt->rtArgs, akbReturn)) - error("%s %s has OUT argument", - rtRoutineKindToStr(rt->rtKind), rt->rtName); - - /* If there were any errors, don't bother calculating more info - that is only used in code generation anyway. Therefore, - the following functions don't have to worry about null types. */ - - if (errors > 0) - return; - - rtCheckSimpleIn(rt->rtArgs, akbRequest, - &rt->rtSimpleFixedRequest, - &rt->rtSimpleSendRequest); - rtCheckSimpleOut(rt->rtArgs, akbRequest, - &rt->rtSimpleCheckRequest, - &rt->rtSimpleReceiveRequest); - rt->rtRequestSize = rtFindSize(rt->rtArgs, akbRequest); - - if (IsKernelServer) - rtCheckSimpleOut(rt->rtArgs, akbReply, - &rt->rtSimpleFixedReply, - &rt->rtSimpleSendReply); - else - rtCheckSimpleIn(rt->rtArgs, akbReply, - &rt->rtSimpleFixedReply, - &rt->rtSimpleSendReply); - rtCheckSimpleOut(rt->rtArgs, akbReply, - &rt->rtSimpleCheckReply, - &rt->rtSimpleReceiveReply); - rt->rtReplySize = rtFindSize(rt->rtArgs, akbReply); - - rtCheckVariable(rt); - rtCheckDestroy(rt); - rtAddByReference(rt); - - if (rt->rtKind == rkFunction) - rt->rtNoReplyArgs = FALSE; - else - rt->rtNoReplyArgs = !rtCheckMask(rt->rtArgs, akbReturnSnd); -} |