-- 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.