-- Copyright (C) 1981, 1982, 1984, 1985  by Xerox Corporation. All rights reserved. 
-- VMStorageMgr.mesa, HGM, 17-Sep-85  2:27:30

-- This module is just barely used, HGM, 16-Sep-85 22:20:19

--  Gobbel: 30-Sep-81 13:11:50
--  M. Johnson: 11-Jan-82 14:15:32
--  Hankins:	25-Jul-84 12:20:04	Klamath update (space rework)

DIRECTORY
  Environment USING [PageNumber],
  File USING [nullFile],
  Space USING [
    Allocate, Deallocate, Interval, LongPointerFromPage, MapAt, PageCount,
    PageFromLongPointer, PageOffset, UnmapAt, virtualMemory, wordsPerPage],
  VMPrivate USING [maxPageIndex, PageIndex],
  VMStorage USING [];

VMStorageMgr: MONITOR
  IMPORTS Space
  EXPORTS VMStorage  =

  BEGIN


  -- Types and Related Constants --

  PageIndex: TYPE = VMPrivate.PageIndex;

  AllocArray: TYPE = PACKED ARRAY PageIndex OF BOOLEAN;

  Page: TYPE = ARRAY [0..Space.wordsPerPage) OF WORD;


  -- Constants and Global Variables --

  inUse: BOOLEAN = TRUE;
  free: BOOLEAN = FALSE;

  freePageCount: Space.PageCount ← VMPrivate.maxPageIndex;
  allocMap: AllocArray ← ALL[free];
  rover: PageIndex ← 0;

  poolSpace: Space.Interval;
  storagePool: LONG POINTER TO ARRAY PageIndex OF Page;

  -- Miscellaneous Declarations --

  AllocMapBug: ERROR = CODE;
  NoMemory: ERROR = CODE;
  PageAlreadyFree: ERROR = CODE;
  UserConfused: ERROR = CODE;


  -- Page-Level Allocator --

  AllocatePage: PUBLIC ENTRY PROCEDURE RETURNS [LONG POINTER, VMPrivate.PageIndex] =
    -- allocates a single page of main memory, returning its address.
    BEGIN
    Inc: PROCEDURE [bit: PageIndex] RETURNS [PageIndex] = INLINE {
      RETURN[(bit + 1) MOD VMPrivate.maxPageIndex]};
    IF freePageCount = 0 THEN ERROR NoMemory;
    FOR i: PageIndex ← Inc[rover], Inc[i] UNTIL i = rover DO
      IF allocMap[i] = free THEN {allocMap[i] ← inUse; rover ← i; EXIT};
      REPEAT FINISHED => ERROR AllocMapBug;
      ENDLOOP;
    freePageCount ← freePageCount - 1;
    RETURN[@storagePool[rover], rover];
    END;

  FreePage: PUBLIC ENTRY PROCEDURE [p: LONG POINTER, bit: VMPrivate.PageIndex] =
    BEGIN
    IF p # @storagePool[rover] THEN ERROR UserConfused;
    IF allocMap[bit] # inUse THEN ERROR PageAlreadyFree;
    allocMap[bit] ← free;
    freePageCount ← freePageCount + 1;
    END;

  InitializeStorage: PUBLIC PROCEDURE RETURNS [LONG POINTER] =
    -- initializes the main memory allocator.
    BEGIN
    InitializePageLevel[];
    RETURN[poolSpace.pointer]
    END;

  FinalizeStorage: PUBLIC PROCEDURE =
    -- finalizes the main memory allocator.
    BEGIN FinalizePageLevel[]; END;


  -- Internal Procedures --

  -- Page-Level Allocator --

  InitializePageLevel: PROCEDURE =
    BEGIN
    firstPage: Environment.PageNumber;
    poolSpace ← Space.Allocate[count: VMPrivate.maxPageIndex, within: Space.virtualMemory];
    storagePool ← poolSpace.pointer;
    firstPage ← Space.PageFromLongPointer[poolSpace.pointer];
    FOR p: Space.PageOffset IN [0..VMPrivate.maxPageIndex) DO
      [] ← Space.MapAt[
        at: [pointer: Space.LongPointerFromPage[firstPage + p], count: 1],
        window: [file: File.nullFile, base: 0, count: 1], class: data];
      ENDLOOP;
    END;

  FinalizePageLevel: PROCEDURE =
    BEGIN
    firstPage: Environment.PageNumber ← Space.PageFromLongPointer[
      poolSpace.pointer];
    FOR p: Space.PageOffset IN [0..VMPrivate.maxPageIndex) DO
      [] ← Space.UnmapAt[pointer: Space.LongPointerFromPage[firstPage + p]];
      ENDLOOP;
    Space.Deallocate[poolSpace];
    END;

  END.