-- Copyright (C) 1981, 1982, 1984, 1985  by Xerox Corporation. All rights reserved. 
-- File: VMPageMgr.mesa, HGM, 17-Sep-85  0:27:06

-- Last edited by Wobber:  2-Nov-82 10:39:22
-- Last edited by Gobbel: 18-May-81 14:16:35
-- Last edited by Levin:  30-Apr-81 13:07:52

DIRECTORY
  VMDefs USING [Error, PageAddress, Page, Problem],
  VMPrivate USING [
    FileHandle, FileObject, PageHandle, PageState, WaitReason];

VMPageMgr: MONITOR IMPORTS VMDefs EXPORTS VMDefs, VMPrivate =

  BEGIN OPEN VMPrivate;


  -- This monitor synchronizes access to PageObjects by main memory address, and
  -- therefore is implicitly concerned with pages for which useCount > 0.  For this
  -- reason, the AddressToHandle mapping is assumed to be stable and can be safely used
  -- outside the cache monitor.


  -- Procedures and Signals Exported to VMDefs --

  FileObject: PUBLIC TYPE = VMPrivate.FileObject;

  CantReadBackingStore: PUBLIC ERROR [badAddress: VMDefs.PageAddress] = CODE;

  CantWriteBackingStore: PUBLIC ERROR [
    badAddress: VMDefs.PageAddress, badPage: VMDefs.Page] = CODE;


  -- Procedures and Signals Exported to VMPrivate --

  InitializeVMPageMgr: PUBLIC PROCEDURE = {NULL};

  FinalizeVMPageMgr: PUBLIC PROCEDURE = {NULL};

  -- Synchronization --

  AcquirePage: PUBLIC ENTRY PROCEDURE [page: PageHandle] =
    BEGIN
    UNTIL page.state = stable DO WAIT page.pageStable; ENDLOOP;
    page.state ← unstable;
    END;

  ReleasePage: PUBLIC ENTRY PROCEDURE [page: PageHandle] = {
    page.state ← stable; BROADCAST page.pageStable};

  WaitUntilStable: PUBLIC PROCEDURE [page: PageHandle, why: WaitReason]
    RETURNS [PageState] =
    BEGIN
    outcome: VMDefs.Problem ← ok;

    GetOutcome: ENTRY PROCEDURE [page: PageHandle] = INLINE
      -- waits until page is in an acceptable state as required by 'why'.
      BEGIN
      IF why = reading AND page.dirty THEN RETURN;  -- writing underway; reading ok
      UNTIL page.state = stable DO WAIT page.pageStable; ENDLOOP;
      IF (outcome ← page.errorStatus) = other THEN page.state ← unstable;
      END;

    GetOutcome[page];
    SELECT outcome FROM
      ok => RETURN[stable];
      other => RETURN[unstable];  -- neverStarted
      io =>
        SELECT why FROM
          reading => ERROR CantReadBackingStore[[page.file, page.page]];
          writing =>
            ERROR CantWriteBackingStore[
              [page.file, page.page], page.pointer];
          ENDCASE;
      ENDCASE;
    ERROR VMDefs.Error[outcome]
    END;

  END.