ReactOS 0.4.15-dev-7842-g558ab78
balance.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: kernel memory management functions
5 * PROGRAMMERS: David Welch <welch@cwcom.net>
6 * Cameron Gutman <cameron.gutman@reactos.org>
7 */
8
9/* INCLUDES *****************************************************************/
10
11#include <ntoskrnl.h>
12#define NDEBUG
13#include <debug.h>
14
15#include "ARM3/miarm.h"
16
17
18/* TYPES ********************************************************************/
20{
24}
26/* GLOBALS ******************************************************************/
27
36
38
39/* FUNCTIONS ****************************************************************/
40
41CODE_SEG("INIT")
42VOID
44MmInitializeBalancer(ULONG NrAvailablePages, ULONG NrSystemPages)
45{
47
48 /* Set up targets. */
51 MiMemoryConsumers[MC_USER].PagesTarget = NrAvailablePages / 2;
52}
53
54CODE_SEG("INIT")
55VOID
58 ULONG Consumer,
59 NTSTATUS (*Trim)(ULONG Target, ULONG Priority, PULONG NrFreed))
60{
61 MiMemoryConsumers[Consumer].Trim = Trim;
62}
63
64VOID
67 IN PFN_NUMBER PageFrameIndex
68);
69
73{
75
76 if (Page == 0)
77 {
78 DPRINT1("Tried to release page zero.\n");
79 KeBugCheck(MEMORY_MANAGEMENT);
80 }
81
82 (void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
84
85 OldIrql = MiAcquirePfnLock();
86
88
89 MiReleasePfnLock(OldIrql);
90
91 return(STATUS_SUCCESS);
92}
93
96MiTrimMemoryConsumer(ULONG Consumer, ULONG InitialTarget)
97{
98 ULONG Target = InitialTarget;
99 ULONG NrFreedPages = 0;
101
102 /* Make sure we can trim this consumer */
103 if (!MiMemoryConsumers[Consumer].Trim)
104 {
105 /* Return the unmodified initial target */
106 return InitialTarget;
107 }
108
110 {
111 /* Global page limit exceeded */
113 }
114 else if (MiMemoryConsumers[Consumer].PagesUsed > MiMemoryConsumers[Consumer].PagesTarget)
115 {
116 /* Consumer page limit exceeded */
117 Target = max(Target, MiMemoryConsumers[Consumer].PagesUsed - MiMemoryConsumers[Consumer].PagesTarget);
118 }
119
120 if (Target)
121 {
122 /* Now swap the pages out */
124
125 DPRINT("Trimming consumer %lu: Freed %lu pages with a target of %lu pages\n", Consumer, NrFreedPages, Target);
126
127 if (!NT_SUCCESS(Status))
128 {
129 KeBugCheck(MEMORY_MANAGEMENT);
130 }
131 }
132
133 /* Return the page count needed to be freed to meet the initial target */
134 return (InitialTarget > NrFreedPages) ? (InitialTarget - NrFreedPages) : 0;
135}
136
139{
140 PFN_NUMBER FirstPage, CurrentPage;
142
143 (*NrFreedPages) = 0;
144
145 DPRINT("MM BALANCER: %s\n", Priority ? "Paging out!" : "Removing access bit!");
146
147 FirstPage = MmGetLRUFirstUserPage();
148 CurrentPage = FirstPage;
149 while (CurrentPage != 0 && Target > 0)
150 {
151 if (Priority)
152 {
153 Status = MmPageOutPhysicalAddress(CurrentPage);
154 if (NT_SUCCESS(Status))
155 {
156 DPRINT("Succeeded\n");
157 Target--;
158 (*NrFreedPages)++;
159 if (CurrentPage == FirstPage)
160 {
161 FirstPage = 0;
162 }
163 }
164 }
165 else
166 {
167 /* When not paging-out agressively, just reset the accessed bit */
170 BOOLEAN Accessed = FALSE;
171
172 /*
173 * We have a lock-ordering problem here. We cant lock the PFN DB before the Process address space.
174 * So we must use circonvoluted loops.
175 * Well...
176 */
177 while (TRUE)
178 {
180 KIRQL OldIrql = MiAcquirePfnLock();
182 while (Entry)
183 {
184 if (RMAP_IS_SEGMENT(Entry->Address))
185 {
186 Entry = Entry->Next;
187 continue;
188 }
189
190 /* Check that we didn't treat this entry before */
191 if (Entry->Address < Address)
192 {
193 Entry = Entry->Next;
194 continue;
195 }
196
197 if ((Entry->Address == Address) && (Entry->Process <= Process))
198 {
199 Entry = Entry->Next;
200 continue;
201 }
202
203 break;
204 }
205
206 if (!Entry)
207 {
208 MiReleasePfnLock(OldIrql);
209 break;
210 }
211
212 Process = Entry->Process;
213 Address = Entry->Address;
214
216
217 if (!ExAcquireRundownProtection(&Process->RundownProtect))
218 {
220 MiReleasePfnLock(OldIrql);
221 continue;
222 }
223
224 MiReleasePfnLock(OldIrql);
225
228
229 /* Be sure this is still valid. */
231 {
233 Accessed = Accessed || Pte->u.Hard.Accessed;
234 Pte->u.Hard.Accessed = 0;
235
236 /* There is no need to invalidate, the balancer thread is never on a user process */
237 //KeInvalidateTlbEntry(Address);
238 }
239
241
243 ExReleaseRundownProtection(&Process->RundownProtect);
245 }
246
247 if (!Accessed)
248 {
249 /* Nobody accessed this page since the last time we check. Time to clean up */
250
251 Status = MmPageOutPhysicalAddress(CurrentPage);
252 if (NT_SUCCESS(Status))
253 {
254 if (CurrentPage == FirstPage)
255 {
256 FirstPage = 0;
257 }
258 }
259 // DPRINT1("Paged-out one page: %s\n", NT_SUCCESS(Status) ? "Yes" : "No");
260 }
261
262 /* Done for this page. */
263 Target--;
264 }
265
266 CurrentPage = MmGetLRUNextUserPage(CurrentPage, TRUE);
267 if (FirstPage == 0)
268 {
269 FirstPage = CurrentPage;
270 }
271 else if (CurrentPage == FirstPage)
272 {
273 DPRINT1("We are back at the start, abort!\n");
274 return STATUS_SUCCESS;
275 }
276 }
277
278 if (CurrentPage)
279 {
280 KIRQL OldIrql = MiAcquirePfnLock();
281 MmDereferencePage(CurrentPage);
282 MiReleasePfnLock(OldIrql);
283 }
284
285 return STATUS_SUCCESS;
286}
287
288VOID
289NTAPI
291{
292 // if (InterlockedCompareExchange(&PageOutThreadActive, 0, 1) == 0)
293 {
295 }
296}
297
298VOID
299NTAPI
301{
302 ASSERT(PsGetCurrentProcess()->AddressCreationLock.Owner != KeGetCurrentThread());
305
309}
310
312NTAPI
314 PPFN_NUMBER AllocatedPage)
315{
317 static INT i = 0;
318 static LARGE_INTEGER TinyTime = {{-1L, -1L}};
319
320 /* Delay some requests for the Memory Manager to recover pages */
321 if (i++ >= 100)
322 {
324 i = 0;
325 }
326
327 /*
328 * Actually allocate the page.
329 */
330 Page = MmAllocPage(Consumer);
331 if (Page == 0)
332 {
333 *AllocatedPage = 0;
334 return STATUS_NO_MEMORY;
335 }
336 *AllocatedPage = Page;
337
338 /* Update the target */
339 InterlockedIncrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
341
342 return(STATUS_SUCCESS);
343}
344
345VOID
348 _Out_ PULONG NrFreed);
349
352{
353 PVOID WaitObjects[2];
355 ULONG i;
356
357 WaitObjects[0] = &MiBalancerEvent;
358 WaitObjects[1] = &MiBalancerTimer;
359
360 while (1)
361 {
364 WaitObjects,
365 WaitAny,
366 Executive,
368 FALSE,
369 NULL,
370 NULL);
371
373 {
374 ULONG InitialTarget = 0;
376 ULONG NrFreedPages;
377
378 do
379 {
380 ULONG OldTarget = InitialTarget;
381
382 /* Trim each consumer */
383 for (i = 0; i < MC_MAXIMUM; i++)
384 {
385 InitialTarget = MiTrimMemoryConsumer(i, InitialTarget);
386 }
387
388 /* Trim cache */
390 if (Target)
391 {
392 CcRosTrimCache(Target, &NrFreedPages);
393 InitialTarget -= min(NrFreedPages, InitialTarget);
394 }
395
396 /* No pages left to swap! */
397 if (InitialTarget != 0 &&
398 InitialTarget == OldTarget)
399 {
400 /* Game over */
401 KeBugCheck(NO_PAGES_AVAILABLE);
402 }
403 }
404 while (InitialTarget != 0);
405
406 if (Status == STATUS_WAIT_0)
408 }
409 else
410 {
411 DPRINT1("KeWaitForMultipleObjects failed, status = %x\n", Status);
412 KeBugCheck(MEMORY_MANAGEMENT);
413 }
414 }
415}
416
417CODE_SEG("INIT")
418VOID
419NTAPI
421{
425
429
430 Timeout.QuadPart = -20000000; /* 2 sec */
432 Timeout,
433 2000, /* 2 sec */
434 NULL);
435
438 NULL,
439 NULL,
442 NULL);
443 if (!NT_SUCCESS(Status))
444 {
445 KeBugCheck(MEMORY_MANAGEMENT);
446 }
447
451 &Priority,
452 sizeof(Priority));
453
454}
455
456
457/* EOF */
unsigned char BOOLEAN
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1431
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
@ ThreadPriority
Definition: compat.h:937
LONG KPRIORITY
Definition: compat.h:803
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define KeDelayExecutionThread(mode, foo, t)
Definition: env_spec_w32.h:484
LONG NTAPI KeResetEvent(IN PKEVENT Event)
Definition: eventobj.c:133
#define InterlockedDecrementUL(Addend)
Definition: ex.h:1524
#define ExReleaseRundownProtection
Definition: ex.h:136
#define InterlockedIncrementUL(Addend)
Definition: ex.h:1527
#define ExAcquireRundownProtection
Definition: ex.h:135
#define abs(i)
Definition: fconv.c:206
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define KeGetCurrentThread
Definition: hal.h:55
#define LOW_REALTIME_PRIORITY
static CODE_SEG("PAGE")
Definition: isapnp.c:1482
#define Unused(x)
Definition: atlwin.h:28
FORCEINLINE VOID MiUnlockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1194
FORCEINLINE BOOLEAN MM_ANY_WS_LOCK_HELD(IN PETHREAD Thread)
Definition: miarm.h:1052
FORCEINLINE VOID MiLockProcessWorkingSet(IN PEPROCESS Process, IN PETHREAD Thread)
Definition: miarm.h:1124
BOOLEAN NTAPI MmIsAddressValid(IN PVOID VirtualAddress)
Definition: mmsup.c:174
#define MiAddressToPte(x)
Definition: mmx86.c:19
#define ASSERT(a)
Definition: mode.c:44
#define min(a, b)
Definition: monoChain.cc:55
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define KernelMode
Definition: asm.h:34
#define THREAD_ALL_ACCESS
Definition: nt_native.h:1339
@ SynchronizationEvent
@ WaitAny
@ SynchronizationTimer
PFN_NUMBER NTAPI MmAllocPage(ULONG Consumer)
Definition: freelist.c:601
struct _MM_RMAP_ENTRY *NTAPI MmGetRmapListHeadPage(PFN_NUMBER Page)
Definition: freelist.c:458
VOID NTAPI MmDereferencePage(PFN_NUMBER Page)
Definition: freelist.c:565
#define MC_USER
Definition: mm.h:114
#define RMAP_IS_SEGMENT(x)
Definition: mm.h:940
_In_ PVOID _Out_opt_ BOOLEAN _Out_opt_ PPFN_NUMBER Page
Definition: mm.h:1306
PFN_NUMBER NTAPI MmGetLRUFirstUserPage(VOID)
Definition: freelist.c:45
FORCEINLINE VOID UpdateTotalCommittedPages(LONG Delta)
Definition: mm.h:871
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1765
PFN_NUMBER MmAvailablePages
Definition: freelist.c:26
#define MC_MAXIMUM
Definition: mm.h:116
PFN_NUMBER NTAPI MmGetLRUNextUserPage(PFN_NUMBER PreviousPage, BOOLEAN MoveToLast)
Definition: freelist.c:125
NTSTATUS NTAPI MmPageOutPhysicalAddress(PFN_NUMBER Page)
Definition: rmap.c:51
NTSTATUS NTAPI KeWaitForMultipleObjects(IN ULONG Count, IN PVOID Object[], IN WAIT_TYPE WaitType, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL, OUT PKWAIT_BLOCK WaitBlockArray OPTIONAL)
Definition: wait.c:586
static HANDLE MiBalancerThreadHandle
Definition: balance.c:32
static KTIMER MiBalancerTimer
Definition: balance.c:35
static KEVENT MiBalancerDoneEvent
Definition: balance.c:34
static CLIENT_ID MiBalancerThreadId
Definition: balance.c:31
MM_MEMORY_CONSUMER MiMemoryConsumers[MC_MAXIMUM]
Definition: balance.c:28
VOID NTAPI MiBalancerThread(PVOID Unused)
Definition: balance.c:351
VOID NTAPI MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex)
Definition: pfnlist.c:122
static ULONG MiMinimumAvailablePages
Definition: balance.c:29
VOID NTAPI MmRebalanceMemoryConsumers(VOID)
Definition: balance.c:290
struct _MM_ALLOCATION_REQUEST MM_ALLOCATION_REQUEST
VOID NTAPI MmInitializeBalancer(ULONG NrAvailablePages, ULONG NrSystemPages)
Definition: balance.c:44
static KEVENT MiBalancerEvent
Definition: balance.c:33
ULONG NTAPI MiTrimMemoryConsumer(ULONG Consumer, ULONG InitialTarget)
Definition: balance.c:96
struct _MM_ALLOCATION_REQUEST * PMM_ALLOCATION_REQUEST
NTSTATUS MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
Definition: balance.c:138
VOID NTAPI MiInitBalancerThread(VOID)
Definition: balance.c:420
NTSTATUS NTAPI MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait, PPFN_NUMBER AllocatedPage)
Definition: balance.c:313
VOID CcRosTrimCache(_In_ ULONG Target, _Out_ PULONG NrFreed)
Definition: view.c:456
VOID NTAPI MmRebalanceMemoryConsumersAndWait(VOID)
Definition: balance.c:300
VOID NTAPI MmInitializeMemoryConsumer(ULONG Consumer, NTSTATUS(*Trim)(ULONG Target, ULONG Priority, PULONG NrFreed))
Definition: balance.c:57
static LONG PageOutThreadActive
Definition: balance.c:37
static ULONG MiMinimumPagesPerRun
Definition: balance.c:30
NTSTATUS NTAPI MmReleasePageMemoryConsumer(ULONG Consumer, PFN_NUMBER Page)
Definition: balance.c:72
NTSTATUS NTAPI NtSetInformationThread(IN HANDLE ThreadHandle, IN THREADINFOCLASS ThreadInformationClass, IN PVOID ThreadInformation, IN ULONG ThreadInformationLength)
Definition: query.c:2018
NTSTATUS NTAPI PsCreateSystemThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PCLIENT_ID ClientId, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext)
Definition: thread.c:602
#define STATUS_WAIT_0
Definition: ntstatus.h:237
#define STATUS_WAIT_1
Definition: ntstatus.h:71
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
long LONG
Definition: pedump.c:60
static WCHAR Address[46]
Definition: ping.c:68
static ULONG Timeout
Definition: ping.c:61
VOID NTAPI KeStackAttachProcess(IN PKPROCESS Process, OUT PRKAPC_STATE ApcState)
Definition: procobj.c:704
VOID NTAPI KeUnstackDetachProcess(IN PRKAPC_STATE ApcState)
Definition: procobj.c:756
ULONG * PPFN_NUMBER
Definition: ke.h:9
ULONG PFN_NUMBER
Definition: ke.h:9
#define memset(x, y, z)
Definition: compat.h:39
static LARGE_INTEGER TinyTime
Definition: section.c:63
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
base of all file and directory entries
Definition: entries.h:83
Definition: typedefs.h:120
ULONG64 Accessed
Definition: mmtypes.h:163
union _MMPTE::@2325 u
MMPTE_HARDWARE Hard
Definition: mmtypes.h:217
PFN_NUMBER Page
Definition: balance.c:21
LIST_ENTRY ListEntry
Definition: balance.c:22
NTSTATUS(* Trim)(ULONG Target, ULONG Priority, PULONG NrFreed)
Definition: mm.h:459
ULONG PagesTarget
Definition: mm.h:458
Definition: mm.h:266
#define max(a, b)
Definition: svc.c:63
BOOLEAN NTAPI KeSetTimerEx(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN LONG Period, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:294
VOID NTAPI KeInitializeTimerEx(OUT PKTIMER Timer, IN TIMER_TYPE Type)
Definition: timerobj.c:244
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
int32_t INT
Definition: typedefs.h:58
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
_In_ WDFINTERRUPT _In_ WDF_INTERRUPT_POLICY _In_ WDF_INTERRUPT_PRIORITY Priority
Definition: wdfinterrupt.h:655
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
#define IO_NO_INCREMENT
Definition: iotypes.h:598
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
@ Executive
Definition: ketypes.h:415
KAPC_STATE
Definition: ketypes.h:1409
#define ObDereferenceObject
Definition: obfuncs.h:203
#define ObReferenceObject
Definition: obfuncs.h:204
#define PsGetCurrentProcess
Definition: psfuncs.h:17