TapeToolQueueImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Diebert, October 16, 1984 5:03:27 pm PDT
Tim Diebert May 13, 1985 4:39:04 pm PDT
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;