-- File: VMControl.mesa
-- Last edited by Levin:  12-Apr-83 11:30:16
-- Last edited by Taft:  April 19, 1983  5:01 PM

DIRECTORY
  DiskIODefs USING [InitializeDiskIO, FinalizeDiskIO],
  FrameDefs USING [IsBound],
  ImageDefs USING [
    AddCleanupProcedure, AllReasons, CleanupItem, CleanupProcedure,
    RemoveCleanupProcedure],
  LogDefs USING [DisplayNumber],
  Map USING [Clean, SETF, WriteProtected],
  SegmentDefs USING [MachineType, memConfig],
  VMSpecial USING [],
  VMStorage USING [InitializeStorage, FinalizeStorage, longTerm],
  VMDefs USING [CacheIndex],
  VMPrivate USING [
    FinalizeVMCache, FinalizeVMFile, FinalizeVMIO, FinalizeVMPageMgr,
    InitializeVMCache, InitializeVMFile, InitializeVMIO, InitializeVMPageMgr,
    maxLookAhead, MDSPageNumber];

VMControl: PROGRAM
  IMPORTS
    DiskIODefs, FrameDefs, ImageDefs, LogDefs, Map, SegmentDefs, VMPrivate, VMStorage
  EXPORTS VMDefs, VMPrivate, VMSpecial
  SHARES DiskIODefs, VMSpecial, VMStorage =

  BEGIN OPEN VMPrivate;


  -- Procedures and Variables Exported to VMDefs --

  InitializeVM: PUBLIC PROCEDURE [
    min, max: VMDefs.CacheIndex, numOps: CARDINAL ← 20] =
    BEGIN
    loggingEnabled ← FrameDefs.IsBound[LogDefs.DisplayNumber];
    VMStorage.InitializeStorage[];
    InitializeClobberCatcher[];
    maxLookAhead ← DiskIODefs.InitializeDiskIO[minOps: numOps] - 1;
    InitializeVMIO[];
    InitializeVMPageMgr[];
    InitializeVMCache[min, max];
    InitializeVMFile[max];
    END;

  FinalizeVM: PUBLIC PROCEDURE =
    BEGIN
    FinalizeVMFile[];
    FinalizeVMCache[];
    FinalizeVMPageMgr[];
    FinalizeVMIO[];
    DiskIODefs.FinalizeDiskIO[];
    FinalizeClobberCatcher[];
    VMStorage.FinalizeStorage[];
    END;

  -- Procedures and Variables Exported to VMSpecial --

  DisableClobberCatcher: PUBLIC PROCEDURE = FinalizeClobberCatcher;

  -- Procedures and Variables Exported to VMPrivate --

  loggingEnabled: PUBLIC BOOLEAN;

  clobberCatcherEnabled: PUBLIC BOOLEAN;
  
  RealWriteEnable: PUBLIC PROCEDURE [page: MDSPageNumber] =
    BEGIN
    IF ~clobberCatcherEnabled THEN RETURN;
    wpTable[page] ← FALSE;
    [] ← Map.SETF[page, Map.Clean];
    END;

  RealWriteProtect: PUBLIC PROCEDURE [page: MDSPageNumber] =
    BEGIN
    IF ~clobberCatcherEnabled THEN RETURN;
    wpTable[page] ← TRUE;
    [] ← Map.SETF[page, Map.WriteProtected];
    END;

  -- Internal Procedures --

  WPTable: TYPE = PACKED ARRAY MDSPageNumber OF BOOLEAN;

  wpTable: POINTER TO WPTable;

  cleanupItem: ImageDefs.CleanupItem ←
    [link: , mask: ImageDefs.AllReasons, proc: Cleanup];

  InitializeClobberCatcher: PROCEDURE =
    BEGIN
    clobberCatcherEnabled ←
      SegmentDefs.memConfig.AltoType IN SegmentDefs.MachineType[D0..Dorado];
    IF ~clobberCatcherEnabled THEN RETURN;
    wpTable ← VMStorage.longTerm.NEW[WPTable ← ALL[FALSE]];
    ImageDefs.AddCleanupProcedure[@cleanupItem];
    END;

  FinalizeClobberCatcher: PROCEDURE =
    BEGIN
    IF ~clobberCatcherEnabled THEN RETURN;
    ImageDefs.RemoveCleanupProcedure[@cleanupItem];
    -- If we are being called from VM finalization, nothing should be
    -- write-protected at this point.  However, if we are being called
    -- through our alias, DisableClobberCatcher, the following is needed.
    Cleanup[OutLd];
    VMStorage.longTerm.FREE[@wpTable];
    clobberCatcherEnabled ← FALSE;
    END;

  Cleanup: ImageDefs.CleanupProcedure =
    BEGIN
    SELECT why FROM
      Finish, Abort => FinalizeClobberCatcher[];
      OutLd, Save, Checkpoint =>
        FOR i: MDSPageNumber IN MDSPageNumber DO
          IF wpTable[i] THEN [] ← Map.SETF[i, Map.Clean];
          ENDLOOP;
      InLd, Restore, Restart =>
        FOR i: MDSPageNumber IN MDSPageNumber DO
          IF wpTable[i] THEN [] ← Map.SETF[i, Map.WriteProtected];
          ENDLOOP;
      ENDCASE;
    END;

  END.