-- File: SequinImplA.mesa -- Last edited by Levin: 3-Feb-82 9:29:58 -- 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], Frame USING [Free], Heap USING [systemZone], Process 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]; SequinImplA: MONITOR LOCKS sequin.LOCK USING sequin: SequinPrivate.Handle IMPORTS BufferDefs, Frame, Heap, Process, PupDefs, Sequin, SequinPrivate 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 -- zone: UNCOUNTED ZONE ← Heap.systemZone; nSequins: CARDINAL ← 0; -- Miscellaneous Declarations -- SequinsInUse: ERROR = CODE; -- Procedures exported to Sequin -- SetZone: PUBLIC PROCEDURE [z: UNCOUNTED ZONE] RETURNS [old: UNCOUNTED ZONE] = BEGIN IF nSequins ~= 0 THEN ERROR SequinsInUse; old ← zone; zone ← 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 ← zone.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]; Process.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]; Frame.Free[sequin.closure]; zone.FREE[@sequin]; nSequins ← nSequins - 1; END; -- 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.