-- Copyright (C) 1982, 1984, 1985  by Xerox Corporation. All rights reserved. 
-- VMPrivate.mesa, HGM, 17-Sep-85  2:05:08

-- Last edited by Wobber:  2-Nov-82 12:02:41
-- Last edited by Levin:  12-Jul-82 14:57:02

DIRECTORY
  FileDefs USING [FileHandle, FSInstance, Operations],
  VMDefs USING [
    FileHandle, FileSystemType, OpenOptions, Page, PageAddress,
    PageByteIndex, PageNumber, Position, Problem];

VMPrivate: DEFINITIONS =

  BEGIN


  -- Types and Related Constants --

  FileSystem: TYPE = LONG POINTER TO FSInstance;

  FSInstance: TYPE = RECORD [
    ops: FileDefs.Operations, instance: FileDefs.FSInstance];

  ObjectType: TYPE = {page, file};

  Object: TYPE = RECORD [
    body: SELECT tag: ObjectType FROM
      file => [
        seal: VMFileSeal,
        useCount: CacheIndex,
        link: FileHandle,
        fh: FileDefs.FileHandle,
        fs: FileSystem,
        cachePages: CacheIndex,
        options: VMDefs.OpenOptions,
        altoFile: BOOLEAN,
        openCount: [0..37B] ],  -- pick a convenient size based on size of other fields
      page => [
        state: PageState,
        age: LRUInfo,
        dirty: BOOLEAN,
        recordNextVda: BOOLEAN,
        errorStatus: VMDefs.Problem,
        pageStable: CONDITION,
        file: FileHandle,
        beingTaken: BOOLEAN,
        page: VMDefs.PageNumber,
	pointer: VMDefs.Page,
	index: PageIndex,
        hashLink: CacheIndex,
        useCount: [0..377B] ],  -- pick a convenient size based on size of other fields
      ENDCASE];

  FileObject: TYPE = file Object;
  PageObject: TYPE = page Object;

  ObjectHandle: TYPE = LONG POINTER TO Object;
  FileHandle: TYPE = LONG POINTER TO FileObject;
  PageHandle: TYPE = LONG POINTER TO PageObject;


  -- File Operations --

  fsOps: ARRAY VMDefs.FileSystemType OF FileDefs.Operations;

  Writable: PROCEDURE [file: FileHandle] RETURNS [BOOLEAN] = INLINE {
    RETURN[file.options ~= oldReadOnly]};


  -- Cache Management --

  -- Types and Related Constants --

  CacheIndex: TYPE = [0..256);
  nilCacheIndex: CacheIndex = CacheIndex.LAST;
  
  maxPageIndex: CARDINAL = 50;
  PageIndex: TYPE = [0..maxPageIndex);

  HandleTable: TYPE = RECORD [SEQUENCE nHandles: CacheIndex OF PageHandle];

  LRUInfo: TYPE = {old, new};

  PageByteCount: TYPE =
    [FIRST[VMDefs.PageByteIndex] + 1..LAST[VMDefs.PageByteIndex] + 1];

  -- Procedures and Signals --

  InitializeVMCache: PROCEDURE [min, max: CacheIndex, first: LONG POINTER];
  -- establishes initial invariant for VMCache.

  FinalizeVMCache: PROCEDURE;
  -- cleans up VMCache.

  InitializeVMCacheMgr: PROCEDURE [
    h: LONG POINTER TO HandleTable, min, max: CacheIndex, first: LONG POINTER];
  -- establishes initial invariant for VMCacheMon.

  FinalizeVMCacheMgr: PROCEDURE;
  -- cleans up VMCacheMon.

  AcquireCache: PROCEDURE;
  -- waits for the cache to become stable, marks it unstable, and returns.

  ReleaseCache: PROCEDURE;
  -- resets the cache to a stable state (and awakens anyone waiting for it).

  AllocateCacheIndex: PROCEDURE RETURNS [CacheIndex];
  -- allocates a slot in the cache and returns its CacheIndex.  This index will
  -- correspond to an allocated page object with page.state = unstable,
  -- page.useCount = 0, page.buffer ~= nilMDSPage, and page.pageStable initialized,
  -- but whose remaining fields are undefined.

  IndexToHandle: PROCEDURE [index: CacheIndex] RETURNS [PageHandle];
  -- maps a CacheIndex to the PageHandle for the corresponding object.

  LookupInHashTable: PROCEDURE [addr: VMDefs.PageAddress]
    RETURNS [index: CacheIndex];
  -- looks up the given address to discover whether there exists a corresponding
  -- page already in the cache.  If so, its CacheIndex is returned, if not,
  -- nilCacheIndex is returned.

  EnterInHashTable: PROCEDURE [page: PageHandle];
  -- enters the given page into the hash table.

  EnterInPageTable: PROCEDURE [page: PageHandle, index: CacheIndex];
  -- establishes a correspondance between the 'page' and slot 'index' in
  -- the cache.

  RemovePageFromTables: PROCEDURE [page: PageHandle];
  -- eliminates 'page' from the mapping tables, and disassociates it from its file.

  EnumerateCachePagesInFile: PROCEDURE [
    file: VMDefs.FileHandle,
    proc: PROCEDURE [page: PageHandle] RETURNS [found, unmap: BOOLEAN]]
    RETURNS [BOOLEAN];
  -- enumerates all cache slots containing pages belonging to 'file'.  If 'proc'
  -- returns 'unmap' = TRUE, RemovePageFromTables will be called (providing that
  -- there are no other users of the page.  If 'found' = TRUE, the enumeration
  -- terminates.  Note: This procedure supplies its own cache mutual exclusion.


  -- Page Management --

  -- Types and Related Constants --

  PageState: TYPE = {stable, unstable};

  WaitReason: TYPE = {reading, writing};

  -- Procedures and Signals --

  InitializeVMPageMgr: PROCEDURE;
  -- establishes initial invariant for VMPageMon.

  FinalizeVMPageMgr: PROCEDURE;
  -- cleans up VMPageMon.

  AcquirePage: PROCEDURE [page: PageHandle];
  -- waits for 'page' to become stable, marks it unstable, and returns.

  ReleasePage: PROCEDURE [page: PageHandle];
  -- resets 'page' to a stable state (and awakens anyone waiting for it).

  WaitUntilStable: PROCEDURE [page: PageHandle, why: WaitReason]
    RETURNS [PageState];
  -- waits for the argument page to become stable, potentially reporting transmission
  -- errors.  If the return value is 'stable', 'page' is stable and the previous
  -- transfer completed successfully.  If the return value is 'unstable', 'page' is
  -- unstable (i.e., an implicit AcquirePage has been done) and the previous transfer
  -- was never started (i.e., the DiskIODefs.CompletionStatus was 'neverStarted').  If
  -- the previous transfer had a permanent transmission error, either
  -- VMDefs.CantReadBackingStore (if why = reading) or VMDefs.CantWriteBackingStore
  -- (if why = writing) is raised.

  ValidatePageAddress: PROCEDURE [page: PageHandle]
    RETURNS [extending: BOOLEAN, newLength: VMDefs.Position];
  -- ensures that page.addr is reasonable for page.file.


  -- I/O Management --

  InitializeVMIO: PROCEDURE;
  -- initializes the I/O handling routines.

  FinalizeVMIO: PROCEDURE;
  -- finalizes the I/O handling routines.

  WritePageToFS: PROCEDURE [page: PageHandle, wait: BOOLEAN];
  -- initiates a write to the file system of 'page'.  page.state is assumed to be
  -- unstable and remains so while the transfer is underway.  If 'wait' is TRUE,
  -- WritePageToFS will wait until the write operation completes before returning,
  -- at which time the page will be placed in the 'stable' state.  If 'wait' if FALSE,
  -- WritePageToFS returns immediately after initiating the operation.  The page is
  -- marked clean (i.e., page.dirty becomes FALSE) when the write completes
  -- successfully.




  -- File Manipulation --

  -- Types and Related Constants --

  VMFileSeal: TYPE = [0..77B];

  openSeal: VMFileSeal = 51B;
  underwaySeal: VMFileSeal = 35B;
  closedSeal: VMFileSeal = 26B;

  -- Procedures and Signals --

  InitializeVMFile: PROCEDURE [maxCachePages: CacheIndex];
  -- establishes initial invariant for VMFile.

  FinalizeVMFile: PROCEDURE;
  -- cleans up VMFile.

  ValidateFile: PROCEDURE [file: VMDefs.FileHandle] = INLINE
    -- ensures that 'file' is a plausible file handle.
    {IF LOOPHOLE[file, FileHandle].seal ~= openSeal THEN ERROR InvalidFile};

  ValidatePageNumber: PROCEDURE [page: VMDefs.PageNumber] = INLINE
    -- ensures that 'page' is a plausible page number.
    {IF CARDINAL[page] > 77777B THEN ERROR InvalidPageNumber};

  InvalidFile: ERROR;
  -- raised by ValidateFile.

  InvalidPageNumber: ERROR;
  -- raised by ValidatePageNumber 

  -- Miscellaneous Procedures and Signals --

  AddressToHandle: PROCEDURE [address: VMDefs.Page] RETURNS [PageHandle];
  -- maps an address to the PageHandle for the corresponding object.

  AddressToPageIndex: PROCEDURE [address: VMDefs.Page] RETURNS [PageIndex];
  -- maps an address to the PageIndex for the corresponding object.

  clobberCatcherEnabled: BOOLEAN;
  -- indicates whether hardware write-protect is to be used to detect clobbers.

  WriteEnable: PROCEDURE [page: VMDefs.PageNumber];
  -- clears write-protection on the indicated page.

  WriteProtect: PROCEDURE [page: VMDefs.PageNumber];
  -- sets write-protection on the indicated page.

  END.