-- File: VMStorageMgr.mesa
-- Last edited by Levin:  12-Apr-83 13:26:33

DIRECTORY
  AllocDefs USING [
    AddSwapStrategy, RemoveSwapStrategy, SwappingProcedure, SwapStrategy,
    TryCodeSwapping],
  DynamicZone USING [CreateZone, DestroyZone, FinalizeZones, InitializeZones],
  SegmentDefs USING [
    DataSegmentAddress, DataSegmentHandle, DataSegmentType, DefaultMDSBase,
    DeleteDataSegment, HardDown, InsufficientVM, MakeDataSegment, VMtoDataSegment],
  VMSpecial USING  [PruneCache],
  VMStorage USING [];

VMStorageMgr: PROGRAM
  IMPORTS AllocDefs, DynamicZone, SegmentDefs, VMSpecial
  EXPORTS VMStorage =

  BEGIN


  -- Types and Related Constants --

  PageBuffer: TYPE = RECORD [link: PagePointer, rest: ARRAY [1..255] OF WORD];

  PagePointer: TYPE = POINTER TO PageBuffer;

  ListState: TYPE = {stable, unstable};


  -- Global Variables --

  swap: AllocDefs.SwapStrategy;

  -- Miscellaneous Declarations --

  vmMiscDS: SegmentDefs.DataSegmentType = 73B;

  NoMemory: ERROR [needed: CARDINAL] = CODE;


  -- Procedures and Variables Exported to VMStorage --

  -- Node-Level Allocator --

  longTerm, shortTerm: PUBLIC MDSZone;

  -- Page-Level Allocator --

  AllocatePage: PUBLIC PROCEDURE RETURNS [POINTER] =
    -- allocates a single page of main memory, returning its address.
    BEGIN OPEN SegmentDefs;
    page: PagePointer;
    seg: DataSegmentHandle =
      MakeDataSegment[DefaultMDSBase, 1, HardDown
				! InsufficientVM => ERROR NoMemory[needed]];
    seg.type ← vmMiscDS;
    page ← LOOPHOLE[DataSegmentAddress[seg]];
    RETURN[page]
    END;

  FreePage: PUBLIC PROCEDURE [p: POINTER] =
    -- releases the single page beginning at 'p'.
    BEGIN OPEN SegmentDefs;
    DeleteDataSegment[VMtoDataSegment[p]];
    END;

  InitializeStorage: PUBLIC PROCEDURE =
    -- initializes the main memory allocator.
    BEGIN
    InitializePageLevel[];
    InitializeNodeLevel[];
    END;

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


  -- Internal Procedures --

  -- Node-Level Allocator --

  InitializeNodeLevel: PROCEDURE =
    BEGIN OPEN DynamicZone;
    InitializeZones[];
    longTerm ← CreateZone[id: "VM long term"L];
    shortTerm ← CreateZone[id: "VM short term"L];
    END;

  FinalizeNodeLevel: PROCEDURE =
    BEGIN OPEN DynamicZone;
    DestroyZone[shortTerm];
    DestroyZone[longTerm];
    FinalizeZones[];
    END;


  -- Page-Level Allocator --

  InitializePageLevel: PROCEDURE =
    BEGIN
    swap.proc ← FlushList;
    AllocDefs.AddSwapStrategy[@swap];
    END;

  FinalizePageLevel: PROCEDURE =
    BEGIN
    AllocDefs.RemoveSwapStrategy[@swap];
    END;

  FlushList: AllocDefs.SwappingProcedure =
    -- try to help the swapper out.
    BEGIN
    IF AllocDefs.TryCodeSwapping[needed, info, seg] THEN RETURN[TRUE];
    RETURN[VMSpecial.PruneCache[needed]]
    END;

  END.