-- Copyright (C) 1981, 1984 by Xerox Corporation. All rights reserved.
-- File: SequinImplA.mesa
-- HGM: 10-Dec-84 21:23:47
-- last edited by Hankins: 24-Jul-84 11:01:29 Klamath update (Pup changes)
-- Last edited by Levin: 6-Jul-81 16:17:08
-- Loosely derived (after extensive discussions with Wobber)
-- from Butterfield's Sequin.mesa of August 27, 1979 2:49 PM.
DIRECTORY
Buffer USING [
AccessHandle, Buffer, GetBuffer, MakePool, QueueCleanup, QueueInitialize],
Process USING [Detach],
PupDefs USING [
DataWordsPerPupBuffer, GetHopsToNetwork, MsToTocks, PupAddress, PupBuffer,
PupSocketDestroy, PupSocketMake, SetPupContentsBytes, Tocks,
UniqueLocalPupSocketID],
PupTypes USING [maxDataWordsPerGatewayPup, PupType],
Sequin USING [Broken],
SequinPrivate USING [Handle, Send, SequinObject, SocketWarmer],
Storage USING [Node, Free];
SequinImplA: MONITOR LOCKS sequin.LOCK USING sequin: SequinPrivate.Handle
IMPORTS Buffer, Process, PupDefs, Sequin, SequinPrivate, Storage
EXPORTS Sequin, SequinPrivate =
BEGIN
-- Types --
Handle: PUBLIC TYPE = SequinPrivate.Handle;
-- Variables exported to SequinPrivate --
maxBytes: PUBLIC CARDINAL;
maxAllocate: PUBLIC CARDINAL;
bufferPool: PUBLIC Buffer.AccessHandle;
-- 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: PupDefs.PupAddress, pupType: PupTypes.PupType]
RETURNS [sequin: Handle] =
BEGIN
GetTicks: PROCEDURE RETURNS [PupDefs.Tocks] =
BEGIN
hops: CARDINAL ← PupDefs.GetHopsToNetwork[dest.net];
IF hops = LAST[CARDINAL] THEN hops ← 0; -- no route
RETURN[[PupDefs.MsToTocks[hops * 750 + 500]]]
END;
sequin ← MDS.NEW[SequinPrivate.SequinObject ← [pupType: pupType]];
Buffer.QueueInitialize[@sequin.retransmitQueue];
Buffer.QueueInitialize[@sequin.getQueue];
sequin.socket ← PupDefs.PupSocketMake[
PupDefs.UniqueLocalPupSocketID[], dest, GetTicks[]];
sequin.id.allocate ← maxAllocate;
Process.Detach[FORK SequinPrivate.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: PupDefs.PupBuffer ← Buffer.GetBuffer[
type: pup, aH: bufferPool, function: send];
PupDefs.SetPupContentsBytes[buffer, 0];
SequinPrivate.Send[sequin, buffer, destroy ! Sequin.Broken => CONTINUE];
WaitUntilAllQuiet[sequin];
Buffer.QueueCleanup[@sequin.retransmitQueue];
Buffer.QueueCleanup[@sequin.getQueue];
PupDefs.PupSocketDestroy[sequin.socket];
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(2): 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[
PupDefs.DataWordsPerPupBuffer[], PupTypes.maxDataWordsPerGatewayPup];
-- 10 = leaf overhead/packet; +1 roundup; +1 for parallelism
maxAllocate ← 511 / (maxBytes - 10) + 1 + 1;
bufferPool ← Buffer.MakePool[send: 25, receive: 0];
END;
-- Main body --
Initialize[];
END.