-- Copyright (C) 1982, 1984, 1985 by Xerox Corporation. All rights reserved. -- LupineRuntimeImpl.mesa, HGM, 18-Jan-85 17:45:03 -- Last edited by BZM on 12-May-82 19:17:55. -- This module is used at runtime for marshaling and other common functions. DIRECTORY Heap USING [systemZone, systemMDSZone], Inline USING [DIVMOD, LongCOPY], LupineRuntime USING [CheckPktLength, Words], MesaRPCLupine USING [ DataLength, maxDataLength, ReceiveExtraPkt, RejectUnbound, RPCPkt, SendPrelimPkt], MesaRPC USING [CallFailed, Zones]; LupineRuntimeImpl: PROGRAM IMPORTS Heap, Inline, Lupine: LupineRuntime, RpcPrivate: MesaRPCLupine, RpcPublic: MesaRPC EXPORTS LupineRuntime = BEGIN Words: TYPE = LupineRuntime.Words; -- Lupine's errors. TranslationError: PUBLIC ERROR = CODE; BindingError: PUBLIC ERROR = CODE; RuntimeError: PUBLIC ERROR = CODE; -- These procedures map into ERRORs (for now). MarshalingError: PUBLIC PROCEDURE = {ERROR}; MarshalingExprError: PUBLIC PROCEDURE RETURNS [never: UNSPECIFIED] = { RETURN[ERROR]}; -- These procedures map into RpcRuntime ERRORs. UnmarshalingError: PUBLIC PROCEDURE = { ERROR RpcPublic.CallFailed[why: stubProtocol]}; UnmarshalingExprError: PUBLIC PROCEDURE RETURNS [never: UNSPECIFIED] = { ERROR RpcPublic.CallFailed[why: stubProtocol]}; DispatchingError: PUBLIC PROCEDURE RETURNS [never: UNSPECIFIED] = { ERROR RpcPrivate.RejectUnbound}; defaultZones: PUBLIC MesaRPC.Zones ← [ gc: NIL, heap: Heap.systemZone, mds: Heap.systemMDSZone]; -- Parameter marshaling routines. Checking: BOOLEAN = TRUE; -- Turning this off is okay; critical runtime checks are always on. FinishThisPkt: PUBLIC PROCEDURE [ pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength] RETURNS [ --zeroPktLength:-- RpcPrivate.DataLength] = BEGIN Lupine.CheckPktLength[pkt: pkt, lastPkt: FALSE, pktLength: pktLength]; [] ← RpcPrivate.ReceiveExtraPkt[prevPkt: pkt]; RETURN[0]; END; StartNextPkt: PUBLIC PROCEDURE [ pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength] RETURNS [ --zeroPktLength:-- RpcPrivate.DataLength] = BEGIN RpcPrivate.SendPrelimPkt[pkt: pkt, length: pktLength]; RETURN[0]; END; CopyToMultiplePkts: PUBLIC PROCEDURE [ pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength, dataAdr: LONG POINTER, dataLength: Words] RETURNS [ --newPktLength:-- RpcPrivate.DataLength] = BEGIN initialWords: Words = RpcPrivate.maxDataLength - pktLength; wholePkts: CARDINAL ← NULL; finalWords: Words ← NULL; IF Checking AND NOT ( -- Preconditions: pktLength IN [0..RpcPrivate.maxDataLength] AND dataLength > 0 AND pktLength + dataLength > RpcPrivate.maxDataLength) THEN ERROR; [quotient: wholePkts, remainder: finalWords] ← Inline.DIVMOD[ num: dataLength - initialWords, ---- ---- ---- ---- ---- ---- den: RpcPrivate.maxDataLength]; -- Put initial data at the end of the current pkt. Inline.LongCOPY[ from: dataAdr, to: @pkt.data[pktLength], nwords: initialWords]; dataAdr ← dataAdr + initialWords; -- Put intermediate data into whole pkts. THROUGH [0..wholePkts) DO RpcPrivate.SendPrelimPkt[pkt: pkt, length: RpcPrivate.maxDataLength]; Inline.LongCOPY[ from: dataAdr, to: @pkt.data[0], nwords: RpcPrivate.maxDataLength]; dataAdr ← dataAdr + RpcPrivate.maxDataLength; ENDLOOP; -- Put final data at the beginning of a fresh pkt. IF finalWords > 0 THEN BEGIN RpcPrivate.SendPrelimPkt[pkt: pkt, length: RpcPrivate.maxDataLength]; Inline.LongCOPY[from: dataAdr, to: @pkt.data[0], nwords: finalWords]; RETURN[finalWords]; END ELSE RETURN[RpcPrivate.maxDataLength]; END; CopyFromMultiplePkts: PUBLIC PROCEDURE [ pkt: RpcPrivate.RPCPkt, pktLength: RpcPrivate.DataLength, dataAdr: LONG POINTER, dataLength: Words] RETURNS [ --newPktLength:-- RpcPrivate.DataLength] = BEGIN firstDataAdr: LONG POINTER = dataAdr; BEGIN ENABLE UNWIND => -- If there's a fault, zero everything. This ensures that any -- REF-containing fields are NIL and not chaos-causing garbage. IF dataLength > 0 THEN BEGIN firstDataAdr↑ ← 0; Inline.LongCOPY[ from: firstDataAdr, to: firstDataAdr + 1, nwords: dataLength - 1]; END; initialWords: Words = RpcPrivate.maxDataLength - pktLength; wholePkts: CARDINAL ← NULL; finalWords: Words ← NULL; IF Checking AND NOT ( -- Preconditions: pktLength IN [0..RpcPrivate.maxDataLength] AND dataLength > 0 AND pktLength + dataLength > RpcPrivate.maxDataLength) THEN ERROR; [quotient: wholePkts, remainder: finalWords] ← Inline.DIVMOD[ num: dataLength - initialWords, ---- ---- ---- ---- ---- ---- den: RpcPrivate.maxDataLength]; -- Get initial data from the end of the current pkt. Inline.LongCOPY[ to: dataAdr, from: @pkt.data[pktLength], nwords: initialWords]; dataAdr ← dataAdr + initialWords; -- Get intermediate data from whole pkts. THROUGH [0..wholePkts) DO Lupine.CheckPktLength[ pkt: pkt, lastPkt: FALSE, pktLength: RpcPrivate.maxDataLength]; [] ← RpcPrivate.ReceiveExtraPkt[prevPkt: pkt]; Inline.LongCOPY[ to: dataAdr, from: @pkt.data[0], nwords: RpcPrivate.maxDataLength]; dataAdr ← dataAdr + RpcPrivate.maxDataLength; ENDLOOP; -- Get final data from the beginning of a fresh pkt. IF finalWords > 0 THEN BEGIN Lupine.CheckPktLength[ pkt: pkt, lastPkt: FALSE, pktLength: RpcPrivate.maxDataLength]; [] ← RpcPrivate.ReceiveExtraPkt[prevPkt: pkt]; Inline.LongCOPY[to: dataAdr, from: @pkt.data[0], nwords: finalWords]; RETURN[finalWords]; END ELSE RETURN[RpcPrivate.maxDataLength]; END; -- ENABLE UNWIND. END; -- Module initialization. -- CopyTo/FromMultiplePkts assume that zero is the representation of NIL. IF NIL # LOOPHOLE[0, POINTER] THEN ERROR; END. -- LupineRuntimeImpl.