-- Swapper>ResidentMemoryImpl.mesa (last edited by Knutsen on November 5, 1980 1:00 PM)
-- Note: No frame heap ALLOC’s may be executed within any ENTRY procedures in this monitor, so that they may be called from the allocation trap handler. If this rule were not followed, we could get an allocation trap when we held the monitor lock, thus making AllocateMDS inaccessible to the allocation trap handler. Please see comments in ResidentMemory.mesa.
DIRECTORY
CachedRegionInternal USING [AllocateMStoreRuthlessly],
Environment USING [bitsPerWord, PageCount, PageNumber],
Frame USING [GetReturnLink, SetReturnLink],
Inline USING [LowHalf],
MStore USING [Deallocate],
PrincOps USING [Port],
Process USING [InitializeMonitor],
ResidentMemory USING [AllocateInternal, AllocateMDSInternal, FreeInternal, Location],
RuntimeInternal USING [WorryCallDebugger],
SimpleSpace USING [AllocateVM],
Space USING [defaultWindow],
StoragePrograms USING [DescribeSpace, lpMDS, outlaw, pageMDS],
Utilities USING [Bit, BitIndex, BitGet, BitPut, LongPointerFromPage, PageFromLongPointer],
VM USING [Interval];
ResidentMemoryImpl: MONITOR
LOCKS residentMemoryLock
IMPORTS CachedRegionInternal, Frame, Inline, MStore, Process, RuntimeInternal, SimpleSpace, StoragePrograms, Utilities
EXPORTS ResidentMemory, StoragePrograms
SHARES ResidentMemory =
BEGIN
-- Parameters:
countMax: Environment.PageCount = 40; -- amount of VM allocated for each location.
-- Variables:
residentMemoryLock: PUBLIC MONITORLOCK; -- (PRIVATE in interface)
locationData: TYPE = RECORD [
page: Environment.PageNumber, -- starting page of VM area.
allocationMap: ARRAY [0..(countMax+Environment.bitsPerWord-1)/Environment.bitsPerWord) OF CARDINAL]; -- PACKED ARRAY OF BOOLEAN in Mesa 6.
first64K: locationData;
mds: locationData;
hyperspace: locationData;
locations: ARRAY ResidentMemory.Location OF POINTER TO locationData ← [
@first64K,
IF StoragePrograms.pageMDS=Environment.PageNumber[0] THEN @first64K ELSE @mds,
@hyperspace];
free: Utilities.Bit = Utilities.Bit[0]; -- for allocationMap. A free page is unmapped.
busy: Utilities.Bit = Utilities.Bit[1];
j: Utilities.BitIndex;
--StoragePrograms.--InitializeResidentMemoryA: PUBLIC ENTRY PROCEDURE =
BEGIN
Process.InitializeMonitor[@residentMemoryLock];
InitializeInternal[];
END;
InitializeInternal: ENTRY --so InitializeAllocate can be called-- PROCEDURE = INLINE
BEGIN
location: ResidentMemory.Location;
FOR location IN ResidentMemory.Location DO
FOR j IN [0..countMax) DO
Utilities.BitPut[free, @locations[location].allocationMap, j];
ENDLOOP;
IF ~( location=mds AND locations[mds]=locations[first64K] ) --(if MDS =first64K, we don’t allocate twice)-- THEN
locations[location].page ← SimpleSpace.AllocateVM[countMax, location];
ENDLOOP;
[] ← InitializeAllocate[]; -- allocate frame; initialize PORT.
[] ← InitializeAllocateMDS[]; -- allocate frame; initialize PORT.
[] ← InitializeFree[]; -- allocate frame; initialize PORT.
END;
--StoragePrograms.--InitializeResidentMemoryB: PUBLIC ENTRY PROCEDURE =
-- tells Swapper about resident memory spaces.
BEGIN
location: ResidentMemory.Location;
FOR location IN ResidentMemory.Location DO
IF ~( location=mds AND locations[mds]=locations[first64K] ) THEN
StoragePrograms.DescribeSpace[StoragePrograms.outlaw, locations[location].page, countMax, Space.defaultWindow];
ENDLOOP;
END;
allocateInternal: PUBLIC --INTERNAL-- ResidentMemory.AllocateInternal ← -- (PRIVATE in interface) ("←" due to compiler glitch)
-- Guaranteed not to do an ALLOC from the frame heap.
[LOOPHOLE[@AwaitAllocateRequest]]; -- an indirect control link to the PORT.
AwaitAllocateRequest: --RESPONDING-- PORT [lp: LONG POINTER TO UNSPECIFIED] RETURNS [where: ResidentMemory.Location, pages: Environment.PageCount]; -- args/results match allocateInternal (but swapped).
InitializeAllocate: INTERNAL PROCEDURE RETURNS [lp: LONG POINTER TO UNSPECIFIED] --to match PORT args-- =
BEGIN
where: ResidentMemory.Location;
pages: Environment.PageCount;
LOOPHOLE[AwaitAllocateRequest, PrincOps.Port].dest ← Frame.GetReturnLink[]; -- set my PORT call to return to my caller on call below.
DO --FOREVER--
-- Return result; Await new request; Process it;
[where, pages] ← AwaitAllocateRequest[lp];
Frame.SetReturnLink[LOOPHOLE[AwaitAllocateRequest, PrincOps.Port].dest]; -- for debugger
--scope of Done --
BEGIN
start, pageInRun: CARDINAL;
FOR start ← 0, pageInRun+1 WHILE start+pages<countMax DO -- look for good starting page..
FOR pageInRun IN [start..start+pages) DO -- look for pages contiguous pages..
IF Utilities.BitGet[@locations[where].allocationMap, pageInRun] = busy THEN EXIT; -- pageInRun must survive loop exit.
REPEAT
FINISHED => -- found pages contiguous free pages.
BEGIN
CachedRegionInternal.AllocateMStoreRuthlessly[ VM.Interval[locations[where].page+start, pages]];
FOR pageInRun IN [start..start+pages) DO
Utilities.BitPut[busy, @locations[where].allocationMap, pageInRun];
ENDLOOP;
lp ← Utilities.LongPointerFromPage[locations[where].page+start];
GO TO Done;
END;
ENDLOOP;
REPEAT -- (not enough contiguous pages beginning at start)
FINISHED =>
DO RuntimeInternal.WorryCallDebugger["Out of VM for resident memory"L]
ENDLOOP; -- (so just increase countMax.)
ENDLOOP;
EXITS
Done => NULL;
END --scope of Done--;
ENDLOOP;
END;
allocateMDSInternal: PUBLIC --INTERNAL-- ResidentMemory.AllocateMDSInternal ← -- (PRIVATE in interface) ("←" due to compiler glitch)
-- Guaranteed not to do an ALLOC from the frame heap.
[LOOPHOLE[@AwaitAllocateMDSRequest]]; -- an indirect control link to the PORT.
AwaitAllocateMDSRequest: --RESPONDING-- PORT [p: POINTER TO UNSPECIFIED] RETURNS [pages: Environment.PageCount]; -- args/results match allocateMDSInternal (but swapped).
InitializeAllocateMDS: INTERNAL PROCEDURE RETURNS [p: POINTER TO UNSPECIFIED] --to match PORT args-- =
BEGIN
pages: Environment.PageCount;
LOOPHOLE[AwaitAllocateMDSRequest, PrincOps.Port].dest ← Frame.GetReturnLink[]; -- set my PORT call to return to my caller on call below.
DO --FOREVER--
-- Return result; Await new request; Process it;
pages ← AwaitAllocateMDSRequest[p];
Frame.SetReturnLink[LOOPHOLE[AwaitAllocateMDSRequest, PrincOps.Port].dest]; -- for debugger
p ← Inline.LowHalf[allocateInternal[mds, pages].lp - StoragePrograms.lpMDS];
ENDLOOP;
END;
freeInternal: PUBLIC --INTERNAL-- ResidentMemory.FreeInternal ← -- (PRIVATE in interface) ("←" due to compiler glitch)
-- Guaranteed not to do an ALLOC from the frame heap.
[LOOPHOLE[@AwaitFreeRequest]]; -- an indirect control link to the PORT.
AwaitFreeRequest: --RESPONDING-- PORT RETURNS [where: ResidentMemory.Location, pages: Environment.PageCount, lp: LONG POINTER TO UNSPECIFIED]; -- args/results match freeInternal (but swapped).
InitializeFree: INTERNAL PROCEDURE =
BEGIN
where: ResidentMemory.Location;
pages: Environment.PageCount;
lp: LONG POINTER TO UNSPECIFIED;
start, pageInRun: CARDINAL;
LOOPHOLE[AwaitFreeRequest, PrincOps.Port].dest ← Frame.GetReturnLink[]; -- set my PORT call to return to my caller on call below.
DO --FOREVER--
-- Return result; Await new request; Process it;
[where, pages, lp] ← AwaitFreeRequest[];
Frame.SetReturnLink[LOOPHOLE[AwaitFreeRequest, PrincOps.Port].dest]; -- for debugger
start ← Utilities.PageFromLongPointer[lp]-locations[where].page;
MStore.Deallocate[interval: VM.Interval[locations[where].page+start, pages], promised: FALSE];
FOR pageInRun IN [start..start+pages) DO
Utilities.BitPut[free, @locations[where].allocationMap, pageInRun];
ENDLOOP;
ENDLOOP;
END;
END.
LOG
April 16, 1980 8:52 AMKnutsenCreated file from PilotControl of March 11, 1980. Added InitializeResidentMemoryA/B. Names changed to AllocateMDS, FreeMDS. Implement Free. Make Allocate alloc in first64K and hyperspace, as well as MDS. Made Allocate, AllocateMDS coroutines.
April 28, 1980 9:56 AMForrestControlDefs=>PrincOps, FrameOps => Frame.
November 5, 1980 1:00 PMKnutsenMade Free a coroutine. Get LongPointerFromPage, PageFromLongPointer from Utiliies.