-- 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.