-- 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.