|
|
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.