-- File: MDSWatcher.mesa
-- Last edited by Levin:  10-Sep-80 18:46:53
-- Andrew Birrell  16-Oct-80 18:30:01

DIRECTORY
  LogDefs	USING [DisplayNumber],
  ProcessDefs	USING [Detach, Pause, SecondsToTicks],
  ProcessOps	USING[ FirstProcess, LastProcess ],
  PSBDefs	USING[ ProcessHandle, PSB ],
  SegmentDefs	USING [SegmentHandle],
  SwapperOps	USING [Page, PageMap, PageStatus, Status, systemTable];

MDSWatcher: PROGRAM
  IMPORTS LogDefs, ProcessDefs, SwapperOps =

  BEGIN OPEN SwapperOps;

  pageMap: PageMap = systemTable.mdsMap;

  Init: PROCEDURE =
    BEGIN
    availablePages ← 0;
    availablePSBs ← 0;
    LogDefs.DisplayNumber["Free MDS"L, [short[@availablePages]]];
    LogDefs.DisplayNumber["Free PSBs"L, [short[@availablePSBs]]];
    END;

  WatchMDS: PROCEDURE =
    BEGIN
    DO
      available: CARDINAL ← 0;
      page: CARDINAL ← FIRST[Page];
      UNTIL page > LAST[Page] DO
	seg: SegmentDefs.SegmentHandle;
	status: PageStatus;
	inc: CARDINAL ← 1;
	[seg, status] ← Status[page];
	SELECT status FROM
	  inuse =>
	    WITH s: seg SELECT FROM
	      file =>
		{inc ← s.pages; IF s.lock = 0 THEN available ← available + s.pages};
	      data => inc ← s.pages;
	      ENDCASE;
	  busy => NULL;
	  free => available ← available + 1;
	  ENDCASE;
	page ← page + inc;
	ENDLOOP;
      availablePages ← available;

      available ← 0;
      FOR p: PSBDefs.ProcessHandle ← ProcessOps.FirstProcess↑,
                 p + SIZE[PSBDefs.PSB]
      UNTIL p = ProcessOps.LastProcess↑
      DO IF p.state = dead THEN available ← available+1; ENDLOOP;
      availablePSBs ← available;

      ProcessDefs.Pause[ProcessDefs.SecondsToTicks[60]];
    ENDLOOP;
    END;

  availablePages: CARDINAL;
  availablePSBs:  CARDINAL;

  Init[];
  ProcessDefs.Detach[FORK WatchMDS[]];

  END.