-- File: VMPrivate.mesa -- Last edited by Levin: 12-Jul-82 14:57:02 DIRECTORY AltoDefs USING [MaxMDSPage], FileDefs USING [FileHandle, FSInstance, Operations, PageNumber], VMDefs USING [ CacheIndex, FileHandle, FileSystemType, OpenOptions, Page, PageAddress, PageByteIndex, PageNumber, Position, Problem]; VMPrivate: DEFINITIONS = BEGIN -- Types and Related Constants -- FileSystem: TYPE = 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, buffer: MDSPageNumber, pageStable: CONDITION, file: FileHandle, beingTaken: BOOLEAN, page: FileDefs.PageNumber, 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 = POINTER TO Object; FileHandle: TYPE = POINTER TO FileObject; PageHandle: TYPE = 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 = VMDefs.CacheIndex; nilCacheIndex: CacheIndex = 255; 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]; -- establishes initial invariant for VMCache. FinalizeVMCache: PROCEDURE; -- cleans up VMCache. InitializeVMCacheMgr: PROCEDURE [h: POINTER TO HandleTable, min, max: CacheIndex]; -- 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: MDSPageNumber, index: CacheIndex]; -- establishes a correspondance between the (MDS) '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 -- MDSPageNumber: TYPE = [0..AltoDefs.MaxMDSPage]; nilMDSPage: MDSPageNumber = 0; PageState: TYPE = {stable, unstable}; PageByte: TYPE = MACHINE DEPENDENT RECORD [p: MDSPageNumber, b: [0..255]]; 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 (MDS) address to the PageHandle for the corresponding object. HandleToAddress: PROCEDURE [page: PageHandle] RETURNS [VMDefs.Page]; -- maps a PageHandle to the (MDS) address of its corresponding buffer. AddressToMDSPage: PROCEDURE [address: POINTER] RETURNS [MDSPageNumber] = INLINE -- maps an (MDS) address to the corresponding MDSPageNumber. {RETURN[LOOPHOLE[address, PageByte].p]}; MDSPageToAddress: PROCEDURE [p: MDSPageNumber] RETURNS [POINTER] = INLINE -- maps a MDSPageNumber to the corresponding (MDS) address. {RETURN[LOOPHOLE[PageByte[p: p, b: 0]]]}; loggingEnabled: BOOLEAN; -- indicates whether statistics logging is enabled. clobberCatcherEnabled: BOOLEAN; -- indicates whether hardware write-protect is to be used to detect clobbers. WriteEnable: PROCEDURE [page: MDSPageNumber]; -- clears write-protection on the indicated page. WriteProtect: PROCEDURE [page: MDSPageNumber]; -- sets write-protection on the indicated page. END.