-- File: SequinImplA.mesa
-- Last edited by Levin: 6-Jul-81 15:26:16
-- Loosely derived (after extensive discussions with Wobber) from Butterfield's
-- Sequin.mesa of August 27, 1979 2:49 PM.
DIRECTORY
BufferDefs USING [Buffer, PupBufferObject, QueueCleanup, QueueInitialize],
FrameOps USING [Free],
ProcessDefs USING [Detach],
PupDefs USING [
DataWordsPerPupBuffer, GetFreePupBuffer, GetHopsToNetwork,
MsToTocks, PupAddress, PupBuffer, PupSocketDestroy,
PupSocketMake, SetPupContentsBytes, Tocks,
UniqueLocalPupSocketID],
PupTypes USING [maxDataWordsPerGatewayPup, PupType],
Sequin USING [Broken],
SequinPrivate USING [
Handle, MakeRequeueClosure, Seconds, Send, SequenceNumber, SequinID,
SequinObject, SocketWarmer],
Storage USING [Node, Free];
SequinImplA: MONITOR LOCKS sequin.LOCK USING sequin: SequinPrivate.Handle
IMPORTS BufferDefs, FrameOps, ProcessDefs, PupDefs, Sequin, SequinPrivate, Storage
EXPORTS Sequin, SequinPrivate =
BEGIN OPEN PupDefs, SequinPrivate;
-- Types --
Handle: PUBLIC TYPE = SequinPrivate.Handle;
-- Variables exported to SequinPrivate --
maxBytes: PUBLIC CARDINAL;
maxAllocate: PUBLIC CARDINAL;
-- Global Variables --
MDS: MDSZone ← LOOPHOLE[@mdsZone];
nSequins: CARDINAL ← 0;
-- Miscellaneous Declarations --
SequinsInUse: ERROR = CODE;
-- Procedures exported to Sequin --
SetZone: PUBLIC PROCEDURE [z: MDSZone] RETURNS [old: MDSZone] =
BEGIN
IF nSequins ~= 0 THEN ERROR SequinsInUse;
old ← MDS;
MDS ← z;
END;
Create: PUBLIC PROCEDURE [dest: PupAddress, pupType: PupTypes.PupType]
RETURNS [sequin: Handle] =
BEGIN
GetTicks: PROCEDURE RETURNS [Tocks] =
BEGIN
hops: CARDINAL ← GetHopsToNetwork[dest.net];
IF hops = LAST[CARDINAL] THEN hops ← 0; -- no route
RETURN [[MsToTocks[hops * 750 + 500]]]
END;
sequin ← MDS.NEW[SequinObject ← [pupType: pupType]];
BufferDefs.QueueInitialize[@sequin.retransmitQueue];
BufferDefs.QueueInitialize[@sequin.getQueue];
sequin.socket ← PupSocketMake[UniqueLocalPupSocketID[], dest, GetTicks[]];
sequin.id.allocate ← maxAllocate;
sequin.closure ← MakeRequeueClosure[sequin];
ProcessDefs.Detach[FORK SocketWarmer[sequin]];
nSequins ← nSequins + 1;
END;
Destroy: PUBLIC PROCEDURE [sequin: Handle] =
BEGIN
WaitUntilAllQuiet: ENTRY PROCEDURE [sequin: Handle] = INLINE
BEGIN
UNTIL sequin.state = destroyed DO WAIT sequin.goAhead ENDLOOP;
UNTIL sequin.buffersToRequeue = 0 DO WAIT sequin.goAhead ENDLOOP;
END;
buffer: PupBuffer ← GetFreePupBuffer[];
SetPupContentsBytes[buffer, 0];
Send[sequin, buffer, destroy ! Sequin.Broken => CONTINUE];
WaitUntilAllQuiet[sequin];
BufferDefs.QueueCleanup[@sequin.retransmitQueue];
BufferDefs.QueueCleanup[@sequin.getQueue];
PupSocketDestroy[sequin.socket];
FrameOps.Free[sequin.closure];
MDS.FREE[@sequin];
nSequins ← nSequins - 1;
END;
-- Papier mache MDSZone over Storage interface --
MDSZoneHandle: TYPE = POINTER TO MDSZoneObject;
MDSZoneObject: TYPE = MACHINE DEPENDENT RECORD [
procs (0:0..15): POINTER TO AllocProcs];
AllocProcs: TYPE = MACHINE DEPENDENT RECORD [
alloc (0): PROCEDURE [zone: MDSZoneHandle, size: CARDINAL] RETURNS [POINTER],
dealloc (1): PROCEDURE [zone: MDSZoneHandle, object: POINTER]];
mdsZone: MDSZoneObject ← [procs: @allocProcs];
allocProcs: AllocProcs ← [alloc: Alloc, dealloc: DeAlloc];
Alloc: PROCEDURE [zone: MDSZoneHandle, size: CARDINAL] RETURNS [POINTER] =
{RETURN[Storage.Node[size]]};
DeAlloc: PROCEDURE [zone: MDSZoneHandle, object: POINTER] =
{Storage.Free[object]};
-- Initialization --
Initialize: PROCEDURE =
BEGIN
maxBytes ← 2*MIN[DataWordsPerPupBuffer[], PupTypes.maxDataWordsPerGatewayPup];
-- 10 = leaf overhead/packet; +1 roundup; +1 for parallelism
maxAllocate ← 511/(maxBytes-10) + 1 + 1;
END;
-- Main body --
Initialize[];
END.