-- RTQueueImpl.Mesa FOR USE BY THE COLLECTOR
-- last edited June 16, 1983 9:15 pm by Paul Rovner

DIRECTORY RTQueue;

RTQueueImpl: MONITOR -- protects q's
LOCKS LOOPHOLE[q, RealQ] USING q: Q
EXPORTS RTQueue
= BEGIN
OPEN RTQueue;

RealQ: TYPE = REF QRec;
QRec: TYPE = MONITORED RECORD
   [ nRefs: CARDINAL,
    nextIndex: CARDINAL ← 0,
    nonEmpty: CONDITION,
    refs: SEQUENCE count: CARDINAL OF REF ANY];

-- Exported procedures (public)

New: PUBLIC PROC[nRefs: CARDINAL ← 10] RETURNS[Q] =
{RETURN[[NEW[QRec[nRefs] ← [nRefs: nRefs, LOCK:, nonEmpty:, refs: NULL]]]]};

-- called only by the collector
Enqueue: PUBLIC ENTRY PROC[ref: REF ANY, q: Q] RETURNS[full: BOOLEAN]=
{ ENABLE UNWIND => NULL;
rq: RealQ = LOOPHOLE[q];
IF rq.nRefs = rq.nextIndex THEN RETURN[TRUE];
-- THE BELOW IS NOT A REFERENCE COUNTED ASSIGNMENT
LOOPHOLE[rq.refs[rq.nextIndex], LONG POINTER] ← LOOPHOLE[ref, LONG POINTER];
rq.nextIndex ← rq.nextIndex + 1;
NOTIFY rq.nonEmpty;
RETURN[FALSE]};

dummy: REF ANYNIL;
Dequeue: PUBLIC PROC[q: Q] RETURNS[ref: REF ANY] = {
ref ← DoDequeue[q];
-- now decrement ref's reference count
LOOPHOLE[dummy, LONG POINTER] ← LOOPHOLE[ref, LONG POINTER];
dummy ← NIL;
};

DoDequeue: ENTRY PROC[q: Q] RETURNS[ref: REF ANY] =
{ ENABLE UNWIND => NULL;
rq: RealQ = LOOPHOLE[q];
WHILE QEmpty[rq] DO WAIT rq.nonEmpty; ENDLOOP;
rq.nextIndex ← rq.nextIndex - 1;
ref ← rq.refs[rq.nextIndex];
-- THE BELOW IS NOT A REFERENCE COUNTED ASSIGNMENT
LOOPHOLE[rq.refs[rq.nextIndex], LONG POINTER] ← NIL};

Empty: PUBLIC ENTRY PROC[q: Q] RETURNS[BOOLEAN] =
{ RETURN[QEmpty[LOOPHOLE[q]]]};

QEmpty: INTERNAL PROC[rq: RealQ] RETURNS[BOOLEAN] =
INLINE {RETURN[rq.nextIndex = 0]};

END.