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