-- RTQueueImpl.Mesa FOR USE BY THE COLLECTOR
-- last edited 3-Sep-81 13:23:02 by Paul Rovner
DIRECTORY
RTBasic USING[Pointer],
RTQueue,
RTStorageOps USING[AssignRef];
RTQueueImpl: MONITOR -- protects q's
LOCKS LOOPHOLE[q, RealQ] USING q: Q
IMPORTS RTStorageOps
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], RTBasic.Pointer] ← LOOPHOLE[ref, RTBasic.Pointer];
rq.nextIndex ← rq.nextIndex + 1;
NOTIFY rq.nonEmpty;
RETURN[FALSE]};
Dequeue: PUBLIC PROC[q: Q] RETURNS[ref: REF ANY] =
{t: REF ANY;
t ← ref ← DoDequeue[q];
-- now decrement ref's reference count
RTStorageOps.AssignRef[NIL, @t]};
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], RTBasic.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.