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