-- [Indigo]<Grapevine>VM>VMDefs.mesa

-- Transport Mechanism - DEFS for simulated virtual memory --

-- Andrew Birrell   8-Feb-80 10:29 --
-- Roy Levin      2-Nov-81 16:07:14 --


VMDefs: DEFINITIONS =

  BEGIN


  -- Types --

  CacheIndex: TYPE = [0..256);
  -- implementation limit on number of pages in cache.

  Page: TYPE = POINTER TO PageContents;
  PageContents: TYPE = RECORD [
    SELECT OVERLAID * FROM
      words => [words: ARRAY PageIndex OF WORD],
      bytes => [bytes: PACKED ARRAY PageByteIndex OF [0..256)],
      chars => [chars: PACKED ARRAY PageByteIndex OF CHARACTER],
      ENDCASE];

  PageNumber: TYPE = [0..LAST[CARDINAL]);
  -- PageNumber = 0 for the first data page of a file.
  -- Note:  Notwithstanding this declaration, the implementation limits the maximum
  -- value of PageNumber to be 77777B.

  pageSize: CARDINAL = 256;
  -- the maximum number of words in a data page.

  pageByteSize: CARDINAL = 512;
  -- the maximum number of bytes in a data page.

  PageIndex: TYPE = [0..pageSize);
  -- PageIndex = 0 for the first data word of a page of a file.

  PageByteIndex: TYPE = [0..pageByteSize);
  -- PageByteIndex = 0 for the first data byte of a page of a file.

  PageAddress: TYPE = RECORD [file: FileHandle, page: PageNumber];

  FullAddress: TYPE = RECORD [page: PageAddress, word: PageIndex];
  -- Defines a data word within a file; the earliest data word occurs at page=0, word=0.

  Position: TYPE = RECORD [page: PageNumber, byte: PageByteIndex];
  -- Defines a data byte index within a file; the earliest data byte occurs at page=0,
  -- byte=0.


  -- Global control --

  InitializeVM: PROCEDURE [min, max: CacheIndex, numOps: CARDINAL ← 20];
  -- Specifies number of pages to be allowed in cache; number may be reduced from in
  -- response to requests for storage for other reasons, but will not be allowed to drop
  -- below min.  "numOps" is the maximum number of (local) disk operations that can be
  -- in progress simultaneously.  This must be called before any other procedure in
  -- VMDefs. It is assumed that during InitializeVM no attempt is made to access
  -- other procedures of the virtual memory system.

  FinalizeVM: PROCEDURE;
  -- Tidies up and shuts down the virtual memory system.  If any files remain open,
  -- an error is raised.  It is assumed that during FinalizeVM no attempt is made to
  -- access other procedures of the virtual memory system.


  -- File system access --

  FileSystemType: TYPE = {Alto, IFS, Juniper};

  FileSystem: TYPE = POINTER TO FSInstance;
  FSInstance: TYPE;

  FSAlto: FileSystem = NIL;

  Login: PROCEDURE [system: FileSystemType,
    server, userName, password, secondaryName, secondaryPassword: STRING ← NIL]
    RETURNS [FileSystem];
  -- Initiates activity with a file system of the indicated sort using the indicated
  -- server, and supplies user's credentials.  The FileSystem returned
  -- is subsequently supplied to OpenFile to identify the file system (see below).
  -- The precise semantics of this procedure are file system dependent:
  --   Alto	This operation has no effect and can be omitted.
  --   IFS	Login is mandatory.  The userName and password are passed
  --		to the indicated server (which cannot be defaulted) for validation.
  --   Juniper	Login is mandatory.  The userName and password are passed to the
  --		indicated server (or nearest one, if defaulted) for validation.  If
  --		the login attempt succeeds, the FileSystem returned implicitly
  --		identifies a transaction under which subsequent file operations will
  --		be performed.  It is permissable to have multiple FileSystems for
  --		Juniper, which represent multiple transactions.

  UnableToLogin: ERROR [reason: Problem];
  -- raised by Login.

  Logout: PROCEDURE [FileSystem];
  -- Terminates activity with the indicated file system.  The precise semantics of
  -- this procedure are file system dependent:
  --    Alto	This operation has no effect and can be omitted.
  --    IFS	All files must previously have been closed.
  --    Juniper	An implicit CheckpointTransaction occurs.
  -- After Logout, the FileSystem is no longer valid and must not be reused.

  Error: ERROR [reason: Problem];
  -- Error conditions that are largely independent of the specific operation are
  -- reported by this signal.  It can be raised by any of the file system access
  -- procedures defined in this interface or by ReadPage, Wait, StartWait, or
  -- MarkStartWait.  The state of open files on the file system's backing store is
  -- file system dependent; local (cached) pages of the files are unaffected.  The
  -- appropriate recovery strategy depends upon the specific problem; see below.

  Problem: TYPE = {ok, io, resources, credentials, other};
  -- The general interpretations of these problems are as follows:
  --    ok		(For internal convenience; never actually raised).
  --    io		An I/O failure has occurred.  For the local (Alto) file system,
  --			this indicates an unrecoverable disk error.  For remote file
  --			systems, a communication failure or other problem (e.g., server
  --			crash) has rendered the file system unavailable.  The use of
  --			AbandonFile to cleanup after this error is encouraged; in
  --			particular, subsequent page access operations (with certain
  --			explicitly noted exceptions, e.g., UsePage), CloseFile, or
  --			AbandonFile are likely to raise this signal again.
  --    resources	The file system cannot perform the requested operation because
  --			of some sort of resource constraint.  For the local (Alto) file
  --			system, this indicates the disk is full.  For remote file
  --			systems, a storage quota may have been reached, or the storage
  --			resource may have been exhausted.
  --    credentials	The file system has rejected the requested operation on the
  --			basis of access controls.  The credentials presented at Login
  --			time were insufficient to permit the attempted operation.
  --	other		This is a placeholder whose meaning is not specified.

  CheckpointTransaction: PROCEDURE [FileSystem];
  -- If the argument FileSystem does not identify a Juniper file system, this operation
  -- has no effect.  Otherwise, the caller is suspended until all previously initiated
  -- writes completed, at which time they become committed.  The underlying transaction
  -- remains valid, and open files remain open.

  AbortTransaction: PROCEDURE [FileSystem];
  -- If the argument FileSystem does not identify a Juniper file system, this operation
  -- has no effect.  Otherwise, any writes started since the last CheckpointTransaction
  -- are canceled.  Any files opened as part of this transaction are automatically
  -- closed.

  TransactionError: ERROR [reason: TransactionProblem];
  -- raised by CheckpointTransaction (and therefore implicitly by Logout).

  TransactionProblem: TYPE = {ok, aborted, brokenReadLock, other};


  -- File handling --

  FileHandle: TYPE = POINTER TO FileObject;
  FileObject: TYPE;

  Percentage: TYPE = [0..100];

  FileTime: TYPE = LONG CARDINAL;
  -- times are expressed in seconds since midnight, January 1, 1901 GMT.  Note that
  -- this is compatible with the standard Time and TimeDefs interfaces.

  defaultTime: FileTime = 0;

  OpenOptions: TYPE = {old, oldReadOnly, new, oldOrNew};
  -- defines how a file will be opened, as follows:
  --  old - file must exist, read/write/append
  --  oldReadOnly - file must exist, only read allowed
  --  new - file must not exist, read/write/append
  --  oldOrNew - created if needed, read/write/append

  OpenFile: PROCEDURE [
    system: FileSystem ← FSAlto, name: STRING, options: OpenOptions ← oldReadOnly,
    cacheFraction: Percentage ← 0]
    RETURNS [FileHandle];
  -- the file 'name' is assumed to be interpretable by the FileSystem 'system', which
  -- is requested to open the file under the conditions specified by 'options'.
  -- 'cacheFraction' suggests the proportion of the cache that should be allocated
  -- for this file.

  CantOpen: ERROR [reason: AccessFailure];
  -- raised by OpenFile.

  AccessFailure: TYPE =
  {ok, io, notFound, alreadyExists, accessDenied, illegalFileName, other};
  -- 'ok' and 'io' are for internal use only; they are never actually raised.
  -- 'notFound' applies if 'options' is either 'old' or 'oldReadOnly' and the file
  -- cannot be found.  'alreadyExists' applies if 'options' is 'new' and the file
  -- already exists.  'accessDenied' applies if granting access would violate
  -- the file system's guarantees of protection or file integrity.  (This may
  -- mean that the file is temporarily unavailable or that the file system
  -- considers the credentials supplied by Login and 'options' to be incompatible.)
  -- 'illegalFileName' applies if the file system rejects the file name on
  -- syntactic grounds.

  GetOpenFileParameters: PROCEDURE [FileHandle]
    RETURNS [system: FileSystem, options: OpenOptions, cacheFraction: Percentage];
  -- returns the values of the indicated parameters supplied at OpenFile time.

  CloseFile: PROCEDURE [FileHandle];
  -- The FileHandle will no longer be used.  An error will be raised if any unreleased
  -- pages remain for this file.  Calls StartFile followed by WaitFile.

  GetFileSystem: PROCEDURE [file: FileHandle] RETURNS [FileSystem] =
  -- returns the 'system' argument supplied to OpenFile at the time that it returned
  -- the indicated FileHandle.
    INLINE {RETURN[GetOpenFileParameters[file].system]};

  DestroyFile: PROCEDURE [FileHandle];
  -- Calls CloseFile, then deletes the file from the file system.

  AbandonFile: PROCEDURE [FileHandle];
  -- The FileHandle will no longer be used.  Any unreleased pages of the file will
  -- be forcibly released.  Dirty pages in the cache are not guaranteed to
  -- reach the backing file.  This procedure is intended to be used to clean up after
  -- Error[io] has been raised.

  GetFileLength: PROCEDURE [FileHandle] RETURNS [Position];
  -- Returns the page and byte number of the byte one beyond the last byte of the file.
  -- For an empty file, this is [0, 0]; for a file with 512 data bytes, this is [1, 0];
  -- for a file with 612 data bytes, this is [1, 100].

  SetFileLength: PROCEDURE [file: FileHandle, position: Position];
  -- Sets the length of the file such that the Position argument refers to the byte
  -- one beyond the last byte of the file.  SetFileLength performs atomic extension of
  -- the file if the new length implies a transfer of at most one page and the data
  -- for the extension is present in the cache.  Otherwise, if the file is implicitly
  -- lengthened, new bytes have undefined content.

  StartFile: PROCEDURE [FileHandle];
  -- Initiates transfers for all pages of the file marked as dirty in the cache.

  WaitFile: PROCEDURE [FileHandle];
  -- The caller is suspended until all previously initiated transfers on this file
  -- have completed.  This call may raise the signal CantWriteBackingStore.

  GetFileTimes: PROCEDURE [file: FileHandle]
    RETURNS [read, write, create: FileTime];
  -- returns the associated times for the given file.

  SetCreationTime: PROCEDURE [file: FileHandle, create: FileTime ← defaultTime];
  -- sets the creation time for the indicated file.  If the time is defaulted, it is
  -- set to the current time.



  -- Access to pages --

  -- The following procedures provide a means of accessing files similar to that
  -- available in an integrated virtual memory.  While a page of the virtual memory
  -- is swapped in to physical memory, it is shared by all its users.  Each page is
  -- locked in physical memory while anyone is using it.  Anyone altering the contents
  -- of a page must notify this fact before releasing the page.

  -- If the page being manipulated is associated with a file that is part of a
  -- transaction, then operations that write the page to the file do not become
  -- permanent until the transaction is "committed" (see CheckpointTransaction and
  -- Logout, above).  The comments below define the moment of committal for
  -- pages in files that are not part of a transaction, which includes all files on the
  -- local Alto disk.

  LookAheadCount: TYPE = CacheIndex;

  ReadPage: PROCEDURE [addr: PageAddress, lookAhead: LookAheadCount ← 0]
    RETURNS [Page];
  -- Read specified page, waiting until the contents are available, and possibly
  -- initiating read-ahead.  The memory is allocated by the virtual memory system, and
  -- is available to the caller until he calls ReleasePage with this page.  Multiple
  -- users of the same page receive the same 'Page' value.   Reading beyond the end
  -- of the file is not allowed.  If an unrecoverable error has occurred when reading
  -- the data from the file, and has not been cleared (see UsePage), the signal
  -- CantReadBackingStore is raised.

  StartReading: PROCEDURE [addr: PageAddress, lookAhead: LookAheadCount ← 0];
  -- Initiates reading the specified page, and "lookAhead" extra pages.  addr.page
  -- may legitimately fall in the range [0..filesize).

  UsePage: PROCEDURE [addr: PageAddress] RETURNS [Page];
  -- Return specified page, but its contents are undefined; no read operation occurs.
  -- The memory is allocated by the virtual memory system, and is available to the
  -- caller until he calls ReleasePage with this page.  Multiple users of the same page
  -- receive the same 'Page' value.   addr.page may legitimately fall in the range
  -- [0..filesize].  This call clears any unrecoverable errors which had previously
  -- occurred when reading the data for this page from the file.

  AllocatePage: PROCEDURE RETURNS [Page];
  -- Allocate page in memory with undefined contents.  The memory is allocated by the
  -- virtual memory system, and is available to the caller until he calls ReleasePage
  -- with this page.  Before this page can passed to MarkStart or MarkStartWait, it must
  -- be associated with an address by passing it to RemapPage.

  RemapPage: PROCEDURE [page: Page, addr: PageAddress];
  -- The given page is now to be considered as the contents of the address "addr".  It
  -- is required that there be no other user of "page", and that there be no user of
  -- "addr".  addr.page may legitimately fall in the range [0..filesize].  This call
  -- clears any unrecoverable errors which had previously occurred when reading the data
  -- for "addr" from the file.

  UnmapPage: PROCEDURE [Page];
  -- The given page is disassociated from any backing storage.  It is required that
  -- there be no other user of the argument Page.

  PageInCache: PROCEDURE [PageAddress] RETURNS [BOOLEAN];
  -- This procedure permits clients to optimize performance by testing whether a ReadPage
  -- of the argument PageAddress is likely to be fast.  A TRUE result from this procedure
  -- means a subsequent ReadPage will probably not require physical I/O.

  Mark: PROCEDURE [Page];
  -- The contents of the given page have been altered.  If the page is associated
  -- with a backing file page and is subsequently removed from the in-core cache, the
  -- new data will be written to the file.  The implicitly associated PageNumber must be
  -- in the range [0..filesize).  It is an error to invoke this operation on a page
  -- that is associated with a read-only file.

  MarkStart: PROCEDURE [Page];
  -- The contents of the given page have been altered and are to be written to the
  -- associated page of backing file (it is an error to perform this operation on a page
  -- that has no backing storage).  MarkStart initiates the transfer of the data
  -- to the file, but does not wait for it to complete.  The implicitly associated
  -- PageNumber may legitimately fall in the range [0..filesize].  If it equals
  -- filesize, the file is implicitly extended during this call, although this fact may
  -- not yet be recorded on stable storage.  It is an error to invoke this operation
  -- on a page that is associated with a read-only file.

  MarkStartWait: PROCEDURE [Page];
  -- The contents of the given page have been altered and are to be written to the
  -- associated page of backing file (it is an error to perform this operation on a page
  -- that has no backing storage).  MarkStartWait initiates the transfer of the data
  -- to the file, and waits for it to complete.  The implicitly associated
  -- PageNumber may legitimately fall in the range [0..filesize].  If it equals
  -- filesize, the file is implicitly extended during this call.  This call may raise
  -- the signal CantWriteBackingStore.  It is an error to invoke this operation
  -- on a page that is associated with a read-only file.

  Start: PROCEDURE [Page];
  -- If the contents of the given page have been marked as dirty, Start initiates the
  -- transfer of the data to the file (it is an error to perform this operation on a
  -- page that has no backing storage).  The implicitly associated PageNumber may
  -- legitimately fall in the range [0..filesize].  If it equals filesize, the file is
  -- implicitly extended during this call.

  StartWait: PROCEDURE [Page];
  -- If the contents of the given page have been marked as dirty, StartWait initiates
  -- the transfer of the data to the file, and wait for it to complete (it is an error
  -- to perform this operation on a page that has no backing storage).  The implicitly
  -- associated PageNumber may legitimately fall in the range [0..filesize].  If it
  -- equals filesize, the file is implicitly extended during this call.  This call may
  -- raise the signal CantWriteBackingStore.

  Wait: PROCEDURE [Page];
  -- If a transfer of the data to the file has previously been initiated, then wait
  -- for it to complete.  This call may raise the signal CantWriteBackingStore.

  Release: PROCEDURE [Page];
  -- The caller is no longer reading or writing the page of memory indicated, although
  -- others may be doing so.  The data contents of the page are preserved, although
  -- they are not necessarily written to the file unless MarkStart or MarkStartWait has
  -- previously been called for this page.

  Deactivate: PROCEDURE [Page];
  -- This operation is logically equivalent to Release, but additionally suggests to
  -- the implementation that the argument Page be removed from the in-core cache.
  -- Deactivate can produce better cache performance during extended "streaming"
  -- operations.

  PageToPageAddress: PROCEDURE [Page] RETURNS [PageAddress];
  -- delivers the PageAddress corresponding to Page.  The page must be associated with
  -- a backing storage location.


  -- Errors --

  CantWriteBackingStore: ERROR [badAddress: PageAddress, badPage: Page];
  -- the data for this page could not be written to the file, because of persistent
  -- errors;  this is raised if the user waits for the page to reach the file.

  CantReadBackingStore: ERROR [badAddress: PageAddress];
  -- the data for this page could not be read from the file; this is raised whenever
  -- the user asks for the data (see ReadPage and UsePage).

  END.