xref: /reactos/ntoskrnl/mm/balance.c (revision 195c4918)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * COPYRIGHT:   See COPYING in the top level directory
3c2c66affSColin Finck  * PROJECT:     ReactOS kernel
46db0d24fSHermès Bélusca-Maïto  * PURPOSE:     kernel memory management functions
5*195c4918SJoachim Henze  * PROGRAMMERS: David Welch <welch@cwcom.net>
6*195c4918SJoachim Henze  *              Cameron Gutman <cameron.gutman@reactos.org>
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck /* INCLUDES *****************************************************************/
10c2c66affSColin Finck 
11c2c66affSColin Finck #include <ntoskrnl.h>
12c2c66affSColin Finck #define NDEBUG
13c2c66affSColin Finck #include <debug.h>
14c2c66affSColin Finck 
15c2c66affSColin Finck #include "ARM3/miarm.h"
16c2c66affSColin Finck 
173adf4508SJérôme Gardou 
18c2c66affSColin Finck /* TYPES ********************************************************************/
19c2c66affSColin Finck typedef struct _MM_ALLOCATION_REQUEST
20c2c66affSColin Finck {
21c2c66affSColin Finck     PFN_NUMBER Page;
22c2c66affSColin Finck     LIST_ENTRY ListEntry;
23c2c66affSColin Finck     KEVENT Event;
24c2c66affSColin Finck }
25c2c66affSColin Finck MM_ALLOCATION_REQUEST, *PMM_ALLOCATION_REQUEST;
26c2c66affSColin Finck /* GLOBALS ******************************************************************/
27c2c66affSColin Finck 
28c2c66affSColin Finck MM_MEMORY_CONSUMER MiMemoryConsumers[MC_MAXIMUM];
29c2c66affSColin Finck static ULONG MiMinimumAvailablePages;
30c2c66affSColin Finck static ULONG MiMinimumPagesPerRun;
31c2c66affSColin Finck static CLIENT_ID MiBalancerThreadId;
32c2c66affSColin Finck static HANDLE MiBalancerThreadHandle = NULL;
33c2c66affSColin Finck static KEVENT MiBalancerEvent;
34047dc972STimo Kreuzer static KEVENT MiBalancerDoneEvent;
35c2c66affSColin Finck static KTIMER MiBalancerTimer;
36c2c66affSColin Finck 
37625f2733SJérôme Gardou static LONG PageOutThreadActive;
38625f2733SJérôme Gardou 
39c2c66affSColin Finck /* FUNCTIONS ****************************************************************/
40c2c66affSColin Finck 
415c7ce447SVictor Perevertkin CODE_SEG("INIT")
42b20f8151SSerge Gautherie VOID
43c2c66affSColin Finck NTAPI
MmInitializeBalancer(ULONG NrAvailablePages,ULONG NrSystemPages)44c2c66affSColin Finck MmInitializeBalancer(ULONG NrAvailablePages, ULONG NrSystemPages)
45c2c66affSColin Finck {
46c2c66affSColin Finck     memset(MiMemoryConsumers, 0, sizeof(MiMemoryConsumers));
47c2c66affSColin Finck 
48c2c66affSColin Finck     /* Set up targets. */
49c2c66affSColin Finck     MiMinimumAvailablePages = 256;
50c2c66affSColin Finck     MiMinimumPagesPerRun = 256;
51aab24ed1SJérôme Gardou     MiMemoryConsumers[MC_USER].PagesTarget = NrAvailablePages / 2;
52c2c66affSColin Finck }
53c2c66affSColin Finck 
545c7ce447SVictor Perevertkin CODE_SEG("INIT")
55b20f8151SSerge Gautherie VOID
56c2c66affSColin Finck NTAPI
MmInitializeMemoryConsumer(ULONG Consumer,NTSTATUS (* Trim)(ULONG Target,ULONG Priority,PULONG NrFreed))57c2c66affSColin Finck MmInitializeMemoryConsumer(
58c2c66affSColin Finck     ULONG Consumer,
59c2c66affSColin Finck     NTSTATUS (*Trim)(ULONG Target, ULONG Priority, PULONG NrFreed))
60c2c66affSColin Finck {
61c2c66affSColin Finck     MiMemoryConsumers[Consumer].Trim = Trim;
62c2c66affSColin Finck }
63c2c66affSColin Finck 
64c2c66affSColin Finck VOID
65c2c66affSColin Finck NTAPI
66c2c66affSColin Finck MiZeroPhysicalPage(
67c2c66affSColin Finck     IN PFN_NUMBER PageFrameIndex
68c2c66affSColin Finck );
69c2c66affSColin Finck 
70c2c66affSColin Finck NTSTATUS
71c2c66affSColin Finck NTAPI
MmReleasePageMemoryConsumer(ULONG Consumer,PFN_NUMBER Page)72c2c66affSColin Finck MmReleasePageMemoryConsumer(ULONG Consumer, PFN_NUMBER Page)
73c2c66affSColin Finck {
7433949028STimo Kreuzer     KIRQL OldIrql;
7533949028STimo Kreuzer 
76c2c66affSColin Finck     if (Page == 0)
77c2c66affSColin Finck     {
78c2c66affSColin Finck         DPRINT1("Tried to release page zero.\n");
79c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
80c2c66affSColin Finck     }
81c2c66affSColin Finck 
82c2c66affSColin Finck     (void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
833703bbd6SKyle Katarn     UpdateTotalCommittedPages(-1);
84c2c66affSColin Finck 
8533949028STimo Kreuzer     OldIrql = MiAcquirePfnLock();
8633949028STimo Kreuzer 
87c2c66affSColin Finck     MmDereferencePage(Page);
88c2c66affSColin Finck 
8933949028STimo Kreuzer     MiReleasePfnLock(OldIrql);
9033949028STimo Kreuzer 
91c2c66affSColin Finck     return(STATUS_SUCCESS);
92c2c66affSColin Finck }
93c2c66affSColin Finck 
94c2c66affSColin Finck ULONG
95c2c66affSColin Finck NTAPI
MiTrimMemoryConsumer(ULONG Consumer,ULONG InitialTarget)96c2c66affSColin Finck MiTrimMemoryConsumer(ULONG Consumer, ULONG InitialTarget)
97c2c66affSColin Finck {
98c2c66affSColin Finck     ULONG Target = InitialTarget;
99c2c66affSColin Finck     ULONG NrFreedPages = 0;
100c2c66affSColin Finck     NTSTATUS Status;
101c2c66affSColin Finck 
102c2c66affSColin Finck     /* Make sure we can trim this consumer */
103c2c66affSColin Finck     if (!MiMemoryConsumers[Consumer].Trim)
104c2c66affSColin Finck     {
105c2c66affSColin Finck         /* Return the unmodified initial target */
106c2c66affSColin Finck         return InitialTarget;
107c2c66affSColin Finck     }
108c2c66affSColin Finck 
109c2c66affSColin Finck     if (MmAvailablePages < MiMinimumAvailablePages)
110c2c66affSColin Finck     {
111c2c66affSColin Finck         /* Global page limit exceeded */
112c2c66affSColin Finck         Target = (ULONG)max(Target, MiMinimumAvailablePages - MmAvailablePages);
113c2c66affSColin Finck     }
114625f2733SJérôme Gardou     else if (MiMemoryConsumers[Consumer].PagesUsed > MiMemoryConsumers[Consumer].PagesTarget)
115625f2733SJérôme Gardou     {
116625f2733SJérôme Gardou         /* Consumer page limit exceeded */
117625f2733SJérôme Gardou         Target = max(Target, MiMemoryConsumers[Consumer].PagesUsed - MiMemoryConsumers[Consumer].PagesTarget);
118625f2733SJérôme Gardou     }
119aab24ed1SJérôme Gardou 
120c2c66affSColin Finck     if (Target)
121c2c66affSColin Finck     {
122c2c66affSColin Finck         /* Now swap the pages out */
12341475dfcSJérôme Gardou         Status = MiMemoryConsumers[Consumer].Trim(Target, MmAvailablePages < MiMinimumAvailablePages, &NrFreedPages);
124c2c66affSColin Finck 
125c2c66affSColin Finck         DPRINT("Trimming consumer %lu: Freed %lu pages with a target of %lu pages\n", Consumer, NrFreedPages, Target);
126c2c66affSColin Finck 
127c2c66affSColin Finck         if (!NT_SUCCESS(Status))
128c2c66affSColin Finck         {
129c2c66affSColin Finck             KeBugCheck(MEMORY_MANAGEMENT);
130c2c66affSColin Finck         }
131c2c66affSColin Finck     }
132aab24ed1SJérôme Gardou 
133aab24ed1SJérôme Gardou     /* Return the page count needed to be freed to meet the initial target */
134aab24ed1SJérôme Gardou     return (InitialTarget > NrFreedPages) ? (InitialTarget - NrFreedPages) : 0;
135c2c66affSColin Finck }
136c2c66affSColin Finck 
137c2c66affSColin Finck NTSTATUS
MmTrimUserMemory(ULONG Target,ULONG Priority,PULONG NrFreedPages)138c2c66affSColin Finck MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
139c2c66affSColin Finck {
140d7de53b6STimo Kreuzer     PFN_NUMBER FirstPage, CurrentPage;
141c2c66affSColin Finck     NTSTATUS Status;
142c2c66affSColin Finck 
143c2c66affSColin Finck     (*NrFreedPages) = 0;
144c2c66affSColin Finck 
145*195c4918SJoachim Henze     DPRINT("MM BALANCER: %s\n", Priority ? "Paging out!" : "Removing access bit!");
14641475dfcSJérôme Gardou 
147d7de53b6STimo Kreuzer     FirstPage = MmGetLRUFirstUserPage();
148d7de53b6STimo Kreuzer     CurrentPage = FirstPage;
149c2c66affSColin Finck     while (CurrentPage != 0 && Target > 0)
150c2c66affSColin Finck     {
15141475dfcSJérôme Gardou         if (Priority)
15241475dfcSJérôme Gardou         {
153c2c66affSColin Finck             Status = MmPageOutPhysicalAddress(CurrentPage);
154c2c66affSColin Finck             if (NT_SUCCESS(Status))
155c2c66affSColin Finck             {
156c2c66affSColin Finck                 DPRINT("Succeeded\n");
157c2c66affSColin Finck                 Target--;
158c2c66affSColin Finck                 (*NrFreedPages)++;
159d7de53b6STimo Kreuzer                 if (CurrentPage == FirstPage)
160d7de53b6STimo Kreuzer                 {
161d7de53b6STimo Kreuzer                     FirstPage = 0;
162d7de53b6STimo Kreuzer                 }
163c2c66affSColin Finck             }
16441475dfcSJérôme Gardou         }
16541475dfcSJérôme Gardou         else
16641475dfcSJérôme Gardou         {
16741475dfcSJérôme Gardou             /* When not paging-out agressively, just reset the accessed bit */
16841475dfcSJérôme Gardou             PEPROCESS Process = NULL;
16941475dfcSJérôme Gardou             PVOID Address = NULL;
17041475dfcSJérôme Gardou             BOOLEAN Accessed = FALSE;
17141475dfcSJérôme Gardou 
17241475dfcSJérôme Gardou             /*
17341475dfcSJérôme Gardou              * We have a lock-ordering problem here. We cant lock the PFN DB before the Process address space.
17441475dfcSJérôme Gardou              * So we must use circonvoluted loops.
17541475dfcSJérôme Gardou              * Well...
17641475dfcSJérôme Gardou              */
17741475dfcSJérôme Gardou             while (TRUE)
17841475dfcSJérôme Gardou             {
17941475dfcSJérôme Gardou                 KAPC_STATE ApcState;
18041475dfcSJérôme Gardou                 KIRQL OldIrql = MiAcquirePfnLock();
18141475dfcSJérôme Gardou                 PMM_RMAP_ENTRY Entry = MmGetRmapListHeadPage(CurrentPage);
18241475dfcSJérôme Gardou                 while (Entry)
18341475dfcSJérôme Gardou                 {
18441475dfcSJérôme Gardou                     if (RMAP_IS_SEGMENT(Entry->Address))
18541475dfcSJérôme Gardou                     {
18641475dfcSJérôme Gardou                         Entry = Entry->Next;
18741475dfcSJérôme Gardou                         continue;
18841475dfcSJérôme Gardou                     }
18941475dfcSJérôme Gardou 
19041475dfcSJérôme Gardou                     /* Check that we didn't treat this entry before */
19141475dfcSJérôme Gardou                     if (Entry->Address < Address)
19241475dfcSJérôme Gardou                     {
19341475dfcSJérôme Gardou                         Entry = Entry->Next;
19441475dfcSJérôme Gardou                         continue;
19541475dfcSJérôme Gardou                     }
19641475dfcSJérôme Gardou 
19741475dfcSJérôme Gardou                     if ((Entry->Address == Address) && (Entry->Process <= Process))
19841475dfcSJérôme Gardou                     {
19941475dfcSJérôme Gardou                         Entry = Entry->Next;
20041475dfcSJérôme Gardou                         continue;
20141475dfcSJérôme Gardou                     }
20241475dfcSJérôme Gardou 
20341475dfcSJérôme Gardou                     break;
20441475dfcSJérôme Gardou                 }
20541475dfcSJérôme Gardou 
20641475dfcSJérôme Gardou                 if (!Entry)
20741475dfcSJérôme Gardou                 {
20841475dfcSJérôme Gardou                     MiReleasePfnLock(OldIrql);
20941475dfcSJérôme Gardou                     break;
21041475dfcSJérôme Gardou                 }
21141475dfcSJérôme Gardou 
21241475dfcSJérôme Gardou                 Process = Entry->Process;
21341475dfcSJérôme Gardou                 Address = Entry->Address;
21441475dfcSJérôme Gardou 
215acf28dbcSJérôme Gardou                 ObReferenceObject(Process);
216acf28dbcSJérôme Gardou 
217acf28dbcSJérôme Gardou                 if (!ExAcquireRundownProtection(&Process->RundownProtect))
218acf28dbcSJérôme Gardou                 {
219acf28dbcSJérôme Gardou                     ObDereferenceObject(Process);
220acf28dbcSJérôme Gardou                     MiReleasePfnLock(OldIrql);
221acf28dbcSJérôme Gardou                     continue;
222acf28dbcSJérôme Gardou                 }
223acf28dbcSJérôme Gardou 
22441475dfcSJérôme Gardou                 MiReleasePfnLock(OldIrql);
22541475dfcSJérôme Gardou 
22641475dfcSJérôme Gardou                 KeStackAttachProcess(&Process->Pcb, &ApcState);
227acf28dbcSJérôme Gardou                 MiLockProcessWorkingSet(Process, PsGetCurrentThread());
22841475dfcSJérôme Gardou 
2297c006df7SJérôme Gardou                 /* Be sure this is still valid. */
230acf28dbcSJérôme Gardou                 if (MmIsAddressValid(Address))
231676dc4b4SJérôme Gardou                 {
232acf28dbcSJérôme Gardou                     PMMPTE Pte = MiAddressToPte(Address);
23341475dfcSJérôme Gardou                     Accessed = Accessed || Pte->u.Hard.Accessed;
23441475dfcSJérôme Gardou                     Pte->u.Hard.Accessed = 0;
23541475dfcSJérôme Gardou 
23641475dfcSJérôme Gardou                     /* There is no need to invalidate, the balancer thread is never on a user process */
23741475dfcSJérôme Gardou                     //KeInvalidateTlbEntry(Address);
23841475dfcSJérôme Gardou                 }
23941475dfcSJérôme Gardou 
240acf28dbcSJérôme Gardou                 MiUnlockProcessWorkingSet(Process, PsGetCurrentThread());
24141475dfcSJérôme Gardou 
24241475dfcSJérôme Gardou                 KeUnstackDetachProcess(&ApcState);
243acf28dbcSJérôme Gardou                 ExReleaseRundownProtection(&Process->RundownProtect);
244acf28dbcSJérôme Gardou                 ObDereferenceObject(Process);
24541475dfcSJérôme Gardou             }
24641475dfcSJérôme Gardou 
24741475dfcSJérôme Gardou             if (!Accessed)
24841475dfcSJérôme Gardou             {
24941475dfcSJérôme Gardou                 /* Nobody accessed this page since the last time we check. Time to clean up */
25041475dfcSJérôme Gardou 
25141475dfcSJérôme Gardou                 Status = MmPageOutPhysicalAddress(CurrentPage);
252d7de53b6STimo Kreuzer                 if (NT_SUCCESS(Status))
253d7de53b6STimo Kreuzer                 {
254d7de53b6STimo Kreuzer                     if (CurrentPage == FirstPage)
255d7de53b6STimo Kreuzer                     {
256d7de53b6STimo Kreuzer                         FirstPage = 0;
257d7de53b6STimo Kreuzer                     }
258d7de53b6STimo Kreuzer                 }
25941475dfcSJérôme Gardou                 // DPRINT1("Paged-out one page: %s\n", NT_SUCCESS(Status) ? "Yes" : "No");
26041475dfcSJérôme Gardou             }
26141475dfcSJérôme Gardou 
26241475dfcSJérôme Gardou             /* Done for this page. */
26341475dfcSJérôme Gardou             Target--;
26441475dfcSJérôme Gardou         }
265c2c66affSColin Finck 
2668a8b4db4SJérôme Gardou         CurrentPage = MmGetLRUNextUserPage(CurrentPage, TRUE);
267d7de53b6STimo Kreuzer         if (FirstPage == 0)
268d7de53b6STimo Kreuzer         {
269d7de53b6STimo Kreuzer             FirstPage = CurrentPage;
270d7de53b6STimo Kreuzer         }
271d7de53b6STimo Kreuzer         else if (CurrentPage == FirstPage)
272d7de53b6STimo Kreuzer         {
273d7de53b6STimo Kreuzer             DPRINT1("We are back at the start, abort!\n");
274d7de53b6STimo Kreuzer             return STATUS_SUCCESS;
275d7de53b6STimo Kreuzer         }
276c2c66affSColin Finck     }
2778a8b4db4SJérôme Gardou 
2788a8b4db4SJérôme Gardou     if (CurrentPage)
2798a8b4db4SJérôme Gardou     {
2808a8b4db4SJérôme Gardou         KIRQL OldIrql = MiAcquirePfnLock();
2818a8b4db4SJérôme Gardou         MmDereferencePage(CurrentPage);
2828a8b4db4SJérôme Gardou         MiReleasePfnLock(OldIrql);
283c2c66affSColin Finck     }
284c2c66affSColin Finck 
285c2c66affSColin Finck     return STATUS_SUCCESS;
286c2c66affSColin Finck }
287c2c66affSColin Finck 
288c2c66affSColin Finck VOID
289c2c66affSColin Finck NTAPI
MmRebalanceMemoryConsumers(VOID)290c2c66affSColin Finck MmRebalanceMemoryConsumers(VOID)
291c2c66affSColin Finck {
2926f2b94c0SJérôme Gardou     // if (InterlockedCompareExchange(&PageOutThreadActive, 0, 1) == 0)
293c2c66affSColin Finck     {
294c2c66affSColin Finck         KeSetEvent(&MiBalancerEvent, IO_NO_INCREMENT, FALSE);
295c2c66affSColin Finck     }
296c2c66affSColin Finck }
297c2c66affSColin Finck 
298047dc972STimo Kreuzer VOID
299047dc972STimo Kreuzer NTAPI
MmRebalanceMemoryConsumersAndWait(VOID)300047dc972STimo Kreuzer MmRebalanceMemoryConsumersAndWait(VOID)
301047dc972STimo Kreuzer {
302047dc972STimo Kreuzer     ASSERT(PsGetCurrentProcess()->AddressCreationLock.Owner != KeGetCurrentThread());
303047dc972STimo Kreuzer     ASSERT(!MM_ANY_WS_LOCK_HELD(PsGetCurrentThread()));
304047dc972STimo Kreuzer     ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
305047dc972STimo Kreuzer 
306047dc972STimo Kreuzer     KeResetEvent(&MiBalancerDoneEvent);
307047dc972STimo Kreuzer     MmRebalanceMemoryConsumers();
308047dc972STimo Kreuzer     KeWaitForSingleObject(&MiBalancerDoneEvent, Executive, KernelMode, FALSE, NULL);
309047dc972STimo Kreuzer }
310047dc972STimo Kreuzer 
311c2c66affSColin Finck NTSTATUS
312c2c66affSColin Finck NTAPI
MmRequestPageMemoryConsumer(ULONG Consumer,BOOLEAN CanWait,PPFN_NUMBER AllocatedPage)313c2c66affSColin Finck MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
314c2c66affSColin Finck                             PPFN_NUMBER AllocatedPage)
315c2c66affSColin Finck {
316c2c66affSColin Finck     PFN_NUMBER Page;
3172b140566SDoug Lyons     static INT i = 0;
3182b140566SDoug Lyons     static LARGE_INTEGER TinyTime = {{-1L, -1L}};
3192b140566SDoug Lyons 
3202b140566SDoug Lyons     /* Delay some requests for the Memory Manager to recover pages */
3212b140566SDoug Lyons     if (i++ >= 100)
3222b140566SDoug Lyons     {
3232b140566SDoug Lyons         KeDelayExecutionThread(KernelMode, FALSE, &TinyTime);
3242b140566SDoug Lyons         i = 0;
3252b140566SDoug Lyons     }
326c2c66affSColin Finck 
327c2c66affSColin Finck     /*
328c2c66affSColin Finck      * Actually allocate the page.
329c2c66affSColin Finck      */
330c2c66affSColin Finck     Page = MmAllocPage(Consumer);
331c2c66affSColin Finck     if (Page == 0)
332c2c66affSColin Finck     {
3333ae12d5aSTimo Kreuzer         *AllocatedPage = 0;
3343ae12d5aSTimo Kreuzer         return STATUS_NO_MEMORY;
335c2c66affSColin Finck     }
336c2c66affSColin Finck     *AllocatedPage = Page;
337c2c66affSColin Finck 
3383ae12d5aSTimo Kreuzer     /* Update the target */
3393ae12d5aSTimo Kreuzer     InterlockedIncrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
3403ae12d5aSTimo Kreuzer     UpdateTotalCommittedPages(1);
3413ae12d5aSTimo Kreuzer 
342c2c66affSColin Finck     return(STATUS_SUCCESS);
343c2c66affSColin Finck }
344c2c66affSColin Finck 
3452b140566SDoug Lyons VOID
3462b140566SDoug Lyons CcRosTrimCache(
3472b140566SDoug Lyons     _In_ ULONG Target,
3482b140566SDoug Lyons     _Out_ PULONG NrFreed);
349c2c66affSColin Finck 
350c2c66affSColin Finck VOID NTAPI
MiBalancerThread(PVOID Unused)351c2c66affSColin Finck MiBalancerThread(PVOID Unused)
352c2c66affSColin Finck {
353c2c66affSColin Finck     PVOID WaitObjects[2];
354c2c66affSColin Finck     NTSTATUS Status;
355c2c66affSColin Finck     ULONG i;
356c2c66affSColin Finck 
357c2c66affSColin Finck     WaitObjects[0] = &MiBalancerEvent;
358c2c66affSColin Finck     WaitObjects[1] = &MiBalancerTimer;
359c2c66affSColin Finck 
360c2c66affSColin Finck     while (1)
361c2c66affSColin Finck     {
362047dc972STimo Kreuzer         KeSetEvent(&MiBalancerDoneEvent, IO_NO_INCREMENT, FALSE);
363c2c66affSColin Finck         Status = KeWaitForMultipleObjects(2,
364c2c66affSColin Finck                                           WaitObjects,
365c2c66affSColin Finck                                           WaitAny,
366c2c66affSColin Finck                                           Executive,
367c2c66affSColin Finck                                           KernelMode,
368c2c66affSColin Finck                                           FALSE,
369c2c66affSColin Finck                                           NULL,
370c2c66affSColin Finck                                           NULL);
371c2c66affSColin Finck 
372c2c66affSColin Finck         if (Status == STATUS_WAIT_0 || Status == STATUS_WAIT_1)
373c2c66affSColin Finck         {
374c2c66affSColin Finck             ULONG InitialTarget = 0;
3752b140566SDoug Lyons             ULONG Target;
3762b140566SDoug Lyons             ULONG NrFreedPages;
377c2c66affSColin Finck 
378c2c66affSColin Finck             do
379c2c66affSColin Finck             {
380c2c66affSColin Finck                 ULONG OldTarget = InitialTarget;
381c2c66affSColin Finck 
382c2c66affSColin Finck                 /* Trim each consumer */
383c2c66affSColin Finck                 for (i = 0; i < MC_MAXIMUM; i++)
384c2c66affSColin Finck                 {
385c2c66affSColin Finck                     InitialTarget = MiTrimMemoryConsumer(i, InitialTarget);
386c2c66affSColin Finck                 }
387c2c66affSColin Finck 
3882b140566SDoug Lyons                 /* Trim cache */
3892b140566SDoug Lyons                 Target = max(InitialTarget, abs(MiMinimumAvailablePages - MmAvailablePages));
3902b140566SDoug Lyons                 if (Target)
3912b140566SDoug Lyons                 {
3922b140566SDoug Lyons                     CcRosTrimCache(Target, &NrFreedPages);
3932b140566SDoug Lyons                     InitialTarget -= min(NrFreedPages, InitialTarget);
3942b140566SDoug Lyons                 }
3952b140566SDoug Lyons 
396c2c66affSColin Finck                 /* No pages left to swap! */
397c2c66affSColin Finck                 if (InitialTarget != 0 &&
398c2c66affSColin Finck                         InitialTarget == OldTarget)
399c2c66affSColin Finck                 {
400c2c66affSColin Finck                     /* Game over */
401c2c66affSColin Finck                     KeBugCheck(NO_PAGES_AVAILABLE);
402c2c66affSColin Finck                 }
403c2c66affSColin Finck             }
404c2c66affSColin Finck             while (InitialTarget != 0);
405625f2733SJérôme Gardou 
406625f2733SJérôme Gardou             if (Status == STATUS_WAIT_0)
407625f2733SJérôme Gardou                 InterlockedDecrement(&PageOutThreadActive);
408c2c66affSColin Finck         }
409c2c66affSColin Finck         else
410c2c66affSColin Finck         {
411c2c66affSColin Finck             DPRINT1("KeWaitForMultipleObjects failed, status = %x\n", Status);
412c2c66affSColin Finck             KeBugCheck(MEMORY_MANAGEMENT);
413c2c66affSColin Finck         }
414c2c66affSColin Finck     }
415c2c66affSColin Finck }
416c2c66affSColin Finck 
4175c7ce447SVictor Perevertkin CODE_SEG("INIT")
418b20f8151SSerge Gautherie VOID
419c2c66affSColin Finck NTAPI
MiInitBalancerThread(VOID)420c2c66affSColin Finck MiInitBalancerThread(VOID)
421c2c66affSColin Finck {
422c2c66affSColin Finck     KPRIORITY Priority;
423c2c66affSColin Finck     NTSTATUS Status;
42441475dfcSJérôme Gardou     LARGE_INTEGER Timeout;
425c2c66affSColin Finck 
426c2c66affSColin Finck     KeInitializeEvent(&MiBalancerEvent, SynchronizationEvent, FALSE);
427047dc972STimo Kreuzer     KeInitializeEvent(&MiBalancerDoneEvent, SynchronizationEvent, FALSE);
428c2c66affSColin Finck     KeInitializeTimerEx(&MiBalancerTimer, SynchronizationTimer);
42941475dfcSJérôme Gardou 
43041475dfcSJérôme Gardou     Timeout.QuadPart = -20000000; /* 2 sec */
431c2c66affSColin Finck     KeSetTimerEx(&MiBalancerTimer,
43241475dfcSJérôme Gardou                  Timeout,
433c2c66affSColin Finck                  2000,         /* 2 sec */
434c2c66affSColin Finck                  NULL);
435c2c66affSColin Finck 
436c2c66affSColin Finck     Status = PsCreateSystemThread(&MiBalancerThreadHandle,
437c2c66affSColin Finck                                   THREAD_ALL_ACCESS,
438c2c66affSColin Finck                                   NULL,
439c2c66affSColin Finck                                   NULL,
440c2c66affSColin Finck                                   &MiBalancerThreadId,
441c2c66affSColin Finck                                   MiBalancerThread,
442c2c66affSColin Finck                                   NULL);
443c2c66affSColin Finck     if (!NT_SUCCESS(Status))
444c2c66affSColin Finck     {
445c2c66affSColin Finck         KeBugCheck(MEMORY_MANAGEMENT);
446c2c66affSColin Finck     }
447c2c66affSColin Finck 
448c2c66affSColin Finck     Priority = LOW_REALTIME_PRIORITY + 1;
449c2c66affSColin Finck     NtSetInformationThread(MiBalancerThreadHandle,
450c2c66affSColin Finck                            ThreadPriority,
451c2c66affSColin Finck                            &Priority,
452c2c66affSColin Finck                            sizeof(Priority));
453c2c66affSColin Finck 
454c2c66affSColin Finck }
455c2c66affSColin Finck 
456c2c66affSColin Finck 
457c2c66affSColin Finck /* EOF */
458