-- MonitoredQueueImpl.Mesa
-- 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
DIRECTORY
MonitoredQueue,
SafeStorage;
MonitoredQueueImpl:
CEDAR MONITOR
LOCKS queue USING queue: MQ
IMPORTS SafeStorage
EXPORTS MonitoredQueue =
BEGIN
MQ: TYPE = REF QueueBody;
QueueBody:
PUBLIC
TYPE =
MONITORED
RECORD [
start, end, free: LIST OF REF ANY,
closed: BOOLEAN ← FALSE,
z: ZONE, -- for allocating LISTs
change: CONDITION
];
QueueClosed: PUBLIC ERROR = CODE;
EndOfQueue: PUBLIC ERROR = CODE;
Create:
PUBLIC
PROC [z:
ZONE ←
NIL]
RETURNS [queue:
MQ] = {
IF z = NIL THEN z ← SafeStorage.GetSystemZone[];
queue ← z.NEW[QueueBody];
queue.z ← z };
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 ← z.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.