-- File: DogWatcher.mesa - last edit:
-- AOF                  8-Feb-88 11:32:15
-- HGM                 16-Jul-85 11:37:07
-- Copyright (C) 1983, 1988 by Xerox Corporation. All rights reserved. 
-- Beware: Start this early, or you might not have time.

DIRECTORY
  Buffer USING [Buffer, ReturnBuffer],
  CmFile USING [Handle, TableError],
  Driver USING [GetInputBuffer],
  Process USING [
    Detach, Pause, priorityBackground, SecondsToTicks, SetPriority, Ticks],
  PupDefs USING [
    Buffer, PupAddress, PupSocket, PupSocketMake, ReturnBuffer, UniqueLocalPupAddress,
    veryShortWait],
  Put USING [Text],
  Protocol1 USING [Family, GetFamilyUnit],
  StringLookUp USING [noMatch, TableDesc],
  String USING [AppendChar, AppendDecimal, AppendString],
  Token USING [Boolean, Decimal],
  Indirect USING [Close, NextValue, OpenSection],
  Watchdog USING [Activate, Deactivate, Reactivate];

DogWatcher: PROGRAM
  IMPORTS
    Buffer, CmFile, Driver, Process, Protocol1, PupDefs, Put, String, Token,
    Indirect, Watchdog =
  BEGIN
  
  FindParameters: PROCEDURE =
    BEGIN
    cmFile: CmFile.Handle;
    Option: TYPE = MACHINE DEPENDENT{
      activate(0), deactivate, poke, noMatch(StringLookUp.noMatch)};
    DefinedOption: TYPE = Option [activate..poke];
    CheckType: PROCEDURE [h: CmFile.Handle, table: StringLookUp.TableDesc]
      RETURNS [index: CARDINAL] = Indirect.NextValue;
    MyNextValue: PROCEDURE [
      h: CmFile.Handle,
      table: LONG DESCRIPTOR FOR ARRAY DefinedOption OF LONG STRING]
      RETURNS [index: Option] = LOOPHOLE[CheckType];
    optionTable: ARRAY DefinedOption OF LONG STRING ← [
      activate: "Activate"L, deactivate: "Deactivate"L, poke: "Poke"L];
    leasedLines: CARDINAL ← 0;
    cmFile ← Indirect.OpenSection["WatchdogTimer"L];
    IF cmFile = NIL THEN
      BEGIN
      Message["Can't find [WatchdogTimer] section in Parameter file"L];
      Watchdog.Deactivate[];
      Message["Deactivating Watchdog timer"L];
      RETURN;
      END;
    DO
      option: Option;
      option ← MyNextValue[cmFile, DESCRIPTOR[optionTable] !
        CmFile.TableError =>
          BEGIN
	  IF name[0] # '; THEN Message["Unrecognized parameter: ", name];
	  RETRY;
	  END];
      SELECT option FROM
        noMatch => EXIT;
        activate => 
          BEGIN
          IF Token.Boolean[cmFile] THEN
            BEGIN
            Message["(Re)Activating Watchdog timer for another 3 minutes"L];
	    Watchdog.Activate[3*60];
            END
          ELSE Message["Didn't activate Watchdog timer"L];
          END;
        deactivate => 
          BEGIN
          IF Token.Boolean[cmFile] THEN
            BEGIN
            Message["Deactivating Watchdog timer"L];
	    Watchdog.Deactivate[];
            END
          ELSE Message["Didn't deactivate Watchdog timer"L];
          END;
        poke =>
          BEGIN
          IF Token.Boolean[cmFile] THEN
            BEGIN
	    howLong: CARDINAL ← Token.Decimal[cmFile];
	    howOften: CARDINAL ← Token.Decimal[cmFile];
            MessagePoke["Poking Watchdog timer"L, howLong, howOften];
	    Process.Detach[FORK Poker[howLong: howLong, howOften: howOften]];
            END
          ELSE Message["Won't Poke Watchdog timer"L];
          END;
        ENDCASE => ERROR;
      ENDLOOP;
    Indirect.Close[cmFile];
    END;


  Poker: PROCEDURE [howLong, howOften: CARDINAL] =
    BEGIN
    b: Buffer.Buffer;
    p: PupDefs.Buffer;
    temp: PupDefs.PupAddress ← PupDefs.UniqueLocalPupAddress[NIL];
    pup: PupDefs.PupSocket ← PupDefs.PupSocketMake[
      temp.socket, temp, PupDefs.veryShortWait, [0,0]];
    ticks: Process.Ticks = Process.SecondsToTicks[howOften];
    family: Protocol1.Family = Protocol1.GetFamilyUnit[pup];  --better not be null
    Process.SetPriority[Process.priorityBackground];
    DO
      -- Check for Buffer Lockup
      UNTIL (b ← Driver.GetInputBuffer[TRUE, family.maxBufferSize]) # NIL DO ENDLOOP;
      Buffer.ReturnBuffer[b];
      -- Check for Pup Router Lockup
      IF (p ← pup.get[]) # NIL THEN PupDefs.ReturnBuffer[p];
      Watchdog.Reactivate[howLong];
      Process.Pause[ticks];
      ENDLOOP;
    END;

  Message: PROCEDURE [one, two, three: LONG STRING ← NIL] =
    BEGIN
    text: STRING = [100];
    String.AppendString[text, one];
    IF two # NIL THEN String.AppendString[text, two];
    IF three # NIL THEN String.AppendString[text, three];
    String.AppendChar[text, '.];
    String.AppendChar[text, '\n];
    LogString[text];
    END;

  MessagePoke: PROCEDURE [one: LONG STRING, howLong, howOften: CARDINAL] =
    BEGIN
    text: STRING = [100];
    String.AppendString[text, "Poking Watchdog timer for another "L];
    String.AppendDecimal[text, howLong];
    String.AppendString[text, " seconds every "L];
    String.AppendDecimal[text, howOften];
    String.AppendString[text, " seconds.\n"L];
    LogString[text];
    END;

  LogString: PROCEDURE [text: LONG STRING] = BEGIN Put.Text[NIL, text]; END;

  FindParameters[];
  END.