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