-- IntervalTimerHeadDorado.mesa
-- Last Edited by: Taft, March 31, 1983 9:12 am

DIRECTORY
  DeviceCleanup USING [Await, Item, Reason],
  DoradoInputOutput USING [SetIntervalTimer],
  HeadStartChain USING [Start],
  Inline USING [LowHalf],
  IntervalTimerFace,
  ProcessInternal USING [AllocateNakedCondition],
  ProcessOperations USING [LongNotify],
  ProcessorFace USING [GetClockPulses];

IntervalTimerHeadDorado: MONITOR
  IMPORTS DeviceCleanup, DoradoInputOutput, RemainingHeads: HeadStartChain, Inline,
    ProcessInternal, ProcessOperations, ProcessorFace
  EXPORTS HeadStartChain, IntervalTimerFace =
  BEGIN OPEN IntervalTimerFace;

  csb: LONG POINTER TO IntervalTimerCSB = LOOPHOLE[LONG[177422B]];
  IntervalTimerCSB: TYPE = RECORD [
    wakeups: WORD];

  nakedCondition: LONG POINTER TO CONDITION;

  expirationTime: ClockPulses;

  SetExpirationTime: PUBLIC PROCEDURE [time: ClockPulses] =
    BEGIN
    expirationTime ← time;
    DoradoInputOutput.SetIntervalTimer[Inline.LowHalf[expirationTime]];
    IF LOOPHOLE[ProcessorFace.GetClockPulses[] - expirationTime, INT] >= 0 THEN
      ProcessOperations.LongNotify[nakedCondition];
    END;

  Wait: PUBLIC ENTRY PROCEDURE =
    BEGIN
    DO
      WAIT nakedCondition;
      IF LOOPHOLE[ProcessorFace.GetClockPulses[] - expirationTime, INT] >= 0 THEN EXIT;
      SetExpirationTime[expirationTime];
      ENDLOOP;
    END;

  exists: PUBLIC BOOLEAN ← TRUE;

  InitializeCleanup: PROCEDURE =
    BEGIN
    item: DeviceCleanup.Item;
    reason: DeviceCleanup.Reason;
    savedCSB: IntervalTimerCSB;
    DO
      reason ← DeviceCleanup.Await[@item];
      SELECT reason FROM
	turnOff, kill =>
	  BEGIN
	  savedCSB ← csb↑;
	  csb.wakeups ← 0;
	  END;
	turnOn =>
	  BEGIN
	  csb↑ ← savedCSB;
	  SetExpirationTime[expirationTime];
	  END;
	ENDCASE
      ENDLOOP
    END;

  Start: PUBLIC PROCEDURE =
    BEGIN
    [cv: nakedCondition, mask: csb.wakeups] ← ProcessInternal.AllocateNakedCondition[];
    InitializeCleanup[];
    RemainingHeads.Start[];
    END;

  END.