File [Ivy]<Nelson>Lupine>LupineRuntimeImpl.mesa.
Last edited by BZM on 12-May-82 19:17:55.
This module is used at runtime for marshaling and other common functions.
Last Edited by: Birrell, September 12, 1983 2:07 pm
DIRECTORY
Basics USING [DIVMOD],
LupineRuntime USING [CheckPktLength, Words],
PrincOpsUtils USING [LongCOPY],
RPCLupine USING [DataLength, maxDataLength, ReceiveExtraPkt, RejectUnbound, RPCPkt, SendPrelimPkt ],
RPC USING [CallFailed, Zones],
SafeStorage USING [GetSystemZone],
UnsafeStorage USING [GetSystemUZone];
LupineRuntimeImpl: PROGRAM
IMPORTS Basics, Lupine: LupineRuntime, PrincOpsUtils, RpcPrivate: RPCLupine, RpcPublic: RPC, SafeStorage, UnsafeStorage
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};
Default parameter storage zones.
defaultZones: PUBLIC RPC.Zones ← [
gc: SafeStorage.GetSystemZone[],
heap: UnsafeStorage.GetSystemUZone[],
mds: NIL--??--
];
Parameter marshaling routines.
Checking: BOOLEANTRUE;
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: CARDINALNULL;
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] ← Basics.DIVMOD[
num: dataLength-initialWords,
------------------------
den: RpcPrivate.maxDataLength ];
Put initial data at the end of the current pkt.
PrincOpsUtils.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];
PrincOpsUtils.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];
PrincOpsUtils.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;
PrincOpsUtils.LongCOPY[
from: firstDataAdr, to: firstDataAdr+1, nwords: dataLength-1 ];
END;
initialWords: Words = RpcPrivate.maxDataLength - pktLength;
wholePkts: CARDINALNULL;
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] ← Basics.DIVMOD[
num: dataLength-initialWords,
------------------------
den: RpcPrivate.maxDataLength ];
Get initial data from the end of the current pkt.
PrincOpsUtils.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];
PrincOpsUtils.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];
PrincOpsUtils.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.