<> <> <> <> <> <> DIRECTORY Allocator USING[NHeaderP], Collector 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, 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: 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; backgroundCollectorProcess: PUBLIC PROCESS _ NIL; -- EXPORT to CollectorWatchdog tAndSProc: PROC _ NIL; <<>> <> 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[]}; <> <> <> <<_ suspendMe>> <> << 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 }; <> 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; StorageAccounting.ResetNWordsAllocated[]; BROADCAST CollectorFinished; BROADCAST TrimZonesFinished; }; <<>> <> BackgroundCollector: PROC = TRUSTED{ backgroundCollectorProcess _ Process.GetCurrent[]; DO BackgroundCollectorInner[]; Process.SetPriority[Process.priorityBackground]; <> 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; }; <<>> <> TRUSTED{Process.Detach[FORK BackgroundCollector[]]}; END.