-- File: QueuePup.mesa - last edit:
-- MAS May 19, 1980 6:23 PM
-- HGM October 15, 1979 7: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, freeQueue, firstBuffer, freeQueueNotEmpty],
PupDefs: FROM "PupDefs" USING [DequeuePup, EnqueuePup],
BufferDefs: FROM "BufferDefs" USING [
Buffer, PupBuffer, RppBuffer,
Queue, buffersToReserve],
DriverTypes: FROM "DriverTypes" USING [bufferSeal, queueSeal];

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

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

ExtractPupFromQueue: PUBLIC PROCEDURE [Queue, PupBuffer] RETURNS [PupBuffer] = LOOPHOLE[ExtractFromQueue];
ExtractRppFromQueue: PUBLIC PROCEDURE [Queue, RppBuffer] RETURNS [RppBuffer] = LOOPHOLE[ExtractFromQueue];
ExtractFromQueue: PUBLIC PROCEDURE [q: Queue, b: Buffer] RETURNS [Buffer] =
BEGIN
previousB, currentB: Buffer;
IF q=NIL THEN Glitch[QueueScrambled];
IF doDebug AND q.seal#DriverTypes.queueSeal THEN Glitch[QueueSealBroken];
IF doDebug AND b.seal#DriverTypes.bufferSeal THEN Glitch[BufferSealBroken];
previousB ← NIL;
currentB ← q.first;
UNTIL currentB=b
DO
IF currentB=NIL THEN EXIT;
previousB ← currentB;
currentB ← currentB.next;
ENDLOOP;
IF currentB#NIL THEN
BEGIN
-- remove this buffer from the queue
IF doDebug AND currentB.seal#DriverTypes.bufferSeal THEN Glitch[BufferSealBroken];
IF currentB=q.first THEN q.first ← currentB.next;
IF currentB=q.last THEN q.last ← previousB;
IF previousB#NIL THEN previousB.next ← currentB.next;
q.length ← q.length-1;
currentB.queue ← NIL;
currentB.next ← NIL;
IF doStats THEN StatsDefs.StatIncr[statXqueue];
END
ELSE IF doStats THEN StatsDefs.StatIncr[statXqueueNIL];
RETURN[currentB];
END;

GetClumpOfPupBuffers: PUBLIC ENTRY PROCEDURE [
q: Queue, n: CARDINAL, wait: BOOLEAN] =
BEGIN ENABLE UNWIND => NULL;
b: PupBuffer;
IF doDebug AND firstBuffer=NIL THEN Glitch[FreeQueueNotInitialized];
IF doDebug AND q.seal#DriverTypes.queueSeal THEN Glitch[QueueSealBroken];
UNTIL freeQueue.length>n+buffersToReserve DO
IF ~wait THEN RETURN;
WAIT freeQueueNotEmpty;
ENDLOOP;
THROUGH [0..n) DO
b ← PupDefs.DequeuePup[@freeQueue];
IF doDebug OR doSee THEN b.type ← pup;
b.pupType ← data;
IF doDebug THEN b.debug ← CommUtilDefs.GetReturnFrame[].accesslink;
PupDefs.EnqueuePup[q,b];
ENDLOOP;
END;

-- initialization
END. -- QueuePup