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