-- SystemImpl.mesa (last edited by: Levin on: August 26, 1982 9:09 am)
-- THINGS TO DO:
-- 1) Get rid of call to TemporarySetGMT.SetGMT if ever through with gmt clock simulation
DIRECTORY
ControlPrograms USING [],
DeviceCleanup USING [Await, Item, Reason],
Environment USING [Long],
Inline USING [LongDiv, LongDivMod, LongMult],
KernelPhysicalVolume USING [
GetSavedLocalTimeParameters, SetSavedLocalTimeParameters],
Process USING [MsecToTicks, SetTimeout],
ProcessorFace USING [
GetGreenwichMeanTime, gmtEpoch, microsecondsPerHundredPulses, PowerOff,
processorID, ResetAutomaticPowerOn, SetAutomaticPowerOn],
RuntimeInternal USING [WorryCallDebugger],
SpecialSystem USING [ProcessorID],
System USING [GetClockPulses, GreenwichMeanTime, LocalTimeParameters,
Microseconds, PhysicalVolumeID, Pulses, TimerHandle, UniversalID],
SystemInternal USING [UniversalID],
TemporarySetGMT USING [SetGMT],
Volume USING [Close, GetNext, ID, nullID];
SystemImpl: MONITOR
IMPORTS
DeviceCleanup, KernelPhysicalVolume, Inline, Process, ProcessorFace,
RuntimeInternal, System, TemporarySetGMT, Volume
EXPORTS SpecialSystem, System, SystemInternal, ControlPrograms =
BEGIN OPEN System;
-- Interval timers
GetIntervalTime: PUBLIC SAFE PROC [t: TimerHandle] RETURNS [Microseconds] = TRUSTED {
RETURN[PulsesToMicroseconds[[GetClockPulses[] - LOOPHOLE[t, Pulses]]]]};
PulsesToMicroseconds: PUBLIC SAFE PROC [p: Pulses] RETURNS [Microseconds] = TRUSTED
BEGIN -- (p*msPerHp)/(100units/hundred)
RETURN[MultThenDiv[p, ProcessorFace.microsecondsPerHundredPulses, 100]]
END;
MicrosecondsToPulses: PUBLIC SAFE PROC [m: Microseconds] RETURNS [Pulses] = TRUSTED
BEGIN -- (microseconds*100units/hundred)/microsecondsPerHundredPulses
RETURN[[MultThenDiv[m, 100, ProcessorFace.microsecondsPerHundredPulses]]]
END;
MultThenDiv: PROC [m1: LONG CARDINAL, m2: CARDINAL, dv: CARDINAL]
RETURNS [result: LONG CARDINAL] =
BEGIN OPEN Inline, mm1: LOOPHOLE[m1, num Environment.Long];
t: MACHINE DEPENDENT RECORD [
SELECT OVERLAID * FROM
separate => [low, mid, high: CARDINAL],
lower => [lowlong: LONG CARDINAL, junk: CARDINAL],
higher => [junk: CARDINAL, highlong: LONG CARDINAL],
ENDCASE];
t.lowlong ← LongMult[mm1.lowbits, m2];
IF mm1.highbits # 0 THEN
BEGIN
t.highlong ← LongMult[mm1.highbits, m2] + t.mid;
IF t.high # 0 THEN
BEGIN OPEN q: LOOPHOLE[result, num Environment.Long];
-- have to do triple divide
IF t.high >= dv THEN t.high ← t.high MOD dv; -- overflow; lowbits will be right
[quotient: q.highbits, remainder: t.mid] ← LongDivMod[t.highlong, dv];
q.lowbits ← LongDiv[t.lowlong, dv];
RETURN;
END;
END;
-- t.high is 0, so let mesa do the work...
RETURN[t.lowlong/LONG[dv]];
END;
-- GMT
-- This is an entry procedure to serialize access to ProcessorFace.GetGreenwichMeanTime
GetGreenwichMeanTime: PUBLIC ENTRY SAFE PROC RETURNS [GreenwichMeanTime] =
TRUSTED {RETURN[LOOPHOLE[ProcessorFace.GetGreenwichMeanTime[]]]};
ltpState: {
unknown, -- => ltp undefined
known, -- => ltp defined, but may not be saved on nonvolatile storage
knownAndSaved} -- ltp defined and saved on nonvolatile storage
← unknown;
ltp: LocalTimeParameters;
InitializeLocalTimeParameters: PROC =
BEGIN
valid: BOOLEAN;
[valid, ltp] ← TemporarySetGMT.SetGMT[];
IF valid THEN ltpState ← known
END;
GetLocalTimeParameters: PUBLIC ENTRY SAFE PROC [pvID: PhysicalVolumeID]
RETURNS [LocalTimeParameters] = TRUSTED
BEGIN
valid: BOOLEAN;
SELECT ltpState FROM
unknown => -- try to read them from nonvolatile storage
BEGIN
[valid, ltp] ← KernelPhysicalVolume.GetSavedLocalTimeParameters[pvID];
IF valid THEN ltpState ← knownAndSaved
ELSE RETURN WITH ERROR LocalTimeParametersUnknown;
END;
known => -- (try to) make sure they are saved on nonvolatile storage
SetSavedLTP[pvID];
ENDCASE;
RETURN[ltp]
END;
LocalTimeParametersUnknown: PUBLIC ERROR = CODE;
SetLocalTimeParameters: PUBLIC ENTRY PROC [
params: LocalTimeParameters, pvID: PhysicalVolumeID] =
BEGIN
SELECT TRUE FROM
ltpState=knownAndSaved AND ltp=params => NULL;
ENDCASE => {ltp ← params; ltpState ← known; SetSavedLTP[pvID]};
END;
-- Write local time parameters to nonvolatile storage, if they are different.
SetSavedLTP: INTERNAL PROC [pvID: PhysicalVolumeID] =
BEGIN OPEN KernelPhysicalVolume;
valid: BOOLEAN; savedltp: LocalTimeParameters;
[valid, savedltp] ← GetSavedLocalTimeParameters[pvID];
IF ~valid OR savedltp~=ltp THEN
IF NOT SetSavedLocalTimeParameters[params: ltp, pvID: pvID].updated
THEN GOTO NotSaved;
ltpState ← knownAndSaved; -- (unless pvID=nullID and IsUtilityPilot[])
EXITS NotSaved => NULL;
END;
-- Processor identification (SpecialSystem)
GetProcessorID: PUBLIC PROC RETURNS [SpecialSystem.ProcessorID] = {
RETURN[LOOPHOLE[ProcessorFace.processorID]]};
-- Universal identifiers
UniversalID: PUBLIC TYPE = SystemInternal.UniversalID;
-- Generate new universalID from the processorID and universal id counter.
-- Sequence field of resultant value always less than
-- SecondsSinceEpoch[GetGreenwichMeanTime].
GetUniversalID: PUBLIC ENTRY PROC RETURNS [UniversalID] =
BEGIN
secondsSinceEpoch: LONG CARDINAL;
nextUID: SystemInternal.UniversalID;
-- If clock isn't set, GetGreenwichMeanTime returns gmtEpoch, so uidCounter=0
DO
secondsSinceEpoch ← ProcessorFace.GetGreenwichMeanTime[] - ProcessorFace.gmtEpoch;
IF secondsSinceEpoch = 0 THEN
RuntimeInternal.WorryCallDebugger["GMT clock not set: GetUniversalID"L];
IF ~uidCounterValid THEN
BEGIN
uidCounter ← secondsSinceEpoch; -- clock set after initialization
uidCounterValid ← TRUE;
END;
IF uidCounter < secondsSinceEpoch THEN EXIT;
WAIT oneSecond;
ENDLOOP;
nextUID ← [processor: LOOPHOLE[ProcessorFace.processorID], sequence: uidCounter];
uidCounter ← uidCounter + 1;
RETURN[nextUID]
END;
oneSecond: CONDITION;
uidCounter: LONG CARDINAL; -- always <=SecondsSinceEpoch[GetGreenwichMeanTime[]]
uidCounterValid: BOOLEAN ← FALSE;
InitializeUIDCleanup: PROC =
BEGIN OPEN DeviceCleanup;
item: Item;
reason: Reason;
DO
reason ← Await[@item];
SELECT reason FROM turnOff => uidCounterValid ← FALSE; ENDCASE;
ENDLOOP;
END;
-- System Power Control
PowerOff: PUBLIC PROC =
BEGIN
vID: Volume.ID ← Volume.nullID;
UNTIL (vID ← Volume.GetNext[vID]) = Volume.nullID DO
Volume.Close[vID] ENDLOOP;
ProcessorFace.PowerOff[];
END;
SetAutomaticPowerOn: PUBLIC SAFE PROC [
time: GreenwichMeanTime, externalEvent: BOOLEAN] = TRUSTED {
ProcessorFace.SetAutomaticPowerOn[time, externalEvent]; };
ResetAutomaticPowerOn: PUBLIC SAFE PROC = TRUSTED
{ProcessorFace.ResetAutomaticPowerOn[]; };
-- SystemInternal
Unimplemented: PUBLIC SIGNAL = CODE;
-- Initialization
InitializeLocalTimeParameters[]; -- may set GMT from Ethernet too
Process.SetTimeout[@oneSecond, Process.MsecToTicks[1000]];
-- set timeout to (approx) one second
InitializeUIDCleanup[];
END.
(For earlier log entries see Pilot 3.0 archive version.)
February 4, 1980 3:56 PM McJones Move gmt-keeping below OISProcessorFace
February 26, 1980 12:22 PM McJones AR1840: Reset uidCounter on return from debugger
April 15, 1980 3:11 PM McJones Move InitializeGMT to another module
June 24, 1980 4:39 PM McJones Convert to 48-bit processor ids and 80-bit universal ids; OISProcessorFace=>ProcessorFace
October 3, 1980 7:56 PM Forrest Convert to use 48 bit arithmetic in usec<=>pulses
January 23, 1981 2:50 PM McJones Local time parameters
February 4, 1981 3:09 PM McJones SystemExtras=>System
February 14, 1981 6:34 PM McJones Set ltpState at least to known in SetLocalTimeParameters
August 26, 1982 9:09 am Levin Make things SAFE.