<> <> <> <> <<>> DIRECTORY Process USING [Detach], Rope USING [ROPE], TapeToolInternal USING [Action, ExecuteOp, IdleCheck, TapeTool]; TapeToolQueueImpl: CEDAR MONITOR LOCKS q USING q: Queue IMPORTS Process, TapeToolInternal EXPORTS TapeToolInternal = BEGIN OPEN Tool: TapeToolInternal; ROPE: TYPE = Rope.ROPE; ClientProgrammingError: ERROR = CODE; InternalProgrammingError: ERROR = CODE; Queue: TYPE = REF QueueObj; QueueObj: PUBLIC TYPE = MONITORED RECORD [ firstEvent: Event _ NIL, tool: Tool.TapeTool, notifierRunning: BOOL _ FALSE]; Action: TYPE = Tool.Action; Event: TYPE = LIST OF Action; -- Public procedures Create: PUBLIC PROC [tool: Tool.TapeTool] RETURNS [queue: Queue] = BEGIN queue _ NEW[QueueObj]; queue.tool _ tool; RETURN[queue]; END; Flush: PUBLIC ENTRY PROC [q: Queue] = BEGIN q.firstEvent_ NIL END; Enqueue: PUBLIC ENTRY PROC [tool: Tool.TapeTool, q: Queue, a: Action] = BEGIN e: Event _ CONS[first: a, rest: NIL]; qEnd: Event; IF q.firstEvent=NIL THEN q.firstEvent_ e ELSE BEGIN FOR qEnd_ q.firstEvent, qEnd.rest UNTIL qEnd.rest=NIL DO ENDLOOP; qEnd.rest_ e END; IF q.notifierRunning THEN RETURN; q.notifierRunning_ TRUE; TRUSTED {Process.Detach[FORK Notifier[tool, q]]}; END; Notifier: PROC [tool: Tool.TapeTool, q: Queue] = BEGIN -- This process is not under the queue monitor.There are exactly one or zero notifiers per -- queue, so that no more than one event happens at a time. -- FORKed from Enqueue. event: Event; UNTIL (event_ Dequeue[q])=NIL DO ENABLE ABORTED => {tool.active _ FALSE; Flush[q]; LOOP}; tool.active _ TRUE; Tool.ExecuteOp[q.tool, event.first]; ENDLOOP; IF q.tool.outer.iconic OR Tool.IdleCheck[tool] THEN Tool.ExecuteOp[tool: q.tool, op: [op: Close]]; tool.active _ FALSE; END; Dequeue: PUBLIC ENTRY PROC [q: Queue] RETURNS [event: Event] = -- Removes the first event on q's event list, returning NIL if list empty. -- Called from Notifier. BEGIN IF q.firstEvent=NIL THEN {q.notifierRunning_ FALSE; RETURN[NIL]}; event_ q.firstEvent; q.firstEvent_ q.firstEvent.rest; END; END.