SweepCollectableStorageImpl.mesa
last change by Bob Hagmann, July 25, 1984 4:27:51 pm PDT
DIRECTORY
Allocator: TYPE USING [bsiEscape, ExtendedHeader, HeaderP, NHeaderP, pagesPerQuantum, QuantumIndex, wordsPerQuantum, LastAddress, NormalHeader],
AllocatorOps: TYPE USING [EnterAndCallBack, quantumMap, BlockSize],
LoadState: TYPE USING [Acquire, Release, local],
Process,
SafeStorage: TYPE USING [Type],
SweepCollectableStorage USING [InfoProc],
VM: TYPE USING [Interval, SwapIn],
ZCT: TYPE USING [EnterAndCallBack, EnterRCOvAndCallBack];
SweepCollectableStorageImpl: PROGRAM
IMPORTS AllocatorOps, LoadState, Process, VM, ZCT
EXPORTS SweepCollectableStorage
= BEGIN OPEN Allocator, AllocatorOps, SafeStorage;
Variables
currentQuantumStart: Allocator.QuantumIndex;
TYPEs and constants
PROCS
LPToQuantumIndex: PROC[lp: LONG POINTER] RETURNS[QuantumIndex] = {
RETURN[LOOPHOLE[lp, LONG CARDINAL]/wordsPerQuantum];
};
QuantumIndexToLP: PROC[qi: QuantumIndex] RETURNS[LONG POINTER] = {
n: LONG CARDINAL ← qi;
RETURN[LOOPHOLE[n*wordsPerQuantum, LONG POINTER]];
};
IsExtendedBlock: PROC[hp: HeaderP] RETURNS[BOOL] = {
RETURN[LOOPHOLE[hp, NHeaderP].blockSizeIndex = bsiEscape];
};
EnumerateCollectableStorage: PUBLIC PROC [callersInfoProc: SweepCollectableStorage.InfoProc] = {
done: BOOLFALSE;
regionCount: INT ← 0 ;
ActuallyDoIt: PROC[] RETURNS [userFinished: BOOL] = {
this proc visits all collectible objects (free AND allocated) in a region of contiguous VM
Find the beginning of the next run of quanta from the quantum map
hp: HeaderP;
blockSize: INT ← 0;
Start parsing at the beginning of this run
FOR hp ← QuantumIndexToLP[currentQuantumStart], hp + blockSize
WHILE LOOPHOLE[hp, LONG CARDINAL] < LastAddress
AND quantumMap[LPToQuantumIndex[hp]]
DO
continue: BOOL;
nhp: NHeaderP
= LOOPHOLE
[
IF IsExtendedBlock[hp]
THEN hp + SIZE[ExtendedHeader] - SIZE[NormalHeader]
ELSE hp,
NHeaderP
];
blockSize ← BlockSize[hp];
continue ← callersInfoProc[type: nhp.type, size: blockSize, object: hp, objectHP: nhp];
IF ~continue THEN RETURN[TRUE];
ENDLOOP;
IF LOOPHOLE[hp, LONG CARDINAL] >= LastAddress THEN RETURN[FALSE];
RETURN[FALSE];
};
doSweepOfRegion: PROC RETURNS [endOfMemory: BOOL] = {
ENABLE UNWIND => NULL;
quantumEnd: Allocator.QuantumIndex;
userDone: BOOL;
haveAllocatorLocked: PROC = { -- here with the loader and allocator locked
haveRCOvLocked: PROC = {
here with the loader, allocator and RCOvBank locked
haveZCTLocked: PROC = {
here with the loader, allocator, RCOvBank and ZCT locked
userDone ← ActuallyDoIt[];
};
START haveRCOvLocked HERE
Acquire the lock on the ref counting machinery, do the work, then release the lock.
ZCT.EnterAndCallBack[haveZCTLocked];
};
START haveAllocatorLocked HERE
Acquire the lock on the RCOverflowBank, do the work, then release the lock.
ZCT.EnterRCOvAndCallBack[haveRCOvLocked];
}; -- end haveAllocatorLocked
START doSweepOfRegion HERE
First, find and swap in interval needed
WHILE ~AllocatorOps.quantumMap[currentQuantumStart] DO
IF currentQuantumStart = LAST[QuantumIndex] THEN RETURN[TRUE];
currentQuantumStart ← currentQuantumStart+1;
ENDLOOP;
quantumEnd ← currentQuantumStart;
WHILE AllocatorOps.quantumMap[quantumEnd] AND quantumEnd < LAST[QuantumIndex] DO
quantumEnd ← quantumEnd+1;
ENDLOOP;
VM.SwapIn[interval: [page: currentQuantumStart * Allocator.pagesPerQuantum, count: (quantumEnd - currentQuantumStart ) * Allocator.pagesPerQuantum ]];
Next, acquire the lock on the loader (REFs in GF's are counted)
LoadState.local.Acquire[exclusive];
Next, acquire the lock on the allocator, do the work, then release the lock.
AllocatorOps.EnterAndCallBack[haveAllocatorLocked ! UNWIND => LoadState.local.Release[]];
Release the loader's lock
LoadState.local.Release[];
currentQuantumStart ← quantumEnd+1;
RETURN[ userDone OR quantumEnd >= LAST[QuantumIndex] ];
}; -- end doSweepOfRegion
currentQuantumStart ← FIRST[QuantumIndex];
WHILE ~done DO
Process.Pause[1];
done ← doSweepOfRegion[];
regionCount ← regionCount + 1 ;
ENDLOOP;
};
START SweepCollectableStorageImpl HERE
END.