DIRECTORY
Allocator USING[NHeaderP],
Collector USING[Reclaim],
Process USING[Detach, SetPriority, priorityBackground],
SafeStorage USING[ReclamationReason, NWordsAllocated, TrimSystemZone],
StorageAccounting USING[ResetNWordsAllocated, ResetTotalNWordsAllocatedOnly, nObjectsCreated, nObjectsReclaimed, nWordsReclaimed],
ZCT USING[ScanTheFrameHeap, MapReclaimableObjects, ResetStackBits, StartMarkingDecrements, StopMarkingDecrements];
CollectorInfo:
TYPE =
RECORD[
incarnation: INT ← 0,
reason: SafeStorage.ReclamationReason ← allocationInterval,
wordsAllocated: INT ← 0,
objectsAllocated: INT ← 0,
totalWordsAllocated: INT ← 0, -- when collection started
totalObjectsAllocated: INT ← 0,
wordsReclaimed: INT ← 0,
objectsReclaimed: INT ← 0
];
collectorRunning: BOOL ← FALSE;
trimZonesNeeded: BOOL ← FALSE;
CollectorNeeded: CONDITION;
CollectionInitiated: CONDITION;
CollectorFinished: CONDITION;
TrimZonesFinished: CONDITION;
collectorIncarnation: INT ← 0;
previousInfo: CollectorInfo ← [];
currentInfo: CollectorInfo ← [];
nObjectsReclaimedAsOfThen: INT ← 0;
nWordsReclaimedAsOfThen: INT ← 0;
tAndSProc: PROC ← NIL;
procedures for dealing with the collector
EstablishTAndSProc: PUBLIC PROC [proc: PROC] = {tAndSProc ← proc};
IsCollectorActive:
PUBLIC
SAFE PROC
RETURNS[active:
BOOL, previousIncarnation:
INT] =
TRUSTED{RETURN[collectorRunning, collectorIncarnation]};
WaitForCollectorStart:
PUBLIC
ENTRY
SAFE PROC
RETURNS[
incarnation: INT,
reason: SafeStorage.ReclamationReason,
wordsAllocated: INT, -- since previous collection was initiated
objectsAllocated: INT] =
TRUSTED{
UNTIL collectorRunning DO WAIT CollectionInitiated ENDLOOP;
RETURN[
incarnation ← currentInfo.incarnation,
reason ← currentInfo.reason,
wordsAllocated ← currentInfo.wordsAllocated,
objectsAllocated ← currentInfo.objectsAllocated
];
};
WaitForCollectorDone:
PUBLIC
ENTRY
SAFE PROC
RETURNS[
incarnation: INT,
reason: SafeStorage.ReclamationReason,
wordsReclaimed: INT,
objectsReclaimed: INT] =
TRUSTED{
WHILE collectorRunning DO WAIT CollectorFinished ENDLOOP;
RETURN[
incarnation ← previousInfo.incarnation,
reason ← previousInfo.reason,
wordsReclaimed ← previousInfo.wordsReclaimed,
objectsReclaimed ← previousInfo.objectsReclaimed
];
};
InternalReclaim:
PUBLIC
ENTRY
PROC
[reason: SafeStorage.ReclamationReason, suspendMe: BOOL] = {
ENABLE UNWIND => ERROR;
IF reason = quantaNeeded THEN trimZonesNeeded ← TRUE;
TRUSTED{StorageAccounting.ResetTotalNWordsAllocatedOnly[]};
obviate decisions to collect while the collector is running, but allow allocator hogs to be suspended during this time
IF NOT collectorRunning THEN InitiateCollection[reason];
WHILE trimZonesNeeded AND collectorRunning DO WAIT TrimZonesFinished ENDLOOP;
WHILE suspendMe
AND collectorRunning
DO WAIT CollectorFinished ENDLOOP; -- await completion
};
client interface
ReclaimCollectibleObjects:
PUBLIC
SAFE
PROC
[suspendMe:
BOOL ←
TRUE, traceAndSweep:
BOOL] =
TRUSTED {
InternalReclaim
[reason: IF traceAndSweep THEN clientTAndSRequest ELSE clientRequest,
suspendMe: suspendMe];
};
InitiateCollection:
INTERNAL
PROC[reason: SafeStorage.ReclamationReason] = {
first: BOOLEAN = (collectorIncarnation = 0);
nw: INT = SafeStorage.NWordsAllocated[];
nob: INT = StorageAccounting.nObjectsCreated;
currentInfo ← [
incarnation: (collectorIncarnation ← collectorIncarnation + 1),
reason: reason,
wordsAllocated: (IF first THEN nw ELSE nw - previousInfo.totalWordsAllocated),
objectsAllocated: (IF first THEN nob ELSE nob - previousInfo.totalObjectsAllocated),
totalWordsAllocated: nw,
totalObjectsAllocated: nob
];
nObjectsReclaimedAsOfThen ← StorageAccounting.nObjectsReclaimed;
nWordsReclaimedAsOfThen ← StorageAccounting.nWordsReclaimed;
collectorRunning ← TRUE;
BROADCAST CollectionInitiated;
NOTIFY CollectorNeeded;
};
BackgroundCollectorInner:
ENTRY
PROC = {
ENABLE
UNWIND =>
NULL;
UNTIL collectorRunning DO WAIT CollectorNeeded ENDLOOP;
};
FinishBC:
ENTRY
PROC = {
ENABLE
UNWIND =>
NULL;
collectorRunning ← FALSE;
currentInfo.wordsReclaimed
← StorageAccounting.nWordsReclaimed - nWordsReclaimedAsOfThen;
currentInfo.objectsReclaimed
← StorageAccounting.nObjectsReclaimed - nObjectsReclaimedAsOfThen;
previousInfo ← currentInfo;
BROADCAST CollectorFinished;
BROADCAST TrimZonesFinished;
};
This guy is fired up as a detached process by the start code
BackgroundCollector:
PROC =
TRUSTED{
Process.SetPriority[Process.priorityBackground];
DO
BackgroundCollectorInner[];
IF currentInfo.reason = clientTAndSRequest
AND tAndSProc #
NIL
THEN tAndSProc[]
ELSE {
ZCT.StartMarkingDecrements[];
ZCT.ScanTheFrameHeap[];
ZCT.MapReclaimableObjects[Collector.Reclaim];
ZCT.StopMarkingDecrements[];
ZCT.ResetStackBits[];
};
StorageAccounting.ResetNWordsAllocated[];
IF trimZonesNeeded THEN {SafeStorage.TrimSystemZone[]; trimZonesNeeded ← FALSE};
FinishBC[];
ENDLOOP;
};
START HERE
TRUSTED{Process.Detach[
FORK BackgroundCollector[]]};