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