<<>> <> <> <> <> <> <> 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] }; <> <> AddToSet: PUBLIC PROC [item: REF ANY, queue: MQ] = { AddIt[item, queue, TRUE] }; <> <> 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; <> <> 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; <> ENABLE UNWIND => NULL; UNTIL closed AND start = NIL DO WAIT change; ENDLOOP; closed ¬ FALSE }; END.