-- File: IntimeImpl.mesa
-- Last edited by
-- Dan Swinehart March 23, 1982 12:58 pm
-- MBrown on 23-Mar-82 16:03:41
-- Dan Swinehart on April 14, 1982 11:04 am
DIRECTORY
Intime,
Inline USING [ LowHalf, LongDiv, LongNumber, HighHalf ],
Process USING [ SecondsToTicks, TicksToMsec ],
SpecialSpace USING [ MakeGlobalFrameResident, MakeCodeResident ],
System USING [ GetGreenwichMeanTime, GetClockPulses, MicrosecondsToPulses,
Pulses, PulsesToMicroseconds, SecondsSinceEpoch ]
;
IntimeImpl: MONITOR
IMPORTS Inline, Process, SpecialSpace, System
EXPORTS Intime
SHARES Intime =
BEGIN OPEN Intime;
msPerDeltaTick: PUBLIC MsTicks ← Process.TicksToMsec[1];
deltaTicksPerSecond: PUBLIC DeltaTicks ← Process.SecondsToTicks[1];
pulsesPerSecond: System.Pulses = System.MicrosecondsToPulses[m: 1000000];
adjustInterval: System.Pulses = [pulsesPerSecond-1];
impossibleInterval: LONG CARDINAL = 30; -- seconds, must be < 64K/1000
seconds: LONG CARDINAL;
--seconds since System.gmtEpoch the last time we set milliseconds
milliseconds: EventTime;
-- milliseconds since System.gmtEpoch
fastBase: System.Pulses;
-- value of System.GetClockPulses[] at time (in the recent past)
--when milliseconds = System.GetGreenwichMeanTime[].
-- things stop working if System.GetClockPulses[]-fastBase gets large (one minute or so).
-- Frequently-running process is supposed to call AdjustEventTime often enough to
-- update fastBase within adjustInterval pulses.
ReadEventTime: PUBLIC ENTRY PROC [] RETURNS [res: EventTime] = {
now: System.Pulses; init: BOOLEAN←FALSE;
WHILE (now ← [System.GetClockPulses[]-fastBase])>adjustInterval DO
InternalAdjustEventTime[init]; init←TRUE; ENDLOOP; -- repeats at most once.
RETURN[Increment[by: Inline.LongDiv[num: System.PulsesToMicroseconds[now], den: 1000]]] };
Increment: INTERNAL PROC [by: --milliseconds--CARDINAL]
RETURNS [res: EventTime] = INLINE {
res← [hiShort[higher: 0, lower: LONG[by] + LONG[milliseconds.lo]]];
res.hi ← res.hi + milliseconds.hi };
AdjustEventTime: PUBLIC ENTRY PROC[initialize: BOOLEAN] = {
InternalAdjustEventTime[initialize]; };
InternalAdjustEventTime: INTERNAL PROC[initialize: BOOLEAN] = INLINE {
newSeconds: LONG CARDINAL =
System.SecondsSinceEpoch[System.GetGreenwichMeanTime[]];
IF newSeconds<seconds OR newSeconds-seconds>impossibleInterval THEN initialize←TRUE;
IF initialize THEN {
milliseconds.higher ← 0;
milliseconds.lower ← LONG[Inline.LowHalf[newSeconds]]*1000;
milliseconds.hi ← milliseconds.hi + LONG[Inline.HighHalf[newSeconds]]*1000;
fastBase ← System.GetClockPulses[]; }
ELSE {
dif: NAT←newSeconds-seconds;
milliseconds ← Increment[by: 1000*dif];
-- Usually go through following loop zero or one times,
-- never more than impossibleInterval times.
THROUGH [1..dif] DO fastBase ← [fastBase+pulsesPerSecond] ENDLOOP };
seconds ← newSeconds; };
BigDifference: PUBLIC PROC [t1, t2: LONG POINTER TO READONLY EventTime]
RETURNS [MsTicks] = {
-- t1 presumed later than or equal to t2. For time differences beyond the MsTicks range,
-- returns LAST[MsTicks] --
tt: Inline.LongNumber ← [lc[t1.lower - t2.lower]];
RETURN[
IF t1.higher > t2.higher + 1 OR tt.highbits # 0 THEN LAST[CARDINAL]
ELSE tt.lowbits] };
-- Initialization --
-- Should be called BEFORE Inscript registers in!
SpecialSpace.MakeGlobalFrameResident[IntimeImpl];
SpecialSpace.MakeCodeResident[IntimeImpl];
END.