-- File: VMStorageMgr.mesa -- Last edited by Levin: 25-Nov-81 14:36:35 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: MONITOR 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 -- pageList: PagePointer; listState: ListState; listStable: CONDITION; 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 page: PagePointer; GrabList[]; IF pageList = NIL THEN BEGIN OPEN SegmentDefs; seg: DataSegmentHandle; ReleaseList[]; seg ← MakeDataSegment[DefaultMDSBase, 1, HardDown ! InsufficientVM => ERROR NoMemory[needed]]; seg.type ← vmMiscDS; page ← LOOPHOLE[DataSegmentAddress[seg]]; END ELSE {page ← pageList; pageList ← page.link; ReleaseList[]}; RETURN[page] END; FreePage: PUBLIC PROCEDURE [p: POINTER] = -- releases the single page beginning at 'p'. BEGIN page: PagePointer = LOOPHOLE[p]; GrabList[]; page.link ← pageList; pageList ← page; ReleaseList[]; 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 pageList ← NIL; listState ← stable; listStable.timeout ← 0; swap.proc ← FlushList; AllocDefs.AddSwapStrategy[@swap]; END; FinalizePageLevel: PROCEDURE = BEGIN GrabList[]; AllocDefs.RemoveSwapStrategy[@swap]; UNTIL pageList = NIL DO FreeOne[]; ENDLOOP; ReleaseList[]; END; GrabList: ENTRY PROCEDURE = -- acquires exclusive access to the storage list. BEGIN UNTIL listState = stable DO WAIT listStable; ENDLOOP; listState ← unstable; END; ReleaseList: ENTRY PROCEDURE = -- relinquishes exclusive access to the storage list. {listState ← stable; NOTIFY listStable}; FlushList: AllocDefs.SwappingProcedure = -- flushes the list of free pages to try to help the swapper out. BEGIN IF AllocDefs.TryCodeSwapping[needed, info, seg] THEN RETURN[TRUE]; GrabList[]; DO IF pageList = NIL THEN BEGIN ReleaseList[]; IF ~VMSpecial.PruneCache[needed] THEN RETURN[FALSE]; GrabList[]; END ELSE EXIT; ENDLOOP; IF needed = 1 THEN FreeOne[] ELSE UNTIL pageList = NIL DO FreeOne[]; ENDLOOP; ReleaseList[]; RETURN[TRUE] END; FreeOne: PROCEDURE = -- returns the page at the head of the pageList to the Mesa allocator. BEGIN OPEN SegmentDefs; p: PagePointer = pageList.link; DeleteDataSegment[VMtoDataSegment[pageList]]; pageList ← p; END; END.