|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1992,1991,1990 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: ! 27: /* ! 28: * ABSTRACT: ! 29: * Provides the routine used by parser.c to generate ! 30: * routine structures for each routine statement. ! 31: * The parser generates a threaded list of statements ! 32: * of which the most interesting are the various kinds ! 33: * routine statments. The routine structure is defined ! 34: * in routine.h which includes it name, kind of routine ! 35: * and other information, ! 36: * a pointer to an argument list which contains the name ! 37: * and type information for each argument, and a list ! 38: * of distinguished arguments, eg. Request and Reply ! 39: * ports, waittime, retcode etc. ! 40: */ ! 41: ! 42: #include <stdio.h> ! 43: #include <stdlib.h> ! 44: ! 45: #include "error.h" ! 46: #include "global.h" ! 47: #include "routine.h" ! 48: #include "message.h" ! 49: ! 50: u_int rtNumber = 0; ! 51: ! 52: routine_t * ! 53: rtAlloc(void) ! 54: { ! 55: register routine_t *new; ! 56: ! 57: new = (routine_t *) calloc(1, sizeof *new); ! 58: if (new == rtNULL) ! 59: fatal("rtAlloc(): %s", unix_error_string(errno)); ! 60: new->rtNumber = rtNumber++; ! 61: new->rtName = strNULL; ! 62: new->rtErrorName = strNULL; ! 63: new->rtUserName = strNULL; ! 64: new->rtServerName = strNULL; ! 65: ! 66: return new; ! 67: } ! 68: ! 69: void ! 70: rtSkip(int n) ! 71: { ! 72: rtNumber += n; ! 73: } ! 74: ! 75: argument_t * ! 76: argAlloc(void) ! 77: { ! 78: static const argument_t prototype = ! 79: { ! 80: strNULL, /* identifier_t argName */ ! 81: argNULL, /* argument_t *argNext */ ! 82: akNone, /* arg_kind_t argKind */ ! 83: itNULL, /* ipc_type_t *argType */ ! 84: strNULL, /* string_t argVarName */ ! 85: strNULL, /* string_t argMsgField */ ! 86: strNULL, /* string_t argTTName */ ! 87: strNULL, /* string_t argPadName */ ! 88: flNone, /* ipc_flags_t argFlags */ ! 89: d_NO, /* dealloc_t argDeallocate */ ! 90: FALSE, /* boolean_t argLongForm */ ! 91: FALSE, /* boolean_t argServerCopy */ ! 92: FALSE, /* boolean_t argCountInOut */ ! 93: rtNULL, /* routine_t *argRoutine */ ! 94: argNULL, /* argument_t *argCount */ ! 95: argNULL, /* argument_t *argCInOut */ ! 96: argNULL, /* argument_t *argPoly */ ! 97: argNULL, /* argument_t *argDealloc */ ! 98: argNULL, /* argument_t *argSCopy */ ! 99: argNULL, /* argument_t *argParent */ ! 100: 1, /* int argMultiplier */ ! 101: 0, /* int argRequestPos */ ! 102: 0, /* int argReplyPos */ ! 103: FALSE, /* boolean_t argByReferenceUser */ ! 104: FALSE /* boolean_t argByReferenceServer */ ! 105: }; ! 106: register argument_t *new; ! 107: ! 108: new = malloc(sizeof *new); ! 109: if (new == argNULL) ! 110: fatal("argAlloc(): %s", unix_error_string(errno)); ! 111: *new = prototype; ! 112: return new; ! 113: } ! 114: ! 115: routine_t * ! 116: rtMakeRoutine(identifier_t name, argument_t *args) ! 117: { ! 118: register routine_t *rt = rtAlloc(); ! 119: ! 120: rt->rtName = name; ! 121: rt->rtKind = rkRoutine; ! 122: rt->rtArgs = args; ! 123: ! 124: return rt; ! 125: } ! 126: ! 127: routine_t * ! 128: rtMakeSimpleRoutine(identifier_t name, argument_t *args) ! 129: { ! 130: register routine_t *rt = rtAlloc(); ! 131: ! 132: rt->rtName = name; ! 133: rt->rtKind = rkSimpleRoutine; ! 134: rt->rtArgs = args; ! 135: ! 136: return rt; ! 137: } ! 138: ! 139: routine_t * ! 140: rtMakeProcedure(identifier_t name, argument_t *args) ! 141: { ! 142: register routine_t *rt = rtAlloc(); ! 143: ! 144: rt->rtName = name; ! 145: rt->rtKind = rkProcedure; ! 146: rt->rtArgs = args; ! 147: ! 148: warn("Procedure %s: obsolete routine kind", name); ! 149: ! 150: return rt; ! 151: } ! 152: ! 153: routine_t * ! 154: rtMakeSimpleProcedure(identifier_t name, argument_t *args) ! 155: { ! 156: register routine_t *rt = rtAlloc(); ! 157: ! 158: rt->rtName = name; ! 159: rt->rtKind = rkSimpleProcedure; ! 160: rt->rtArgs = args; ! 161: ! 162: warn("SimpleProcedure %s: obsolete routine kind", name); ! 163: ! 164: return rt; ! 165: } ! 166: ! 167: routine_t * ! 168: rtMakeFunction(identifier_t name, argument_t *args, ipc_type_t *type) ! 169: { ! 170: register routine_t *rt = rtAlloc(); ! 171: register argument_t *ret = argAlloc(); ! 172: ! 173: ret->argName = name; ! 174: ret->argKind = akReturn; ! 175: ret->argType = type; ! 176: ret->argNext = args; ! 177: ! 178: rt->rtName = name; ! 179: rt->rtKind = rkFunction; ! 180: rt->rtArgs = ret; ! 181: ! 182: warn("Function %s: obsolete routine kind", name); ! 183: ! 184: return rt; ! 185: } ! 186: ! 187: const char * ! 188: rtRoutineKindToStr(routine_kind_t rk) ! 189: { ! 190: switch (rk) ! 191: { ! 192: case rkRoutine: ! 193: return "Routine"; ! 194: case rkSimpleRoutine: ! 195: return "SimpleRoutine"; ! 196: case rkProcedure: ! 197: return "Procedure"; ! 198: case rkSimpleProcedure: ! 199: return "SimpleProcedure"; ! 200: case rkFunction: ! 201: return "Function"; ! 202: default: ! 203: fatal("rtRoutineKindToStr(%d): not a routine_kind_t", rk); ! 204: /*NOTREACHED*/ ! 205: } ! 206: } ! 207: ! 208: static void ! 209: rtPrintArg(register const argument_t *arg) ! 210: { ! 211: register const ipc_type_t *it = arg->argType; ! 212: ! 213: if (!akCheck(arg->argKind, akbUserArg|akbServerArg) || ! 214: (akIdent(arg->argKind) == akeCount) || ! 215: (akIdent(arg->argKind) == akePoly)) ! 216: return; ! 217: ! 218: printf("\n\t"); ! 219: ! 220: switch (akIdent(arg->argKind)) ! 221: { ! 222: case akeRequestPort: ! 223: printf("RequestPort"); ! 224: break; ! 225: case akeReplyPort: ! 226: printf("ReplyPort"); ! 227: break; ! 228: case akeWaitTime: ! 229: printf("WaitTime"); ! 230: break; ! 231: case akeMsgOption: ! 232: printf("MsgOption"); ! 233: break; ! 234: case akeMsgSeqno: ! 235: printf("MsgSeqno\t"); ! 236: break; ! 237: default: ! 238: if (akCheck(arg->argKind, akbRequest)) ! 239: if (akCheck(arg->argKind, akbSend)) ! 240: printf("In"); ! 241: else ! 242: printf("(In)"); ! 243: if (akCheck(arg->argKind, akbReply)) ! 244: if (akCheck(arg->argKind, akbReturn)) ! 245: printf("Out"); ! 246: else ! 247: printf("(Out)"); ! 248: printf("\t"); ! 249: } ! 250: ! 251: printf("\t%s: %s", arg->argName, it->itName); ! 252: ! 253: if (arg->argDeallocate != it->itDeallocate) ! 254: if (arg->argDeallocate == d_YES) ! 255: printf(", Dealloc"); ! 256: else if (arg->argDeallocate == d_MAYBE) ! 257: printf(", Dealloc[]"); ! 258: else ! 259: printf(", NotDealloc"); ! 260: ! 261: if (arg->argLongForm != it->itLongForm) ! 262: if (arg->argLongForm) ! 263: printf(", IsLong"); ! 264: else ! 265: printf(", IsNotLong"); ! 266: ! 267: if (arg->argServerCopy) ! 268: printf(", ServerCopy"); ! 269: ! 270: if (arg->argCountInOut) ! 271: printf(", CountInOut"); ! 272: } ! 273: ! 274: void ! 275: rtPrintRoutine(register const routine_t *rt) ! 276: { ! 277: register const argument_t *arg; ! 278: ! 279: printf("%s (%d) %s(", rtRoutineKindToStr(rt->rtKind), ! 280: rt->rtNumber, rt->rtName); ! 281: ! 282: for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) ! 283: rtPrintArg(arg); ! 284: ! 285: if (rt->rtKind == rkFunction) ! 286: printf("): %s\n", rt->rtReturn->argType->itName); ! 287: else ! 288: printf(")\n"); ! 289: ! 290: printf("\n"); ! 291: } ! 292: ! 293: /* ! 294: * Determines appropriate value of msg-simple for the message, ! 295: * and whether this value can vary at runtime. (If it can vary, ! 296: * then the simple value is optimistically returned as TRUE.) ! 297: * Uses itInName values, so useful when sending messages. ! 298: */ ! 299: ! 300: static void ! 301: rtCheckSimpleIn(const argument_t *args, u_int mask, boolean_t *fixed, ! 302: boolean_t *simple) ! 303: { ! 304: register const argument_t *arg; ! 305: boolean_t MayBeComplex = FALSE; ! 306: boolean_t MustBeComplex = FALSE; ! 307: ! 308: for (arg = args; arg != argNULL; arg = arg->argNext) ! 309: if (akCheck(arg->argKind, mask)) ! 310: { ! 311: register const ipc_type_t *it = arg->argType; ! 312: ! 313: if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC) ! 314: MayBeComplex = TRUE; ! 315: ! 316: if (it->itIndefinite) ! 317: MayBeComplex = TRUE; ! 318: ! 319: if (MACH_MSG_TYPE_PORT_ANY(it->itInName) || ! 320: !it->itInLine) ! 321: MustBeComplex = TRUE; ! 322: } ! 323: ! 324: *fixed = MustBeComplex || !MayBeComplex; ! 325: *simple = !MustBeComplex; ! 326: } ! 327: ! 328: /* ! 329: * Determines appropriate value of msg-simple for the message, ! 330: * and whether this value can vary at runtime. (If it can vary, ! 331: * then the simple value is optimistically returned as TRUE.) ! 332: * Uses itOutName values, so useful when receiving messages ! 333: * (and sending reply messages in KernelServer interfaces). ! 334: */ ! 335: ! 336: static void ! 337: rtCheckSimpleOut(const argument_t *args, u_int mask, boolean_t *fixed, ! 338: boolean_t *simple) ! 339: { ! 340: register const argument_t *arg; ! 341: boolean_t MayBeComplex = FALSE; ! 342: boolean_t MustBeComplex = FALSE; ! 343: ! 344: for (arg = args; arg != argNULL; arg = arg->argNext) ! 345: if (akCheck(arg->argKind, mask)) ! 346: { ! 347: register const ipc_type_t *it = arg->argType; ! 348: ! 349: if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC) ! 350: MayBeComplex = TRUE; ! 351: ! 352: if (it->itIndefinite) ! 353: MayBeComplex = TRUE; ! 354: ! 355: if (MACH_MSG_TYPE_PORT_ANY(it->itOutName) || ! 356: !it->itInLine) ! 357: MustBeComplex = TRUE; ! 358: } ! 359: ! 360: *fixed = MustBeComplex || !MayBeComplex; ! 361: *simple = !MustBeComplex; ! 362: } ! 363: ! 364: static u_int ! 365: rtFindSize(const argument_t *args, u_int mask) ! 366: { ! 367: register const argument_t *arg; ! 368: u_int size = sizeof_mach_msg_header_t; ! 369: ! 370: for (arg = args; arg != argNULL; arg = arg->argNext) ! 371: if (akCheck(arg->argKind, mask)) ! 372: { ! 373: register ipc_type_t *it = arg->argType; ! 374: ! 375: if (arg->argLongForm) { ! 376: /* might need proper alignment on 64bit archies */ ! 377: size = (size + word_size-1) & ~(word_size-1); ! 378: size += sizeof_mach_msg_type_long_t; ! 379: } else { ! 380: register bs = (it->itSize / 8); /* in bytes */ ! 381: size += (bs > sizeof_mach_msg_type_t) ? bs : sizeof_mach_msg_type_t; ! 382: } ! 383: ! 384: size += it->itMinTypeSize; ! 385: } ! 386: ! 387: return size; ! 388: } ! 389: ! 390: boolean_t ! 391: rtCheckMask(const argument_t *args, u_int mask) ! 392: { ! 393: register const argument_t *arg; ! 394: ! 395: for (arg = args; arg != argNULL; arg = arg->argNext) ! 396: if (akCheckAll(arg->argKind, mask)) ! 397: return TRUE; ! 398: return FALSE; ! 399: } ! 400: ! 401: boolean_t ! 402: rtCheckMaskFunction(const argument_t *args, u_int mask, ! 403: boolean_t (*func)(const argument_t *)) ! 404: { ! 405: register const argument_t *arg; ! 406: ! 407: for (arg = args; arg != argNULL; arg = arg->argNext) ! 408: if (akCheckAll(arg->argKind, mask)) ! 409: if ((*func)(arg)) ! 410: return TRUE; ! 411: return FALSE; ! 412: } ! 413: ! 414: /* arg->argType may be NULL in this function */ ! 415: ! 416: static void ! 417: rtDefaultArgKind(const routine_t *rt, argument_t *arg) ! 418: { ! 419: if ((arg->argKind == akNone) && ! 420: (rt->rtRequestPort == argNULL)) ! 421: arg->argKind = akRequestPort; ! 422: ! 423: if (arg->argKind == akNone) ! 424: arg->argKind = akIn; ! 425: } ! 426: ! 427: /* ! 428: * Initializes arg->argDeallocate, arg->argLongForm, ! 429: * arg->argServerCopy, arg->argCountInOut from arg->argFlags. ! 430: */ ! 431: ! 432: static void ! 433: rtProcessArgFlags(register argument_t *arg) ! 434: { ! 435: register const ipc_type_t *it = arg->argType; ! 436: ! 437: arg->argFlags = itCheckFlags(arg->argFlags, arg->argName); ! 438: ! 439: if (((IsKernelServer && akCheck(arg->argKind, akbReturn)) || ! 440: (IsKernelUser && akCheck(arg->argKind, akbSend))) && ! 441: (arg->argFlags & flDealloc) && ! 442: (it->itDeallocate == d_NO)) { ! 443: /* ! 444: * For a KernelServer interface and an Out argument, ! 445: * or a KernelUser interface and an In argument, ! 446: * we avoid a possible spurious warning about the deallocate bit. ! 447: * For compatibility with Mach 2.5, the deallocate bit ! 448: * may need to be enabled on some inline arguments. ! 449: */ ! 450: ! 451: arg->argDeallocate = d_YES; ! 452: } else ! 453: arg->argDeallocate = itCheckDeallocate(it, arg->argFlags, ! 454: it->itDeallocate, arg->argName); ! 455: ! 456: arg->argLongForm = itCheckIsLong(it, arg->argFlags, ! 457: it->itLongForm, arg->argName); ! 458: ! 459: if (arg->argFlags & flServerCopy) { ! 460: if (it->itIndefinite && akCheck(arg->argKind, akbSend)) ! 461: arg->argServerCopy = TRUE; ! 462: else ! 463: warn("%s: ServerCopy on argument is meaningless", arg->argName); ! 464: } ! 465: ! 466: if (arg->argFlags & flCountInOut) { ! 467: if (it->itVarArray && it->itInLine && ! 468: akCheck(arg->argKind, akbReply)) ! 469: arg->argCountInOut = TRUE; ! 470: else ! 471: warn("%s: CountInOut on argument is meaningless", arg->argName); ! 472: } ! 473: } ! 474: ! 475: static void ! 476: rtAugmentArgKind(argument_t *arg) ! 477: { ! 478: register ipc_type_t *it = arg->argType; ! 479: ! 480: /* akbVariable means variable-sized inline. */ ! 481: ! 482: if (it->itVarArray && it->itInLine) ! 483: { ! 484: if (akCheckAll(arg->argKind, akbRequest|akbReply)) ! 485: error("%s: Inline variable-sized arguments can't be InOut", ! 486: arg->argName); ! 487: arg->argKind = akAddFeature(arg->argKind, akbVariable); ! 488: ! 489: /* akbIndefinite means inline or out-of-line */ ! 490: ! 491: if (it->itIndefinite) ! 492: arg->argKind = akAddFeature(arg->argKind, akbIndefinite); ! 493: } ! 494: ! 495: /* ! 496: * Kernel servers can't do quick-checking of request arguments ! 497: * which are out-of-line or ports, because the deallocate bit isn't ! 498: * predictable. This is because the deallocate bit is preserved ! 499: * at message copyin time and normalized during message copyout. ! 500: * This accomodates old IPC programs which expect the deallocate ! 501: * bit to be preserved. ! 502: */ ! 503: ! 504: if (akCheck(arg->argKind, akbRequest) && ! 505: !arg->argLongForm && ! 506: (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC) && ! 507: !it->itVarArray && ! 508: !(IsKernelServer && (!it->itInLine || ! 509: MACH_MSG_TYPE_PORT_ANY(it->itOutName)))) ! 510: arg->argKind = akAddFeature(arg->argKind, akbRequestQC); ! 511: ! 512: if (akCheck(arg->argKind, akbReply) && ! 513: !arg->argLongForm && ! 514: (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC) && ! 515: !it->itVarArray) ! 516: arg->argKind = akAddFeature(arg->argKind, akbReplyQC); ! 517: ! 518: /* ! 519: * Need to use a local variable in the following cases: ! 520: * 1) There is a translate-out function & the argument is being ! 521: * returned. We need to translate it before it hits the message. ! 522: * 2) There is a translate-in function & the argument is ! 523: * sent and returned. We need a local variable for its address. ! 524: * 3) There is a destructor function, which will be used ! 525: * (SendRcv and not ReturnSnd), and there is a translate-in ! 526: * function whose value must be saved for the destructor. ! 527: * 4) This is a count arg, getting returned. The count can't get ! 528: * stored directly into the msg-type, because the msg-type won't ! 529: * get initialized until later, and that would trash the count. ! 530: * 5) This is a poly arg, getting returned. The name can't get ! 531: * stored directly into the msg-type, because the msg-type won't ! 532: * get initialized until later, and that would trash the name. ! 533: * 6) This is a dealloc arg, being returned. The name can't be ! 534: * stored directly into the msg_type, because the msg-type ! 535: * field is a bit-field. ! 536: */ ! 537: ! 538: if (((it->itOutTrans != strNULL) && ! 539: akCheck(arg->argKind, akbReturnSnd)) || ! 540: ((it->itInTrans != strNULL) && ! 541: akCheckAll(arg->argKind, akbSendRcv|akbReturnSnd)) || ! 542: ((it->itDestructor != strNULL) && ! 543: akCheck(arg->argKind, akbSendRcv) && ! 544: !akCheck(arg->argKind, akbReturnSnd) && ! 545: (it->itInTrans != strNULL)) || ! 546: ((akIdent(arg->argKind) == akeCount) && ! 547: akCheck(arg->argKind, akbReturnSnd)) || ! 548: ((akIdent(arg->argKind) == akePoly) && ! 549: akCheck(arg->argKind, akbReturnSnd)) || ! 550: ((akIdent(arg->argKind) == akeDealloc) && ! 551: akCheck(arg->argKind, akbReturnSnd))) ! 552: { ! 553: arg->argKind = akRemFeature(arg->argKind, akbReplyCopy); ! 554: arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); ! 555: } ! 556: ! 557: /* ! 558: * If the argument is a variable-length array that can be passed in-line ! 559: * or out-of-line, and is being returned, the server procedure ! 560: * is passed a pointer to the buffer, which it can change. ! 561: */ ! 562: if (it->itIndefinite && ! 563: akCheck(arg->argKind, akbReturnSnd)) ! 564: { ! 565: arg->argKind = akAddFeature(arg->argKind, akbPointer); ! 566: } ! 567: } ! 568: ! 569: /* arg->argType may be NULL in this function */ ! 570: ! 571: static void ! 572: rtCheckRoutineArg(routine_t *rt, argument_t *arg) ! 573: { ! 574: switch (akIdent(arg->argKind)) ! 575: { ! 576: case akeRequestPort: ! 577: if (rt->rtRequestPort != argNULL) ! 578: warn("multiple RequestPort args in %s; %s won't be used", ! 579: rt->rtName, rt->rtRequestPort->argName); ! 580: rt->rtRequestPort = arg; ! 581: break; ! 582: ! 583: case akeReplyPort: ! 584: if (akCheck (arg->argKind, akbUserArg)) ! 585: { ! 586: if (rt->rtUReplyPort != argNULL) ! 587: warn("multiple UserReplyPort args in %s; %s won't be used", ! 588: rt->rtName, rt->rtUReplyPort->argName); ! 589: rt->rtUReplyPort = arg; ! 590: } ! 591: if (akCheck (arg->argKind, akbServerArg)) ! 592: { ! 593: if (rt->rtSReplyPort != argNULL) ! 594: warn("multiple ServerReplyPort args in %s; %s won't be used", ! 595: rt->rtName, rt->rtSReplyPort->argName); ! 596: rt->rtSReplyPort = arg; ! 597: } ! 598: break; ! 599: ! 600: case akeWaitTime: ! 601: if (rt->rtWaitTime != argNULL) ! 602: warn("multiple WaitTime args in %s; %s won't be used", ! 603: rt->rtName, rt->rtWaitTime->argName); ! 604: rt->rtWaitTime = arg; ! 605: break; ! 606: ! 607: case akeMsgOption: ! 608: if (rt->rtMsgOption != argNULL) ! 609: warn("multiple MsgOption args in %s; %s won't be used", ! 610: rt->rtName, rt->rtMsgOption->argName); ! 611: rt->rtMsgOption = arg; ! 612: break; ! 613: ! 614: case akeMsgSeqno: ! 615: if (rt->rtMsgSeqno != argNULL) ! 616: warn("multiple MsgSeqno args in %s; %s won't be used", ! 617: rt->rtName, rt->rtMsgSeqno->argName); ! 618: rt->rtMsgSeqno = arg; ! 619: break; ! 620: ! 621: case akeReturn: ! 622: if (rt->rtReturn != argNULL) ! 623: warn("multiple Return args in %s; %s won't be used", ! 624: rt->rtName, rt->rtReturn->argName); ! 625: rt->rtReturn = arg; ! 626: break; ! 627: ! 628: default: ! 629: break; ! 630: } ! 631: } ! 632: ! 633: /* arg->argType may be NULL in this function */ ! 634: ! 635: static void ! 636: rtSetArgDefaults(routine_t *rt, register argument_t *arg) ! 637: { ! 638: arg->argRoutine = rt; ! 639: if (arg->argVarName == strNULL) ! 640: arg->argVarName = arg->argName; ! 641: if (arg->argMsgField == strNULL) ! 642: switch(akIdent(arg->argKind)) ! 643: { ! 644: case akeRequestPort: ! 645: arg->argMsgField = "Head.msgh_request_port"; ! 646: break; ! 647: case akeReplyPort: ! 648: arg->argMsgField = "Head.msgh_reply_port"; ! 649: break; ! 650: case akeMsgSeqno: ! 651: arg->argMsgField = "Head.msgh_seqno"; ! 652: break; ! 653: default: ! 654: arg->argMsgField = arg->argName; ! 655: break; ! 656: } ! 657: if (arg->argTTName == strNULL) ! 658: arg->argTTName = strconcat(arg->argName, "Type"); ! 659: if (arg->argPadName == strNULL) ! 660: arg->argPadName = strconcat(arg->argName, "Pad"); ! 661: ! 662: /* ! 663: * The poly args for the request and reply ports have special defaults, ! 664: * because their msg-type-name values aren't stored in normal fields. ! 665: */ ! 666: ! 667: if ((rt->rtRequestPort != argNULL) && ! 668: (rt->rtRequestPort->argPoly == arg) && ! 669: (arg->argType != itNULL)) { ! 670: arg->argMsgField = "Head.msgh_bits"; ! 671: arg->argType->itInTrans = "MACH_MSGH_BITS_REQUEST"; ! 672: } ! 673: ! 674: if ((rt->rtUReplyPort != argNULL) && ! 675: (rt->rtUReplyPort->argPoly == arg) && ! 676: (arg->argType != itNULL)) { ! 677: arg->argMsgField = "Head.msgh_bits"; ! 678: arg->argType->itInTrans = "MACH_MSGH_BITS_REPLY"; ! 679: } ! 680: if ((rt->rtSReplyPort != argNULL) && ! 681: (rt->rtSReplyPort->argPoly == arg) && ! 682: (arg->argType != itNULL)) { ! 683: arg->argMsgField = "Head.msgh_bits"; ! 684: arg->argType->itInTrans = "MACH_MSGH_BITS_REPLY"; ! 685: } ! 686: } ! 687: ! 688: static void ! 689: rtAddCountArg(register argument_t *arg) ! 690: { ! 691: register argument_t *count; ! 692: ! 693: count = argAlloc(); ! 694: count->argName = strconcat(arg->argName, "Cnt"); ! 695: count->argType = itMakeCountType(); ! 696: count->argParent = arg; ! 697: count->argMultiplier = arg->argType->itElement->itNumber; ! 698: count->argNext = arg->argNext; ! 699: arg->argNext = count; ! 700: arg->argCount = count; ! 701: ! 702: if (arg->argType->itString) { ! 703: /* C String gets no Count argument on either side. ! 704: There is no explicit field in the message - ! 705: the count is passed as part of the descriptor. */ ! 706: count->argKind = akeCount; ! 707: count->argVarName = (char *)0; ! 708: } else ! 709: count->argKind = akAddFeature(akCount, ! 710: akCheck(arg->argKind, akbSendReturnBits)); ! 711: ! 712: if (arg->argLongForm) ! 713: count->argMsgField = strconcat(arg->argTTName, ! 714: ".msgtl_number"); ! 715: else ! 716: count->argMsgField = strconcat(arg->argTTName, ".msgt_number"); ! 717: } ! 718: ! 719: static void ! 720: rtAddCountInOutArg(register argument_t *arg) ! 721: { ! 722: register argument_t *count; ! 723: ! 724: /* ! 725: * The user sees a single count variable. However, to get the ! 726: * count passed from user to server for variable-sized inline OUT ! 727: * arrays, we need two count arguments internally. This is ! 728: * because the count value lives in different message fields (and ! 729: * is scaled differently) in the request and reply messages. ! 730: * ! 731: * The two variables have the same name to simplify code generation. ! 732: * ! 733: * This variable has a null argParent field because it has akbRequest. ! 734: * For example, see rtCheckVariable. ! 735: */ ! 736: ! 737: count = argAlloc(); ! 738: count->argName = strconcat(arg->argName, "Cnt"); ! 739: count->argType = itMakeCountType(); ! 740: count->argParent = argNULL; ! 741: count->argNext = arg->argNext; ! 742: arg->argNext = count; ! 743: (count->argCInOut = arg->argCount)->argCInOut = count; ! 744: count->argKind = akCountInOut; ! 745: } ! 746: ! 747: static void ! 748: rtAddPolyArg(register argument_t *arg) ! 749: { ! 750: register const ipc_type_t *it = arg->argType; ! 751: register argument_t *poly; ! 752: arg_kind_t akbsend, akbreturn; ! 753: ! 754: poly = argAlloc(); ! 755: poly->argName = strconcat(arg->argName, "Poly"); ! 756: poly->argType = itMakePolyType(); ! 757: poly->argParent = arg; ! 758: poly->argNext = arg->argNext; ! 759: arg->argNext = poly; ! 760: arg->argPoly = poly; ! 761: ! 762: /* ! 763: * akbsend is bits added if the arg is In; ! 764: * akbreturn is bits added if the arg is Out. ! 765: * The mysterious business with KernelServer subsystems: ! 766: * when packing Out arguments, they use OutNames instead ! 767: * of InNames, and the OutName determines if they are poly-in ! 768: * as well as poly-out. ! 769: */ ! 770: ! 771: akbsend = akbSend|akbSendBody; ! 772: akbreturn = akbReturn|akbReturnBody; ! 773: ! 774: if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC) ! 775: { ! 776: akbsend |= akbUserArg|akbSendSnd; ! 777: if (!IsKernelServer) ! 778: akbreturn |= akbServerArg|akbReturnSnd; ! 779: } ! 780: if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC) ! 781: { ! 782: akbsend |= akbServerArg|akbSendRcv; ! 783: akbreturn |= akbUserArg|akbReturnRcv; ! 784: if (IsKernelServer) ! 785: akbreturn |= akbServerArg|akbReturnSnd; ! 786: } ! 787: ! 788: poly->argKind = akPoly; ! 789: if (akCheck(arg->argKind, akbSend)) ! 790: poly->argKind = akAddFeature(poly->argKind, ! 791: akCheck(arg->argKind, akbsend)); ! 792: if (akCheck(arg->argKind, akbReturn)) ! 793: poly->argKind = akAddFeature(poly->argKind, ! 794: akCheck(arg->argKind, akbreturn)); ! 795: ! 796: if (arg->argLongForm) ! 797: poly->argMsgField = strconcat(arg->argTTName, ! 798: ".msgtl_name"); ! 799: else ! 800: poly->argMsgField = strconcat(arg->argTTName, ".msgt_name"); ! 801: } ! 802: ! 803: static void ! 804: rtAddDeallocArg(register argument_t *arg) ! 805: { ! 806: register argument_t *dealloc; ! 807: ! 808: dealloc = argAlloc(); ! 809: dealloc->argName = strconcat(arg->argName, "Dealloc"); ! 810: dealloc->argType = itMakeDeallocType(); ! 811: dealloc->argParent = arg; ! 812: dealloc->argNext = arg->argNext; ! 813: arg->argNext = dealloc; ! 814: arg->argDealloc = dealloc; ! 815: ! 816: /* ! 817: * For Indefinite types, we leave out akbSendSnd and akbReturnSnd ! 818: * so that the normal argument-packing is bypassed. The special code ! 819: * generated for the Indefinite argument handles the deallocate bit. ! 820: * (It can only be enabled if the data is actually out-of-line.) ! 821: */ ! 822: ! 823: dealloc->argKind = akeDealloc; ! 824: if (akCheck(arg->argKind, akbSend)) ! 825: dealloc->argKind = akAddFeature(dealloc->argKind, ! 826: akCheck(arg->argKind, ! 827: akbUserArg|akbSend|akbSendBody| ! 828: (arg->argType->itIndefinite ? 0 : akbSendSnd))); ! 829: if (akCheck(arg->argKind, akbReturn)) { ! 830: dealloc->argKind = akAddFeature(dealloc->argKind, ! 831: akCheck(arg->argKind, ! 832: akbServerArg|akbReturn|akbReturnBody| ! 833: (arg->argType->itIndefinite ? 0 : akbReturnSnd))); ! 834: ! 835: /* ! 836: * Without akbReturnSnd, rtAugmentArgKind will not add ! 837: * akbVarNeeded and rtAddByReference will not set ! 838: * argByReferenceServer. So we do it here. ! 839: */ ! 840: ! 841: if (arg->argType->itIndefinite) { ! 842: dealloc->argKind = akAddFeature(dealloc->argKind, akbVarNeeded); ! 843: dealloc->argByReferenceServer = TRUE; ! 844: } ! 845: } ! 846: ! 847: if (arg->argLongForm) ! 848: dealloc->argMsgField = strconcat(arg->argTTName, ! 849: ".msgtl_header.msgt_deallocate"); ! 850: else ! 851: dealloc->argMsgField = strconcat(arg->argTTName, ".msgt_deallocate"); ! 852: ! 853: } ! 854: ! 855: static void ! 856: rtAddSCopyArg(register argument_t *arg) ! 857: { ! 858: register argument_t *scopy; ! 859: ! 860: scopy = argAlloc(); ! 861: scopy->argName = strconcat(arg->argName, "SCopy"); ! 862: scopy->argType = itMakeDeallocType(); ! 863: scopy->argParent = arg; ! 864: scopy->argNext = arg->argNext; ! 865: arg->argNext = scopy; ! 866: arg->argSCopy = scopy; ! 867: ! 868: scopy->argKind = akServerCopy; ! 869: ! 870: if (arg->argLongForm) ! 871: scopy->argMsgField = strconcat(arg->argTTName, ! 872: ".msgtl_header.msgt_inline"); ! 873: else ! 874: scopy->argMsgField = strconcat(arg->argTTName, ".msgt_inline"); ! 875: } ! 876: ! 877: static void ! 878: rtCheckRoutineArgs(routine_t *rt) ! 879: { ! 880: register argument_t *arg; ! 881: ! 882: for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) ! 883: { ! 884: register const ipc_type_t *it = arg->argType; ! 885: ! 886: rtDefaultArgKind(rt, arg); ! 887: rtCheckRoutineArg(rt, arg); ! 888: ! 889: /* need to set argTTName before adding implicit args */ ! 890: rtSetArgDefaults(rt, arg); ! 891: ! 892: /* the arg may not have a type (if there was some error in parsing it), ! 893: in which case we don't want to do these steps. */ ! 894: ! 895: if (it != itNULL) ! 896: { ! 897: /* need to set argLongForm before adding implicit args */ ! 898: rtProcessArgFlags(arg); ! 899: rtAugmentArgKind(arg); ! 900: ! 901: /* args added here will get processed in later iterations */ ! 902: /* order of args is 'arg poly countinout count dealloc scopy' */ ! 903: ! 904: if (arg->argServerCopy) ! 905: rtAddSCopyArg(arg); ! 906: if (arg->argDeallocate == d_MAYBE) ! 907: rtAddDeallocArg(arg); ! 908: if (it->itVarArray) ! 909: rtAddCountArg(arg); ! 910: if (arg->argCountInOut) ! 911: rtAddCountInOutArg(arg); ! 912: if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) || ! 913: (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) ! 914: rtAddPolyArg(arg); ! 915: } ! 916: } ! 917: } ! 918: ! 919: static void ! 920: rtCheckArgTypes(routine_t *rt) ! 921: { ! 922: if (rt->rtRequestPort == argNULL) ! 923: error("%s %s doesn't have a server port argument", ! 924: rtRoutineKindToStr(rt->rtKind), rt->rtName); ! 925: ! 926: if ((rt->rtKind == rkFunction) && ! 927: (rt->rtReturn == argNULL)) ! 928: error("Function %s doesn't have a return arg", rt->rtName); ! 929: ! 930: if ((rt->rtKind != rkFunction) && ! 931: (rt->rtReturn != argNULL)) ! 932: error("non-function %s has a return arg", rt->rtName); ! 933: ! 934: if ((rt->rtReturn == argNULL) && !rt->rtProcedure) ! 935: rt->rtReturn = rt->rtRetCode; ! 936: ! 937: rt->rtServerReturn = rt->rtReturn; ! 938: ! 939: if ((rt->rtReturn != argNULL) && ! 940: (rt->rtReturn->argType != itNULL)) ! 941: itCheckReturnType(rt->rtReturn->argName, ! 942: rt->rtReturn->argType); ! 943: ! 944: if ((rt->rtRequestPort != argNULL) && ! 945: (rt->rtRequestPort->argType != itNULL)) ! 946: itCheckRequestPortType(rt->rtRequestPort->argName, ! 947: rt->rtRequestPort->argType); ! 948: ! 949: if ((rt->rtUReplyPort != argNULL) && ! 950: (rt->rtUReplyPort->argType != itNULL)) ! 951: itCheckReplyPortType(rt->rtUReplyPort->argName, ! 952: rt->rtUReplyPort->argType); ! 953: if ((rt->rtSReplyPort != argNULL) && ! 954: (rt->rtSReplyPort->argType != itNULL)) ! 955: itCheckReplyPortType(rt->rtSReplyPort->argName, ! 956: rt->rtSReplyPort->argType); ! 957: ! 958: if ((rt->rtWaitTime != argNULL) && ! 959: (rt->rtWaitTime->argType != itNULL)) ! 960: itCheckIntType(rt->rtWaitTime->argName, ! 961: rt->rtWaitTime->argType); ! 962: ! 963: if ((rt->rtMsgOption != argNULL) && ! 964: (rt->rtMsgOption->argType != itNULL)) ! 965: itCheckIntType(rt->rtMsgOption->argName, ! 966: rt->rtMsgOption->argType); ! 967: ! 968: if ((rt->rtMsgSeqno != argNULL) && ! 969: (rt->rtMsgSeqno->argType != itNULL)) ! 970: itCheckNaturalType(rt->rtMsgSeqno->argName, ! 971: rt->rtMsgSeqno->argType); ! 972: } ! 973: ! 974: /* ! 975: * Check for arguments which are missing seemingly needed functions. ! 976: * We make this check here instead of in itCheckDecl, because here ! 977: * we can take into account what kind of argument the type is ! 978: * being used with. ! 979: * ! 980: * These are warnings, not hard errors, because mig will generate ! 981: * reasonable code in any case. The generated code will work fine ! 982: * if the ServerType and TransType are really the same, even though ! 983: * they have different names. ! 984: */ ! 985: ! 986: static void ! 987: rtCheckArgTrans(const routine_t *rt) ! 988: { ! 989: register const argument_t *arg; ! 990: ! 991: /* the arg may not have a type (if there was some error in parsing it) */ ! 992: ! 993: for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) ! 994: { ! 995: register const ipc_type_t *it = arg->argType; ! 996: ! 997: if ((it != itNULL) && ! 998: !streql(it->itServerType, it->itTransType)) ! 999: { ! 1000: if (akCheck(arg->argKind, akbSendRcv) && ! 1001: (it->itInTrans == strNULL)) ! 1002: warn("%s: argument has no in-translation function", ! 1003: arg->argName); ! 1004: ! 1005: if (akCheck(arg->argKind, akbReturnSnd) && ! 1006: (it->itOutTrans == strNULL)) ! 1007: warn("%s: argument has no out-translation function", ! 1008: arg->argName); ! 1009: } ! 1010: } ! 1011: } ! 1012: ! 1013: /* ! 1014: * Adds an implicit return-code argument. It exists in the reply message, ! 1015: * where it is the first piece of data. Even if there is no reply ! 1016: * message (rtOneWay is true), we generate the argument because ! 1017: * the server-side stub needs a dummy reply msg to return error codes ! 1018: * back to the server loop. ! 1019: */ ! 1020: ! 1021: static void ! 1022: rtAddRetCode(routine_t *rt) ! 1023: { ! 1024: register argument_t *arg = argAlloc(); ! 1025: ! 1026: arg->argName = "RetCode"; ! 1027: arg->argType = itRetCodeType; ! 1028: arg->argKind = akRetCode; ! 1029: rt->rtRetCode = arg; ! 1030: ! 1031: /* add at beginning, so return-code is first in the reply message */ ! 1032: arg->argNext = rt->rtArgs; ! 1033: rt->rtArgs = arg; ! 1034: } ! 1035: ! 1036: /* ! 1037: * Adds a dummy WaitTime argument to the function. ! 1038: * This argument doesn't show up in any C argument lists; ! 1039: * it implements the global WaitTime statement. ! 1040: */ ! 1041: ! 1042: static void ! 1043: rtAddWaitTime(routine_t *rt, identifier_t name) ! 1044: { ! 1045: register argument_t *arg = argAlloc(); ! 1046: argument_t **loc; ! 1047: ! 1048: arg->argName = "dummy WaitTime arg"; ! 1049: arg->argVarName = name; ! 1050: arg->argType = itWaitTimeType; ! 1051: arg->argKind = akeWaitTime; ! 1052: rt->rtWaitTime = arg; ! 1053: ! 1054: /* add wait-time after msg-option, if possible */ ! 1055: ! 1056: if (rt->rtMsgOption != argNULL) ! 1057: loc = &rt->rtMsgOption->argNext; ! 1058: else ! 1059: loc = &rt->rtArgs; ! 1060: ! 1061: arg->argNext = *loc; ! 1062: *loc = arg; ! 1063: ! 1064: rtSetArgDefaults(rt, arg); ! 1065: } ! 1066: ! 1067: /* ! 1068: * Adds a dummy MsgOption argument to the function. ! 1069: * This argument doesn't show up in any C argument lists; ! 1070: * it implements the global MsgOption statement. ! 1071: */ ! 1072: ! 1073: static void ! 1074: rtAddMsgOption(routine_t *rt, identifier_t name) ! 1075: { ! 1076: register argument_t *arg = argAlloc(); ! 1077: argument_t **loc; ! 1078: ! 1079: arg->argName = "dummy MsgOption arg"; ! 1080: arg->argVarName = name; ! 1081: arg->argType = itMsgOptionType; ! 1082: arg->argKind = akeMsgOption; ! 1083: rt->rtMsgOption = arg; ! 1084: ! 1085: /* add msg-option after msg-seqno */ ! 1086: ! 1087: if (rt->rtMsgSeqno != argNULL) ! 1088: loc = &rt->rtMsgSeqno->argNext; ! 1089: else ! 1090: loc = &rt->rtArgs; ! 1091: ! 1092: arg->argNext = *loc; ! 1093: *loc = arg; ! 1094: ! 1095: rtSetArgDefaults(rt, arg); ! 1096: } ! 1097: ! 1098: /* ! 1099: * Adds a dummy reply port argument to the function. If USER is true, the ! 1100: * user reply port is set, otherwise the server. ! 1101: */ ! 1102: ! 1103: static void ! 1104: rtAddDummyReplyPort(routine_t *rt, ipc_type_t *type, int user) ! 1105: { ! 1106: register argument_t *arg = argAlloc(); ! 1107: argument_t **loc; ! 1108: ! 1109: arg->argName = "dummy ReplyPort arg"; ! 1110: arg->argVarName = "dummy ReplyPort arg"; ! 1111: arg->argType = type; ! 1112: arg->argKind = akeReplyPort; ! 1113: if (user) ! 1114: rt->rtUReplyPort = arg; ! 1115: else ! 1116: rt->rtSReplyPort = arg; ! 1117: ! 1118: /* add the reply port after the request port */ ! 1119: ! 1120: if (rt->rtRequestPort != argNULL) ! 1121: loc = &rt->rtRequestPort->argNext; ! 1122: else ! 1123: loc = &rt->rtArgs; ! 1124: ! 1125: arg->argNext = *loc; ! 1126: *loc = arg; ! 1127: ! 1128: rtSetArgDefaults(rt, arg); ! 1129: } ! 1130: ! 1131: /* ! 1132: * Initializes argRequestPos, argReplyPos, rtMaxRequestPos, rtMaxReplyPos, ! 1133: * rtNumRequestVar, rtNumReplyVar, and adds akbVarNeeded to those arguments ! 1134: * that need it because of variable-sized inline considerations. ! 1135: * ! 1136: * argRequestPos and argReplyPos get -1 if the value shouldn't be used. ! 1137: */ ! 1138: static void ! 1139: rtCheckVariable(register routine_t *rt) ! 1140: { ! 1141: register argument_t *arg; ! 1142: int NumRequestVar = 0; ! 1143: int NumReplyVar = 0; ! 1144: int MaxRequestPos = 0; ! 1145: int MaxReplyPos = 0; ! 1146: ! 1147: for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { ! 1148: register argument_t *parent = arg->argParent; ! 1149: ! 1150: if (parent == argNULL) { ! 1151: if (akCheck(arg->argKind, akbRequest|akbSend)) { ! 1152: arg->argRequestPos = NumRequestVar; ! 1153: MaxRequestPos = NumRequestVar; ! 1154: if (akCheck(arg->argKind, akbVariable)) ! 1155: NumRequestVar++; ! 1156: } else ! 1157: arg->argRequestPos = -1; ! 1158: ! 1159: if (akCheck(arg->argKind, akbReply|akbReturn)) { ! 1160: arg->argReplyPos = NumReplyVar; ! 1161: MaxReplyPos = NumReplyVar; ! 1162: if (akCheck(arg->argKind, akbVariable)) ! 1163: NumReplyVar++; ! 1164: } else ! 1165: arg->argReplyPos = -1; ! 1166: } else { ! 1167: arg->argRequestPos = parent->argRequestPos; ! 1168: arg->argReplyPos = parent->argReplyPos; ! 1169: } ! 1170: ! 1171: /* Out variables that follow a variable-sized field ! 1172: need VarNeeded or ReplyCopy; they can't be stored ! 1173: directly into the reply message. */ ! 1174: ! 1175: if (akCheck(arg->argKind, akbReturnSnd) && ! 1176: !akCheck(arg->argKind, akbReplyCopy|akbVarNeeded) && ! 1177: (arg->argReplyPos > 0)) ! 1178: arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); ! 1179: } ! 1180: ! 1181: rt->rtNumRequestVar = NumRequestVar; ! 1182: rt->rtNumReplyVar = NumReplyVar; ! 1183: rt->rtMaxRequestPos = MaxRequestPos; ! 1184: rt->rtMaxReplyPos = MaxReplyPos; ! 1185: } ! 1186: ! 1187: /* ! 1188: * Adds akbDestroy where needed. ! 1189: */ ! 1190: ! 1191: static void ! 1192: rtCheckDestroy(register routine_t *rt) ! 1193: { ! 1194: register argument_t *arg; ! 1195: ! 1196: for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { ! 1197: register const ipc_type_t *it = arg->argType; ! 1198: ! 1199: if(akCheck(arg->argKind, akbSendRcv) && ! 1200: !akCheck(arg->argKind, akbReturnSnd)) { ! 1201: if ((it->itDestructor != strNULL) || ! 1202: (akCheck(arg->argKind, akbIndefinite) && !arg->argServerCopy)) ! 1203: arg->argKind = akAddFeature(arg->argKind, akbDestroy); ! 1204: } ! 1205: } ! 1206: } ! 1207: ! 1208: /* ! 1209: * Sets ByReferenceUser and ByReferenceServer. ! 1210: */ ! 1211: ! 1212: static void ! 1213: rtAddByReference(register routine_t *rt) ! 1214: { ! 1215: register argument_t *arg; ! 1216: ! 1217: for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { ! 1218: register const ipc_type_t *it = arg->argType; ! 1219: ! 1220: if (akCheck(arg->argKind, akbReturnRcv) && ! 1221: (it->itStruct || it->itIndefinite)) { ! 1222: arg->argByReferenceUser = TRUE; ! 1223: ! 1224: /* ! 1225: * A CountInOut arg itself is not akbReturnRcv, ! 1226: * so we need to set argByReferenceUser specially. ! 1227: */ ! 1228: ! 1229: if (arg->argCInOut != argNULL) ! 1230: arg->argCInOut->argByReferenceUser = TRUE; ! 1231: } ! 1232: ! 1233: if (akCheck(arg->argKind, akbReturnSnd) && ! 1234: (it->itStruct || it->itIndefinite)) ! 1235: arg->argByReferenceServer = TRUE; ! 1236: } ! 1237: } ! 1238: ! 1239: void ! 1240: rtCheckRoutine(register routine_t *rt) ! 1241: { ! 1242: /* Initialize random fields. */ ! 1243: ! 1244: rt->rtErrorName = ErrorProc; ! 1245: rt->rtOneWay = ((rt->rtKind == rkSimpleProcedure) || ! 1246: (rt->rtKind == rkSimpleRoutine)); ! 1247: rt->rtProcedure = ((rt->rtKind == rkProcedure) || ! 1248: (rt->rtKind == rkSimpleProcedure)); ! 1249: rt->rtUseError = rt->rtProcedure || (rt->rtKind == rkFunction); ! 1250: rt->rtServerName = strconcat(ServerPrefix, rt->rtName); ! 1251: rt->rtServerName = strconcat(RoutinePrefix, rt->rtServerName); ! 1252: rt->rtUserName = strconcat(UserPrefix, rt->rtName); ! 1253: rt->rtUserName = strconcat(RoutinePrefix, rt->rtUserName); ! 1254: ! 1255: /* Add implicit arguments. */ ! 1256: ! 1257: rtAddRetCode(rt); ! 1258: ! 1259: /* Check out the arguments and their types. Add count, poly ! 1260: implicit args. Any arguments added after rtCheckRoutineArgs ! 1261: should have rtSetArgDefaults called on them. */ ! 1262: ! 1263: rtCheckRoutineArgs(rt); ! 1264: ! 1265: /* Add dummy WaitTime and MsgOption arguments, if the routine ! 1266: doesn't have its own args and the user specified global values. */ ! 1267: ! 1268: if (rt->rtUReplyPort == argNULL) ! 1269: if (rt->rtOneWay) ! 1270: rtAddDummyReplyPort(rt, itZeroReplyPortType, 1); ! 1271: else ! 1272: rtAddDummyReplyPort(rt, itRealReplyPortType, 1); ! 1273: if (rt->rtSReplyPort == argNULL) ! 1274: if (rt->rtOneWay) ! 1275: rtAddDummyReplyPort(rt, itZeroReplyPortType, 0); ! 1276: else ! 1277: rtAddDummyReplyPort(rt, itRealReplyPortType, 0); ! 1278: ! 1279: if (rt->rtMsgOption == argNULL) ! 1280: if (MsgOption == strNULL) ! 1281: rtAddMsgOption(rt, "MACH_MSG_OPTION_NONE"); ! 1282: else ! 1283: rtAddMsgOption(rt, MsgOption); ! 1284: ! 1285: if ((rt->rtWaitTime == argNULL) && ! 1286: (WaitTime != strNULL)) ! 1287: rtAddWaitTime(rt, WaitTime); ! 1288: ! 1289: /* Now that all the arguments are in place, do more checking. */ ! 1290: ! 1291: rtCheckArgTypes(rt); ! 1292: rtCheckArgTrans(rt); ! 1293: ! 1294: if (rt->rtOneWay && rtCheckMask(rt->rtArgs, akbReturn)) ! 1295: error("%s %s has OUT argument", ! 1296: rtRoutineKindToStr(rt->rtKind), rt->rtName); ! 1297: ! 1298: /* If there were any errors, don't bother calculating more info ! 1299: that is only used in code generation anyway. Therefore, ! 1300: the following functions don't have to worry about null types. */ ! 1301: ! 1302: if (errors > 0) ! 1303: return; ! 1304: ! 1305: rtCheckSimpleIn(rt->rtArgs, akbRequest, ! 1306: &rt->rtSimpleFixedRequest, ! 1307: &rt->rtSimpleSendRequest); ! 1308: rtCheckSimpleOut(rt->rtArgs, akbRequest, ! 1309: &rt->rtSimpleCheckRequest, ! 1310: &rt->rtSimpleReceiveRequest); ! 1311: rt->rtRequestSize = rtFindSize(rt->rtArgs, akbRequest); ! 1312: ! 1313: if (IsKernelServer) ! 1314: rtCheckSimpleOut(rt->rtArgs, akbReply, ! 1315: &rt->rtSimpleFixedReply, ! 1316: &rt->rtSimpleSendReply); ! 1317: else ! 1318: rtCheckSimpleIn(rt->rtArgs, akbReply, ! 1319: &rt->rtSimpleFixedReply, ! 1320: &rt->rtSimpleSendReply); ! 1321: rtCheckSimpleOut(rt->rtArgs, akbReply, ! 1322: &rt->rtSimpleCheckReply, ! 1323: &rt->rtSimpleReceiveReply); ! 1324: rt->rtReplySize = rtFindSize(rt->rtArgs, akbReply); ! 1325: ! 1326: rtCheckVariable(rt); ! 1327: rtCheckDestroy(rt); ! 1328: rtAddByReference(rt); ! 1329: ! 1330: if (rt->rtKind == rkFunction) ! 1331: rt->rtNoReplyArgs = FALSE; ! 1332: else ! 1333: rt->rtNoReplyArgs = !rtCheckMask(rt->rtArgs, akbReturnSnd); ! 1334: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.