DIRECTORY CommTimer USING [Event, EventProc, IsNullEvent, nullEvent], CommTimerPrivate USING [EventObject, TicksSinceBoot, TimerObject], Process USING [Abort, Detach, EnableAborts, MsecToTicks, priorityClient3, SetPriority, SetTimeout, Ticks, TicksToMsec], Rope USING [ROPE] ; CommTimerImpl: CEDAR MONITOR LOCKS lock USING lock: Timer IMPORTS Process, CommTimer, CommTimerPrivate EXPORTS CommTimer ~ { EventProc: TYPE ~ CommTimer.EventProc; Timer: TYPE ~ REF TimerObject; TimerObject: PUBLIC TYPE ~ CommTimerPrivate.TimerObject; Event: TYPE ~ CommTimer.Event; EventObject: PUBLIC TYPE ~ CommTimerPrivate.EventObject; msecPerTick: INT ¬ Process.MsecToTicks[1]; maxSizeOfWheel: CARDINAL ¬ 256; MsecSinceBoot: PROC RETURNS [msec: INT] ~ { msec ¬ LOOPHOLE[Process.TicksToMsec[CommTimerPrivate.TicksSinceBoot[]]]; }; Error: PUBLIC ERROR [codes: LIST OF ATOM, msg: Rope.ROPE] ~ CODE; eventLock: Timer ¬ NEW[TimerObject[0]]; freeList: REF EventObject ¬ NIL; AllocEvent: ENTRY PROC [lock: Timer ¬ eventLock] RETURNS [e: Event] ~ { IF freeList = NIL THEN { e.ref ¬ NEW[EventObject]; } ELSE { e.ref ¬ freeList; freeList ¬ e.ref.next; e.ref.next ¬ NIL; }; e.gen ¬ e.ref.gen; }; FreeEvent: ENTRY PROC [lock: Timer ¬ eventLock, re: REF EventObject] ~ { re.gen ¬ re.gen.SUCC; re.next ¬ freeList; freeList ¬ re; }; EntryWaitForEvent: ENTRY PROC [lock: Timer] RETURNS [list: REF EventObject] ~ { ENABLE UNWIND => NULL; t: Timer ~ lock; nowMsec, rangeMsec, delta: INT; rangeMsec ¬ t.wheelSize * t.grainSizeMsec; DO nowMsec ¬ MsecSinceBoot[]; delta ¬ nowMsec - t.nextMsec; SELECT delta FROM > 2 * rangeMsec => { t.nextMsec ¬ nowMsec - rangeMsec; EXIT }; >= 0 => { t.nextMsec ¬ t.nextMsec + t.grainSizeMsec; EXIT }; >= (-t.grainSizeMsec) => { ticks: Process.Ticks ¬ Process.MsecToTicks[-delta]; TRUSTED { Process.SetTimeout[@t.wakeup, ticks] }; WAIT t.wakeup; LOOP }; ENDCASE => { t.nextMsec ¬ nowMsec - rangeMsec; EXIT }; ENDLOOP; { lDue, lNotDue, e, next: REF EventObject; FOR e ¬ t.wheel[t.wheelIndex], next WHILE e # NIL DO next ¬ e.next; IF (e.whenMsec - t.nextMsec) < 0 THEN { e.next ¬ lDue; lDue ¬ e } ELSE { e.next ¬ lNotDue; lNotDue ¬ e }; ENDLOOP; t.wheel[t.wheelIndex] ¬ lNotDue; list ¬ lDue; }; t.wheelIndex ¬ t.wheelIndex.SUCC MOD t.wheelSize; }; DoEvents: PROC [list: REF EventObject, doCalls: BOOL ¬ TRUE] ~ { WHILE list # NIL DO e: REF EventObject ¬ list; clientData: REF ¬ e.clientData; proc: EventProc ¬ e.proc; list ¬ list.next; IF (proc # NIL) AND doCalls THEN proc[clientData]; FreeEvent[eventLock, e]; ENDLOOP; }; Daemon: PROC [t: Timer] ~ { ENABLE ABORTED => CONTINUE; Process.SetPriority[Process.priorityClient3]; DO list: REF EventObject ¬ EntryWaitForEvent[t]; DoEvents[list]; ENDLOOP; }; CreateTimer: PUBLIC PROC [grainSizeMsec: INT, expectedWaitMsec: INT] RETURNS [t: Timer] ~ { sizeOfWheel: CARDINAL; IF grainSizeMsec < 0 THEN ERROR Error[LIST[$badGrainSize], "negative grain size"]; grainSizeMsec ¬ MAX[msecPerTick, grainSizeMsec]; expectedWaitMsec ¬ MAX[expectedWaitMsec, grainSizeMsec]; sizeOfWheel ¬ expectedWaitMsec / grainSizeMsec; IF sizeOfWheel < maxSizeOfWheel THEN sizeOfWheel ¬ sizeOfWheel + sizeOfWheel/2; sizeOfWheel ¬ MIN[sizeOfWheel, maxSizeOfWheel]; t ¬ NEW[TimerObject[sizeOfWheel]]; t.grainSizeMsec ¬ grainSizeMsec; t.nextMsec ¬ MsecSinceBoot[]; TRUSTED { Process.EnableAborts[@t.wakeup] }; t.daemon ¬ FORK Daemon[t]; }; EntryDestroyTimer: ENTRY PROC [lock: Timer] ~ { lock.destroyed ¬ TRUE; }; DestroyTimer: PUBLIC PROC [t: Timer, doEvents: BOOL] ~ { p: PROCESS; EntryDestroyTimer[t]; IF (p ¬ t.daemon) # NIL THEN TRUSTED { Process.Abort[p]; Process.Detach[p]; }; FOR i: CARDINAL IN [0..t.wheelSize) DO list: REF EventObject; list ¬ t.wheel[i]; t.wheel[i] ¬ NIL; DoEvents[list, doEvents]; ENDLOOP; }; GrainSizeMsec: PUBLIC PROC [t: Timer] RETURNS [grainSizeMsec: INT] ~ { RETURN[t.grainSizeMsec] }; EntryScheduleEvent: PUBLIC ENTRY PROC [lock: Timer, waitMsec: INT, e: Event] RETURNS [Event] ~ { index: CARDINAL; IF lock.destroyed THEN RETURN [CommTimer.nullEvent]; e.ref.whenMsec ¬ waitMsec + lock.nextMsec; index ¬ ((waitMsec / lock.grainSizeMsec) + lock.wheelIndex) MOD lock.wheelSize; e.ref.next ¬ lock.wheel[index]; lock.wheel[index] ¬ e.ref; RETURN [e]; }; ScheduleEvent: PUBLIC PROC [t: Timer, waitMsec: INT, proc: EventProc, clientData: REF] RETURNS [Event] ~ { e: Event ¬ AllocEvent[eventLock]; e.ref.proc ¬ proc; e.ref.clientData ¬ clientData; IF waitMsec > 0 THEN { e ¬ EntryScheduleEvent[t, waitMsec, e]; IF CommTimer.IsNullEvent[e] THEN ERROR Error[LIST[$staleTimer], "timer destroyed"]; } ELSE { DoEvents[e.ref]; }; RETURN[ e ]; }; EntryCancelEvent: ENTRY PROC [lock: Timer ¬ eventLock, e: Event] ~ { IF e.gen # e.ref.gen THEN RETURN; e.ref.proc ¬ NIL; e.ref.clientData ¬ NIL; }; CancelEvent: PUBLIC PROC [t: Timer, e: Event] ~ { EntryCancelEvent[eventLock, e]; }; EntryMsecUntilOccurs: ENTRY PROC [lock: Timer ¬ eventLock, t: Timer, e: Event] RETURNS [INT] ~ { RETURN[ IF e.ref.gen = e.gen THEN e.ref.whenMsec - t.nextMsec ELSE 0 ]; }; MsecUntilOccurs: PUBLIC PROC [t: Timer, e: Event] RETURNS [INT] ~ { RETURN[ EntryMsecUntilOccurs[eventLock, t, e] ]; }; }. bCommTimerImpl.mesa Copyright Σ 1988, 1991 by Xerox Corporation. All rights reserved. Demers, October 11, 1990 8:36 am PDT Willie-s, March 24, 1992 3:33 pm PST Copied Types Parameters Glue Error Event Freelist Daemon We've fallen way behind, so lose some time ... We've fallen incredibly far behind and wrapped, so lose some time ... Operations Κy–(cedarcode) style•NewlineDelimiter ˜code™Kšœ Οeœ7™BK™$K™$K˜—šΟk ˜ Kšœ žœ,˜;Kšœžœ,˜BKšœžœj˜wKšœžœžœ˜K˜K˜—šΟn œžœž˜Kšžœžœ ˜Kšžœ%˜,Kšžœ ˜K˜head™ Kšœ žœ˜&K˜Kšœžœžœ ˜Kšœ žœžœ ˜8K˜Kšœžœ˜Kšœ žœžœ ˜8—™ Kšœ žœ˜*Kšœžœ˜—™šŸ œžœžœžœ˜+Kšœžœ9˜HK˜——™Kš Ÿœžœžœ ž œ žœžœ˜A—™Kšœžœ˜'Kšœ žœžœ˜ K˜šŸ œžœžœžœ˜Gšžœ ž˜šžœ˜Kšœžœ˜K˜—šžœ˜K˜K˜Kšœ žœ˜K˜—K˜—K˜K˜—šŸ œžœžœžœ˜HKšœžœ˜K˜K˜K˜——™š Ÿœžœžœžœžœ˜OKšžœžœžœ˜K˜Kšœžœ˜Kšœ*˜*šž˜Kšœ˜Kšœ˜šžœž˜šœ˜K™/Kšœ!˜!Kšžœ˜—šœ ˜ Kšœ*˜*Kšžœ˜—šœ˜Kšœ3˜3Kšžœ*˜1Kšžœ ˜Kšžœ˜—šžœ˜ K™FKšœ!˜!Kšžœ˜——Kšžœ˜—˜Kšœžœ ˜(šžœ!žœžœž˜4K˜šžœ˜ Kšžœ˜ Kšžœ#˜'—Kšžœ˜—Kšœ ˜ Kšœ ˜ K˜—Kšœžœžœ ˜1K˜K˜——š Ÿœžœžœžœžœ˜@šžœžœž˜Kšœžœ˜Kšœ žœ˜K˜Kšœ˜Kšžœ žœžœ žœ˜2K˜Kšžœ˜—Kšœ˜K˜—šŸœžœ˜Kšžœžœžœ˜Kšœ-˜-šž˜Kšœžœ$˜-K˜Kšžœ˜—Kšœ˜—™ š Ÿ œžœžœžœžœžœ ˜WK˜Kšœ žœ˜Kšžœžœžœžœ(˜RKšœžœ˜0Kšœžœ"˜8Kšœ/˜/šžœ˜Kšžœ+˜/—Kšœžœ˜/Kšœžœ˜"Kšœ ˜ K˜Kšžœ%˜,Kšœ žœ ˜K˜—K˜šŸœžœžœ˜/Kšœžœ˜K˜K˜—šŸ œžœžœžœ˜8Kšœžœ˜ Kšœ˜šžœžœžœžœ˜&Kšœ˜Kšœ˜Kšœ˜—šžœžœžœž˜&Kšœžœ ˜Kšœ žœ˜$K˜Kšžœ˜—K˜K˜—Kš Ÿ œžœžœ žœžœžœ˜aK˜š Ÿœžœžœžœžœ žœ˜\K˜Kšœžœ˜Kšžœžœžœ˜4Kšœ*˜*Kšœ<žœ˜OKšœ˜Kšœ˜Kšžœ˜ K˜K˜—š Ÿ œžœžœžœžœžœ˜fK˜K˜!Kšœ˜K˜šžœ ˜šžœ˜Kšœ'˜'Kšžœžœžœžœ"˜SK˜—šžœ˜K˜K˜——Kšžœ˜ K˜K˜—šŸœžœžœ(˜DKšžœžœžœ˜!Kšœ žœ˜Kšœžœ˜K˜K˜—šŸ œžœžœ˜1Kšœ˜K˜K˜—š Ÿœžœžœ/žœžœ˜`Kšžœžœžœžœ˜GK˜K˜—š Ÿœžœžœžœžœ˜CKšžœ*˜0K˜——K˜K˜——…—έ