MonitoredQueueImpl.mesa
Copyright © 1985 by Xerox Corporation.  All rights reserved.
written by Paxton.  December 1981
last written by Paxton. August 10, 1982 1:27 pm
Last Edited by: Maxwell, January 5, 1983 12:34 pm
Doug Wyatt, March 3, 1985 5:00:34 pm PST
 
DIRECTORY
MonitoredQueue;
 
MonitoredQueueImpl: CEDAR MONITOR LOCKS queue USING queue: MQ
EXPORTS MonitoredQueue
= BEGIN
MQ: TYPE = REF QueueBody;
QueueBody: 
PUBLIC 
TYPE = 
MONITORED 
RECORD [
start, end, free: LIST OF REF ANY ← NIL,
closed: BOOL ← FALSE,
change: CONDITION
];
QueueClosed: PUBLIC ERROR = CODE;
EndOfQueue: PUBLIC ERROR = CODE;
Create: 
PUBLIC 
PROC 
RETURNS [queue: 
MQ] = {
RETURN[NEW[QueueBody ← []]];
};
 
Add: 
PUBLIC 
PROC [item: 
REF 
ANY, queue: 
MQ] = { AddIt[item, queue, 
FALSE] };
adds item to queue
causes ERROR QueueClosed if have already called Close[queue]
 
AddToSet: 
PUBLIC 
PROC [item: 
REF 
ANY, queue: 
MQ] = { AddIt[item, queue, 
TRUE] };
adds item to queue unless it is already in it
causes ERROR QueueClosed if queue is closed
 
AddIt: 
ENTRY 
PROC [item: 
REF 
ANY, queue: 
MQ, toSet: 
BOOL] = { 
OPEN queue;
ENABLE UNWIND => NULL;
new: LIST OF REF ANY;
IF closed THEN ERROR QueueClosed;
IF toSet 
THEN 
-- check if item is alreay in queue
FOR list: 
LIST 
OF 
REF 
ANY ← start, list.rest 
UNTIL list=
NIL 
DO
IF list.first = item THEN RETURN; -- already in queue
ENDLOOP;
 
 
IF free # NIL THEN { new ← free; free ← free.rest; new.rest ← NIL; new.first ← item }
ELSE new ← LIST[item];
IF end=NIL THEN start ← new
ELSE end.rest ← new;
end ← new;
NOTIFY change;
};
 
Remove: 
PUBLIC 
ENTRY 
PROC [queue: 
MQ] 
RETURNS [item: 
REF 
ANY] = { 
OPEN queue;
returns next item
causes ERROR EndOfQueue if have called Close[queue] and no more items
ENABLE UNWIND => NULL;
current: LIST OF REF ANY;
UNTIL closed OR start # NIL DO WAIT change; ENDLOOP;
IF (current ← start) = NIL THEN ERROR EndOfQueue;
item ← current.first; current.first ← NIL;
start ← current.rest; current.rest ← free; free ← current;
IF start = 
NIL 
THEN {
end ← NIL; -- have removed last entry
IF closed THEN BROADCAST change --for possible Reset-- }};
 
 
Close: 
PUBLIC 
ENTRY 
PROC [queue: 
MQ] = { 
OPEN queue;
ENABLE UNWIND => NULL;
closed ← TRUE;
BROADCAST change -- may be several waiting Remove's -- };
 
Reset: 
PUBLIC 
ENTRY 
PROC [queue: 
MQ] = { 
OPEN queue;
this waits until queue is closed and empty, then reopens it
ENABLE UNWIND => NULL;
UNTIL closed AND start = NIL DO WAIT change; ENDLOOP;
closed ← FALSE };
 
END.