-- File: VMPageMgr.mesa
-- Last edited by Levin:  30-Oct-81 16:02:15

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

VMPageMgr: MONITOR
  IMPORTS VMDefs, VMPrivate
  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 AND page.file.altoFile THEN
	page.state ← unstable;
      END;

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

  END.