CollectorImpl.mesa
Implementation of the control of the Cedar incremental collector
Paul Rovner, January 18, 1984 9:33:14 am PST
Russ Atkinson, May 2, 1984 7:20:26 pm PDT
Bob Hagmann, May 10, 1984 3:17:53 pm PDT
DIRECTORY
Allocator USING[NHeaderP],
Collector USING[],
CollectorWatchdog USING [],
Process USING[Detach, SetPriority, priorityBackground, GetCurrent],
SafeStorage USING[ReclamationReason, NWordsAllocated, TrimSystemZone],
StorageAccounting USING[
ResetNWordsAllocated, ResetTotalNWordsAllocatedOnly, nObjectsCreated, nObjectsReclaimed, nWordsReclaimed],
ZCT USING[
ScanTheFrameHeap, MapReclaimableObjects, ResetStackBits, StartMarkingDecrements, StopMarkingDecrements];
CollectorImpl: MONITOR -- protects the collector
IMPORTS Process, SafeStorage, StorageAccounting, ZCT
EXPORTS Collector, CollectorWatchdog, SafeStorage
= BEGIN
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: BOOLFALSE;
trimZonesNeeded: BOOLFALSE;
CollectorNeeded: CONDITION;
CollectionInitiated: CONDITION;
CollectorFinished: CONDITION;
TrimZonesFinished: CONDITION;
collectorIncarnation: INT ← 0;
previousInfo: CollectorInfo ← [];
currentInfo: CollectorInfo ← [];
nObjectsReclaimedAsOfThen: INT ← 0;
nWordsReclaimedAsOfThen: INT ← 0;
backgroundCollectorProcess: PUBLIC PROCESSNIL; -- EXPORT to CollectorWatchdog
tAndSProc: PROCNIL;
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
The next line has been commented out because there is a potential deadlock when you suspend the collector waiting for the collector to finish.
suspendMe
← suspendMe
OR (collectorRunning
AND currentInfo.reason # allocationInterval
AND backgroundCollectorProcess # Process.GetCurrent[]);
IF NOT collectorRunning THEN InitiateCollection[reason]
ELSE IF reason = clientTAndSRequest THEN {
WHILE collectorRunning DO WAIT CollectorFinished ENDLOOP; -- await completion
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: BOOLTRUE, 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;
StorageAccounting.ResetNWordsAllocated[];
BROADCAST CollectorFinished;
BROADCAST TrimZonesFinished;
};
This guy is fired up as a detached process by the start code
BackgroundCollector: PROC = TRUSTED{
backgroundCollectorProcess ← Process.GetCurrent[];
DO
BackgroundCollectorInner[];
Process.SetPriority[Process.priorityBackground];
RRA: do this here to keep priority normally low. CollectorHelperImpl will bump it up if necessary.
IF currentInfo.reason = clientTAndSRequest AND tAndSProc # NIL
THEN tAndSProc[]
ELSE {
ZCT.StartMarkingDecrements[];
ZCT.ScanTheFrameHeap[];
ZCT.MapReclaimableObjects[NIL];
ZCT.StopMarkingDecrements[];
ZCT.ResetStackBits[];
};
IF trimZonesNeeded THEN {SafeStorage.TrimSystemZone[]; trimZonesNeeded ← FALSE};
FinishBC[];
ENDLOOP;
};
START HERE
TRUSTED{Process.Detach[FORK BackgroundCollector[]]};
END.