DIRECTORY BasicTime USING [earliestGMT, GMT, Now, Period, Update], ArpaQueue USING [ElemProc], Rope USING [ROPE]; ArpaQueueImpl: CEDAR PROGRAM IMPORTS BasicTime EXPORTS ArpaQueue = BEGIN MQ: TYPE = REF MQRep; MQRep: PUBLIC TYPE = RECORD[ name: ROPE, elemList: LIST OF QElem _ NIL, lastSlot: LIST OF QElem _ NIL]; QElem: TYPE = REF QElemRep; QElemRep: PUBLIC TYPE = RECORD[ value: REF ANY, inhibitUntil: GMT _ notInhibited, inhibitReason: ROPE _ notInhibitedRope]; ROPE: TYPE = Rope.ROPE; GMT: TYPE = BasicTime.GMT; NewElem: PUBLIC PROC [value: REF ANY] RETURNS [newElem: QElem] = { RETURN[NEW[QElemRep _ [value]]]; }; Value: PUBLIC PROC [qElem: QElem] RETURNS [value: REF ANY] = { RETURN[qElem.value]; }; Create: PUBLIC PROC [name: ROPE] RETURNS [newQueue: MQ] = { newQueue _ NEW[MQRep _ [name: name]]; }; Name: PUBLIC PROC [queue: MQ] RETURNS [ROPE] = { RETURN[queue.name]; }; IsEmpty: PUBLIC PROC [queue: MQ] RETURNS [BOOL] = { RETURN[queue.elemList = NIL]; }; Enqueue: PUBLIC PROC [queue: MQ, qElem: QElem] = { ENABLE UNWIND => NULL; IF queue.lastSlot = NIL THEN -- empty queue queue.elemList _ queue.lastSlot _ LIST[qElem] ELSE { queue.lastSlot.rest _ LIST[qElem]; queue.lastSlot _ queue.lastSlot.rest; }; }; Dequeue: PUBLIC PROC [queue: MQ, value: REF ANY] = { ENABLE UNWIND => NULL; elemList: LIST OF QElem _ queue.elemList; previousList: LIST OF QElem; IF elemList = NIL THEN RETURN WITH ERROR NotOnQueue; IF elemList.first.value = value THEN { queue.elemList _ elemList.rest; IF queue.elemList = NIL THEN queue.lastSlot _ NIL; RETURN; }; previousList _ elemList; FOR restElems: LIST OF QElem _ elemList.rest, previousList.rest UNTIL restElems = NIL DO IF restElems.first.value = value THEN { previousList.rest _ restElems.rest; IF restElems.rest = NIL THEN queue.lastSlot _ previousList; RETURN; }; previousList _ restElems; ENDLOOP; ERROR NotOnQueue; }; NotOnQueue: PUBLIC ERROR = CODE; GetHead: PUBLIC PROC [queue: MQ] RETURNS [qElem: QElem] = { ENABLE UNWIND => NULL; elemList: LIST OF QElem = queue.elemList; IF elemList = NIL THEN RETURN [NIL]; RETURN[elemList.first]; }; GetProcessableElement: PUBLIC PROC [queue: MQ] RETURNS [qElem: QElem] = { ENABLE UNWIND => NULL; FOR restElems: LIST OF QElem _ queue.elemList, restElems.rest UNTIL restElems = NIL DO qElem: QElem = restElems.first; IF Inhibition[qElem].for = 0 THEN RETURN[qElem]; ENDLOOP; RETURN[NIL]; }; QueueEmpty: PUBLIC ERROR = CODE; Enumerate: PUBLIC PROC [queue: MQ, proc: ArpaQueue.ElemProc, procData: REF ANY _ NIL] = { FOR restElems: LIST OF QElem _ queue.elemList, restElems.rest UNTIL restElems = NIL DO qElem: QElem ~ restElems.first; IF NOT proc[qElem, procData] THEN EXIT; ENDLOOP; }; notInhibited: GMT ~ BasicTime.earliestGMT; notInhibitedRope: ROPE ~ "not inhibited"; Inhibit: PUBLIC PROC [qElem: QElem, for--seconds--: INT, why: ROPE] ~ { qElem.inhibitUntil _ BasicTime.Update[BasicTime.Now[], for]; qElem.inhibitReason _ why; }; Uninhibit: PUBLIC PROC [qElem: QElem, queue: MQ] ~ { qElem.inhibitUntil _ notInhibited; qElem.inhibitReason _ notInhibitedRope; }; Inhibition: PUBLIC PROC [qElem: QElem] RETURNS [for: INT, why: ROPE] = { for _ MAX[BasicTime.Period[from: BasicTime.Now[], to: qElem.inhibitUntil], 0]; IF for = 0 THEN qElem.inhibitReason _ notInhibitedRope; RETURN[for, qElem.inhibitReason]; }; END. fArpaQueueImpl.mesa Last Edited by: DCraft, December 21, 1983 9:01 pm Last Edited by: Taft, February 3, 1984 11:25:43 am PST Last Edited by: HGM, April 11, 1984 11:53:06 pm PST John Larson, October 9, 1987 2:49:56 pm PDT Queue and Element Creation, Enqueueing, Dequeueing, and Enumeration A list cell is a pair of (qElem, ref to the next pair). When an element is dequeued, this pair is not reused - thus the ref to the next pair is still valid, and in fact it may still have a ref to it by someone who followed (i.e. copied) the link from the previous pair before it was changed. All of this presents no real problem if we can detect when a cell has been dequeued. For this purpose, in each qElem is included a flag which is initially true, and is set false by Dequeue. If this flag indicates that an element has been dequeued during enumeration, that element is simply skipped. If several adjacent elements have been dequeued, they will all be skipped. Because elements are only ever added at the end of the queue, the only integrity loss during enumeration occurs when the last element is dequeued, another takes its place, and Enumerate has already taken a copy of a ref to the deleted element (or a deleted predecessor). In this case, the newly added element will not be enumerated (big deal!). An element's being requeued [on another queue] causes no problem because the actual pair it occupied in the old queue is not changed. Place element at end of queue. Search down the list until value found and remove it. This will be called several times for each mail item going through the system, but for all except the last (LeavingSystem) the item should be at the beginning of the list or possibly within a short list (if a host is refusing this particular item). Expects a value rather than an element because client may well only have the value. Return the first element in the queue, without Dequeueing it, raising QueueEmpty if none. Inhibition An element may be inhibited as the result of a user order or automatically when a host refuses to accept it. Inhibition may be used in conjunction with placing items on the BadItems queue. ΚΘ˜headšœ™Ibodyšœ1™1Lšœ6™6Lšœ4™4Icode™+code2šΟk ˜ Nšœ œœ˜8Nšœ˜Nšœœœ˜——šΠln œ ˜Nšœ ˜Nšœ ˜Nš˜Nšœœœ˜šœœœœ˜Nšœœ˜ Nšœ œœ œ˜Nšœ œœ œ˜—Nšœœœ ˜šœ œœœ˜Nšœœœ˜Nšœœ˜!Nšœœ˜(—Nšœœœ˜Nšœœ œ˜™CN™N™ψN™—š Οnœœœ œœœ˜BNšœœ˜#—š Ÿœœœœ œœ˜>Nšœ˜—š Ÿœœœœœ œ˜;Nšœ œ˜(—š Ÿœœœ œœœ˜0Nšœ˜—š Ÿœœœ œœœ˜3Nšœœ˜ —šŸœ œ œ˜2Nšœ™Nšœœœ˜šœœœΟc˜+Nšœ"œ˜-—šœ˜Nšœœ˜"Nšœ'œ˜+——š Ÿœ œ œ œœ˜4N™‚Nšœœœ˜Nšœ œœ˜)Nšœœœ˜Nš œ œœœœœ ˜4šœœ˜&Nšœ˜Nšœœœœ˜2Nšœ˜ —N˜š œ œœ*œ œ˜Xšœœ˜'Nšœ#˜#Nšœœœ˜;Nšœ˜Nšœ˜—N˜Nšœ˜—Nšœ˜N˜—Nšœ œœœ˜ š Ÿœœœ œœ˜;N™YNšœœœ˜Nšœ œœ˜)Nš œ œœœœ˜$Nšœ˜—š Ÿœœœ œœ˜INšœœœ˜š œ œœ(œ œ˜VNšœ˜Nšœœœ˜0Nš˜—Nšœœ˜—Nšœ œœœ˜ šŸ œœœ œ&œœœ˜Yš œ œœ(œ œ˜VNšœ˜Nšœœœœ˜'Nšœ˜ ——N™ NšœΌ™ΌNšœœ˜*Nšœœ˜)š Ÿœœœ  œœœ˜GNšœ<˜