-- File: QueueOut.mesa - last edit:
-- MAS May 19, 1980 6:22 PM
-- HGM July 15, 1979 4:53 PM

-- Copyright Xerox Corporation 1979, 1980

DIRECTORY
StatsDefs: FROM "StatsDefs" USING [StatIncr],
CommUtilDefs: FROM "CommUtilDefs" USING [GetReturnFrame],
DriverDefs: FROM "DriverDefs" USING [
doDebug, doSee, doStats, Glitch,
freeQueueLock, firstBuffer, freeQueue, freeQueueNotEmpty],
PupDefs: FROM "PupDefs", -- EXPORTs
BufferDefs: FROM "BufferDefs" USING [Buffer, PupBuffer, Dequeue, buffersToReserve];

QueueOut: MONITOR LOCKS DriverDefs.freeQueueLock
IMPORTS StatsDefs, CommUtilDefs, DriverDefs, BufferDefs
EXPORTS DriverDefs, PupDefs, BufferDefs
SHARES BufferDefs =
BEGIN OPEN DriverDefs, BufferDefs;

FreeQueueNotInitialized: PUBLIC ERROR = CODE;
QueueScrambled: PUBLIC ERROR = CODE;

GetFreePupBuffer: PUBLIC PROCEDURE RETURNS [b: PupBuffer] =
BEGIN
b ← LOOPHOLE[GetFreeBuffer[]];
IF doDebug OR doSee THEN b.type ← pup;
b.pupType ← data;
IF doDebug THEN b.debug ← CommUtilDefs.GetReturnFrame[].accesslink;
END;

GetFreeBuffer: PUBLIC ENTRY PROCEDURE RETURNS [b: Buffer] =
BEGIN ENABLE UNWIND => NULL;
IF doDebug AND firstBuffer=NIL THEN Glitch[FreeQueueNotInitialized];
IF doStats AND ~freeQueue.length>buffersToReserve THEN
StatsDefs.StatIncr[statBufferWaits];
UNTIL freeQueue.length>buffersToReserve DO WAIT freeQueueNotEmpty; ENDLOOP;
b←Dequeue[@freeQueue];
IF doDebug AND b=NIL THEN Glitch[QueueScrambled];
IF doDebug OR doSee THEN b.type ← raw;
IF doDebug THEN b.debug ← CommUtilDefs.GetReturnFrame[].accesslink;
END;

-- Get free buffer, but don’t wait if there is none
-- NB: These will return the last buffer, use with caution

MaybeGetFreePupBuffer: PUBLIC PROCEDURE RETURNS [ b: PupBuffer ] =
BEGIN
b ← LOOPHOLE[MaybeGetFreeBuffer[]];
IF b#NIL THEN
BEGIN
IF doDebug OR doSee THEN b.type ← pup;
b.pupType ← data;
END;
END;


MaybeGetFreeBuffer: PUBLIC ENTRY PROCEDURE RETURNS [ b: Buffer ] =
BEGIN
IF doDebug AND firstBuffer=NIL THEN Glitch[FreeQueueNotInitialized];
IF doStats AND freeQueue.length=0 THEN StatsDefs.StatIncr[statBufferWaits];
b ← Dequeue[@freeQueue];
IF b#NIL THEN
BEGIN
IF doDebug OR doSee THEN b.type ← raw;
IF doDebug THEN b.debug ← CommUtilDefs.GetReturnFrame[].accesslink;
END;
END;

-- initialization
END. -- QueueOut