SequinImplA.mesa
Loosely derived (after extensive discussions with Wobber) from Butterfield's Sequin.mesa of August 27, 1979 2:49 PM.
Levin: 3-Feb-82 9:29:58
Russ Atkinson, November 10, 1983 12:12 pm
DIRECTORY
BufferDefs USING [Buffer, PupBufferObject, QueueCleanup, QueueInitialize, QueueObject],
PrincOpsUtils USING [Free],
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 [
MakeRequeueClosure, Send, SequenceNumber, SequinID, SequinRep, SocketWarmer];
SequinImplA: MONITOR LOCKS sequin.LOCK USING sequin: Handle
IMPORTS BufferDefs, PrincOpsUtils, Process, PupDefs, Sequin, SequinPrivate
EXPORTS Sequin, SequinPrivate =
BEGIN OPEN PupDefs, SequinPrivate;
Types --
Handle: TYPE = REF SequinRep;
SequinRep: PUBLIC TYPE = SequinPrivate.SequinRep;
Variables exported to SequinPrivate --
maxBytes: PUBLIC CARDINAL;
maxAllocate: PUBLIC CARDINAL;
Global Variables --
nSequins: CARDINAL ← 0;
Miscellaneous Declarations --
SequinsInUse: ERROR = CODE;
Procedures exported to Sequin --
Create: PUBLIC PROC
[dest: PupAddress, pupType: PupTypes.PupType] RETURNS [sequin: Handle] = {
GetTicks: PROC RETURNS [Tocks] =
BEGIN
hops: CARDINAL ← GetHopsToNetwork[dest.net];
IF hops = LAST[CARDINAL] THEN hops ← 0; -- no route
RETURN [[MsToTocks[hops * 750 + 500]]]
END;
sequin ← NEW[SequinRep ← [pupType: pupType]];
BufferDefs.QueueInitialize[sequin.retransmitQueue ← NEW[BufferDefs.QueueObject]];
BufferDefs.QueueInitialize[sequin.getQueue ← NEW[BufferDefs.QueueObject]];
sequin.socket ← PupSocketMake[UniqueLocalPupSocketID[], dest, GetTicks[]];
sequin.id.allocate ← maxAllocate;
sequin.closure ← MakeRequeueClosure[sequin];
sequin.opened ← TRUE;
Process.Detach[FORK SocketWarmer[sequin]];
nSequins ← nSequins + 1;
};
WasOpened: ENTRY PROC [sequin: Handle] RETURNS [wasOpened: BOOL] = {
IF sequin = NIL THEN RETURN [FALSE];
IF wasOpened ← sequin.opened THEN sequin.opened ← FALSE;
};
WaitUntilAllQuiet: ENTRY PROC [sequin: Handle] = {
UNTIL sequin.state = destroyed DO WAIT sequin.goAhead ENDLOOP;
UNTIL sequin.buffersToRequeue = 0 DO WAIT sequin.goAhead ENDLOOP;
};
Destroy: PUBLIC PROC [sequin: Handle] = {
IF WasOpened[sequin] THEN {
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];
PrincOpsUtils.Free[sequin.closure];
nSequins ← nSequins - 1;
};
};
Initialization --
Initialize: PROC = {
maxBytes ← 2*MIN[DataWordsPerPupBuffer[], PupTypes.maxDataWordsPerGatewayPup];
10 = leaf overhead/packet; +1 roundup; +1 for parallelism
maxAllocate ← 511/(maxBytes-10) + 1 + 1;
};
Main body --
Initialize[];
END.