-- File: TimeChecker.mesa, Last Edit: HGM December 4, 1980 6:55 PM -- Please don't forget to update the herald.... DIRECTORY InlineDefs USING [BcplToMesaLongNumber], Process USING [Detach, SetTimeout, SecondsToTicks], Runtime USING [IsBound], Storage USING [FreeString], String USING [ AppendChar, AppendString, AppendDecimal, AppendLongDecimal, EquivalentString], Time USING [AppendCurrent, Current], CmFile USING [OpenSection, NextItem, Close], Put USING [Line], Tool USING [Create, MakeSWsProc, MakeMsgSW], ToolWindow USING [TransitionProcType], Window USING [Handle], Indirect USING [GetParmFileName], TimeServerDefs USING [PupTimeFormat], PupDefs USING [ PupBuffer, GetFreePupBuffer, ReturnFreePupBuffer, PupAddress, GetPupAddress, PupNameTrouble, PupSocket, PupSocketDestroy, PupSocketMake, PupPackageDestroy, PupPackageMake, SecondsToTocks, SetPupContentsWords], PupTypes USING [fillInSocketID, miscSrvSoc]; TimeChecker: MONITOR IMPORTS InlineDefs, Process, Runtime, Storage, String, Time, CmFile, Put, Tool, Indirect, PupDefs = BEGIN OPEN PupDefs; target: STRING; timesAround: CARDINAL ← 0; msg: Window.Handle ← NIL; pleaseStop, running: BOOLEAN ← FALSE; Init: PROCEDURE = BEGIN IF ~FindParameters[] THEN RETURN; [] ← Tool.Create[ name: "Time Checker of December 4, 1980"L, makeSWsProc: MakeSWs, clientTransition: ClientTransition]; Process.Detach[FORK ClockWatcher[]]; END; FindParameters: PROCEDURE RETURNS [ok: BOOLEAN] = BEGIN parmFileName: STRING ← NIL; sectionName: STRING = "TimeChecker"L; token, arg: STRING ← NIL; IF Runtime.IsBound[Indirect.GetParmFileName] THEN parmFileName ← Indirect.GetParmFileName[]; IF parmFileName = NIL THEN parmFileName ← "TimeChecker.txt"; IF ~CmFile.OpenSection[parmFileName, sectionName] THEN BEGIN Problem["Can't find [TimeChecker] section in "L, parmFileName]; RETURN[FALSE]; END; ok ← FALSE; DO [token, arg] ← CmFile.NextItem[]; SELECT TRUE FROM token = NIL => EXIT; (token.length > 0 AND token[0] = ';) => NULL; String.EquivalentString[token, "Target"L] => BEGIN target ← arg; arg ← NIL; ok ← TRUE; Problem["Target is "L, target]; END; ENDCASE => Problem["Unknown parameter: "L, token]; Storage.FreeString[token]; Storage.FreeString[arg]; ENDLOOP; CmFile.Close[parmFileName]; RETURN[ok]; END; Problem: PROCEDURE [one, two, three: STRING ← NIL] = BEGIN text: STRING = [100]; Time.AppendCurrent[text]; String.AppendString[text, " TimeChecker: "L]; String.AppendString[text, one]; IF two # NIL THEN String.AppendString[text, two]; IF three # NIL THEN String.AppendString[text, three]; String.AppendChar[text, '.]; LogString[text]; END; ClockWatcher: ENTRY PROCEDURE = BEGIN pause: CONDITION; -- One minute who: PupAddress; when: LONG CARDINAL; running ← TRUE; Process.SetTimeout[@pause, Process.SecondsToTicks[60]]; THROUGH [0..5) DO WAIT pause; ENDLOOP; -- let time get set PupPackageMake[]; who ← FindAddress[]; when ← Time.Current[]; UNTIL pleaseStop DO Probe[who]; -- save frame space when ← when + 3600; THROUGH [0..120) UNTIL Time.Current[] > when DO WAIT pause; ENDLOOP; timesAround ← timesAround + 1; ENDLOOP; PupPackageDestroy[]; running ← FALSE; END; FindAddress: INTERNAL PROCEDURE RETURNS [who: PupAddress] = BEGIN pause: CONDITION; -- one hour error: BOOLEAN ← FALSE; Process.SetTimeout[@pause, Process.SecondsToTicks[60*60]]; who.socket ← PupTypes.miscSrvSoc; BEGIN ENABLE PupDefs.PupNameTrouble => BEGIN text: STRING = [150]; Time.AppendCurrent[text]; String.AppendString[ text, " TimeChecker: Troubles finding address for "L]; String.AppendString[text, target]; String.AppendString[text, ", "L]; String.AppendString[text, e]; String.AppendChar[text, '.]; LogString[text]; error ← TRUE; RETRY; END; IF error THEN WAIT pause; GetPupAddress[@who, target]; END; END; Probe: PROCEDURE [who: PupAddress] = BEGIN soc: PupSocket ← PupSocketMake[ PupTypes.fillInSocketID, who, SecondsToTocks[1]]; b: PupBuffer; diff: LONG INTEGER ← 99999; hits: CARDINAL ← 0; THROUGH [0..10) DO b ← GetFreePupBuffer[]; b.pupType ← dateAltoRequest; SetPupContentsWords[b, 0]; soc.put[b]; IF (b ← soc.get[]) # NIL THEN -- one sec timeout BEGIN -- maybe we should include 1/2 of the response time IF b.pupType = dateAltoIs THEN BEGIN info: LONG POINTER TO TimeServerDefs.PupTimeFormat; me, him: LONG INTEGER; -- NB: not LONG CARDINAL info ← LOOPHOLE[@b.pupWords]; me ← Time.Current[]; him ← InlineDefs.BcplToMesaLongNumber[info.time]; diff ← MIN[diff, (him - me)]; hits ← hits + 1; END; ReturnFreePupBuffer[b]; END; ENDLOOP; PupSocketDestroy[soc]; IF hits # 0 THEN BEGIN text: STRING = [100]; Time.AppendCurrent[text]; SELECT TRUE FROM (timesAround = 0) => BEGIN String.AppendString[text, " At the start of this run, "L]; END; (timesAround = 1) => BEGIN String.AppendString[text, " After one hour, "L]; END; (timesAround = 24) => BEGIN String.AppendString[text, " After one day, "L]; END; (timesAround = 168) => BEGIN String.AppendString[text, " After one week, "L]; END; (timesAround MOD 24) = 0 => BEGIN String.AppendString[text, " After "L]; String.AppendDecimal[text, timesAround/24]; String.AppendString[text, " days, "L]; END; ENDCASE => BEGIN String.AppendString[text, " After "L]; String.AppendDecimal[text, timesAround]; String.AppendString[text, " hours, "L]; END; String.AppendString[text, target]; String.AppendString[text, "'s clock is "L]; String.AppendLongDecimal[text, diff]; String.AppendString[text, " seconds faster than ours."L]; LogString[text]; END; END; LogString: PROCEDURE [text: STRING] = BEGIN IF msg # NIL THEN Put.Line[msg, text]; Put.Line[NIL, text]; END; MakeSWs: Tool.MakeSWsProc = BEGIN msg ← Tool.MakeMsgSW[window: window, lines: 5]; END; ClientTransition: ToolWindow.TransitionProcType = BEGIN IF new = inactive THEN msg ← NIL; END; -- initialization Init[]; END.