<> <> DIRECTORY Process USING [Detach, MsecToTicks, priorityFaultHandlers, SetPriority, Ticks], VM USING [AddressFault, Clean, Interval, PageCount, PageNumberForAddress], VMInternal USING [GetCleaningCandidate, HasBackingStorage, swapBufferSize], VMSideDoor USING [rmPages], VMStatistics USING [rmNewClean, rmOldClean]; VMLaundryImpl: MONITOR IMPORTS Process, VM, VMInternal, VMSideDoor, VMStatistics EXPORTS VMInternal, VMStatistics = BEGIN OPEN VMInternal; <> <<>> highMark: NAT = MIN[VMSideDoor.rmPages/10, 200]; lowMark: NAT = highMark/4; samplingInterval: Process.Ticks = Process.MsecToTicks[250]; <<>> <> dirtyVictims: BOOL; laundry: CONDITION _ [timeout: samplingInterval]; <> laundryWakeups, panicLaundryWakeups, uselessLaundryWakeups: PUBLIC INT _ 0; pagesCleaned, pagesCleanedPanic: PUBLIC INT _ 0; laundryCleanCalls: PUBLIC INT _ 0; <> NoteDirtyVictim: PUBLIC ENTRY PROC = { dirtyVictims _ TRUE; NOTIFY laundry; }; <> LaundryProcess: PROC = { <> prevCleanUsed: INT _ VMStatistics.rmOldClean + VMStatistics.rmNewClean - (highMark - lowMark); Wait: ENTRY PROC RETURNS [badlyBehind: BOOL] = { dirtyVictims _ FALSE; DO WAIT laundry; IF HasBackingStorage[0] THEN EXIT; ENDLOOP; RETURN[dirtyVictims] }; <> Process.SetPriority[Process.priorityFaultHandlers]; DO badlyBehind: BOOL _ Wait[]; cleanUsed: INT = VMStatistics.rmOldClean + VMStatistics.rmNewClean; cleanedThisTime: INT _ 0; --*stats*-- laundryWakeups _ laundryWakeups.SUCC; IF badlyBehind THEN panicLaundryWakeups _ panicLaundryWakeups.SUCC; IF badlyBehind OR (cleanUsed - prevCleanUsed) >= (highMark - lowMark) THEN { UNTIL cleanedThisTime >= highMark DO interval: VM.Interval _ GetCleaningCandidate[ desired: swapBufferSize, -- larger run than this means multiple transfers in Clean comfortLevel: lowMark + cleanedThisTime, tryHard: badlyBehind ]; IF interval.count = 0 THEN <> EXIT; VM.Clean[interval ! VM.AddressFault => { interval.count _ VM.PageNumberForAddress[address] - interval.page; CONTINUE } ]; cleanedThisTime _ cleanedThisTime + interval.count; <<*stats*-->> laundryCleanCalls _ laundryCleanCalls.SUCC; ENDLOOP; prevCleanUsed _ VMStatistics.rmOldClean + VMStatistics.rmNewClean; }; <<*stats*-->> IF cleanedThisTime = 0 THEN uselessLaundryWakeups _ uselessLaundryWakeups.SUCC ELSE { pagesCleaned _ pagesCleaned + cleanedThisTime; IF badlyBehind THEN pagesCleanedPanic _ pagesCleanedPanic + cleanedThisTime; }; ENDLOOP; }; Process.Detach[FORK LaundryProcess[]]; END.