IntimeImpl.mesa
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
Paul Rovner on August 10, 1983 5:49 pm
Russ Atkinson, September 16, 1983 6:00 pm
 
DIRECTORY
Basics USING [LowHalf, LongDiv, LongNumber, HighHalf],
Intime,
Loader USING [MakeProcedureResident, MakeGlobalFrameResident],
Process USING [SecondsToTicks, TicksToMsec],
ProcessorFace 
USING [
GetGreenwichMeanTime, GetClockPulses, gmtEpoch, microsecondsPerHundredPulses];
 
 
IntimeImpl: 
MONITOR
IMPORTS Basics, Loader, Process, ProcessorFace 
EXPORTS Intime
SHARES Intime
= BEGIN OPEN Intime;
 
note: microsecondsPerHundredPulses/100 = microsecondsPerPulse
MicrosecondsToPulses: 
PROC[ms: 
LONG 
CARDINAL] 
RETURNS[
LONG 
CARDINAL] = {
RETURN[(ms*100)/ProcessorFace.microsecondsPerHundredPulses]; -- RRA
};
 
PulsesToMicroseconds: 
PROC[p: 
LONG 
CARDINAL] 
RETURNS[
LONG 
CARDINAL] = {
RETURN[(p*ProcessorFace.microsecondsPerHundredPulses)/100]; -- RRA
};
 
msPerDeltaTick: PUBLIC MsTicks ← Process.TicksToMsec[1];
deltaTicksPerSecond: PUBLIC DeltaTicks ← Process.SecondsToTicks[1];
pulsesPerSecond: LONG CARDINAL = MicrosecondsToPulses[1000000];
adjustInterval: LONG CARDINAL = 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: 
LONG 
CARDINAL;
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: LONG CARDINAL;
init: BOOL ← FALSE;
WHILE (now ← ProcessorFace.GetClockPulses[]-fastBase)>adjustInterval 
DO
InternalAdjustEventTime[init]; init←TRUE; ENDLOOP; -- repeats at most once.
 
RETURN[Increment[by: Basics.LongDiv[num: 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: 
BOOL] = {
InternalAdjustEventTime[initialize]
};
 
InternalAdjustEventTime: 
INTERNAL 
PROC [initialize: 
BOOL] =
 INLINE {
newSeconds: 
LONG 
CARDINAL =
ProcessorFace.GetGreenwichMeanTime[] - ProcessorFace.gmtEpoch;
 
IF newSeconds < seconds 
OR newSeconds - seconds > impossibleInterval
THEN initialize←TRUE;
 
IF initialize 
THEN {
milliseconds.higher ← 0;
milliseconds.lower ← LONG[Basics.LowHalf[newSeconds]]*1000;
milliseconds.hi ← milliseconds.hi + LONG[Basics.HighHalf[newSeconds]]*1000;
fastBase ← ProcessorFace.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, BigDifference returns LAST[MsTicks]
tt: Basics.LongNumber ← [lc[t1.lower - t2.lower]];
RETURN[
IF t1.higher > t2.higher + 1 OR tt.highbits # 0 THEN LAST[CARDINAL]
ELSE tt.lowbits
];
 
};