2008-03-09 14:11:42 +00:00
|
|
|
/*
|
2005-01-26 13:58:37 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
2005-05-09 01:38:29 +00:00
|
|
|
* PROJECT: ReactOS kernel
|
2005-01-26 13:58:37 +00:00
|
|
|
* FILE: ntoskrnl/mm/balance.c
|
|
|
|
* PURPOSE: kernel memory managment functions
|
2005-05-09 01:38:29 +00:00
|
|
|
*
|
2005-01-26 13:58:37 +00:00
|
|
|
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
2001-12-28 00:04:45 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
2001-12-28 00:04:45 +00:00
|
|
|
#define NDEBUG
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
2001-12-28 00:04:45 +00:00
|
|
|
|
2005-11-28 23:25:31 +00:00
|
|
|
#if defined (ALLOC_PRAGMA)
|
|
|
|
#pragma alloc_text(INIT, MmInitializeBalancer)
|
|
|
|
#pragma alloc_text(INIT, MmInitializeMemoryConsumer)
|
|
|
|
#pragma alloc_text(INIT, MiInitBalancerThread)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2001-12-28 00:04:45 +00:00
|
|
|
/* TYPES ********************************************************************/
|
2001-12-31 01:53:46 +00:00
|
|
|
typedef struct _MM_ALLOCATION_REQUEST
|
|
|
|
{
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2004-04-10 22:36:07 +00:00
|
|
|
LIST_ENTRY ListEntry;
|
|
|
|
KEVENT Event;
|
|
|
|
}
|
|
|
|
MM_ALLOCATION_REQUEST, *PMM_ALLOCATION_REQUEST;
|
2001-12-31 01:53:46 +00:00
|
|
|
|
2001-12-28 00:04:45 +00:00
|
|
|
/* GLOBALS ******************************************************************/
|
|
|
|
|
2004-04-22 01:57:49 +00:00
|
|
|
MM_MEMORY_CONSUMER MiMemoryConsumers[MC_MAXIMUM];
|
2001-12-28 00:04:45 +00:00
|
|
|
static ULONG MiMinimumAvailablePages;
|
|
|
|
static ULONG MiNrTotalPages;
|
2001-12-31 01:53:46 +00:00
|
|
|
static LIST_ENTRY AllocationListHead;
|
|
|
|
static KSPIN_LOCK AllocationListLock;
|
2002-01-01 00:21:57 +00:00
|
|
|
static ULONG MiPagesRequired = 0;
|
2003-06-14 17:53:25 +00:00
|
|
|
static ULONG MiMinimumPagesPerRun = 10;
|
2001-12-28 00:04:45 +00:00
|
|
|
|
2003-11-16 15:20:39 +00:00
|
|
|
static CLIENT_ID MiBalancerThreadId;
|
|
|
|
static HANDLE MiBalancerThreadHandle = NULL;
|
|
|
|
static KEVENT MiBalancerEvent;
|
|
|
|
static KTIMER MiBalancerTimer;
|
|
|
|
static LONG MiBalancerWork = 0;
|
|
|
|
|
2001-12-28 00:04:45 +00:00
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
VOID
|
|
|
|
INIT_FUNCTION
|
|
|
|
NTAPI
|
2003-10-23 20:28:08 +00:00
|
|
|
MmInitializeBalancer(ULONG NrAvailablePages, ULONG NrSystemPages)
|
2001-12-28 00:04:45 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
memset(MiMemoryConsumers, 0, sizeof(MiMemoryConsumers));
|
|
|
|
InitializeListHead(&AllocationListHead);
|
|
|
|
KeInitializeSpinLock(&AllocationListLock);
|
|
|
|
|
2004-07-31 09:44:36 +00:00
|
|
|
MiNrTotalPages = NrAvailablePages;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/* Set up targets. */
|
|
|
|
MiMinimumAvailablePages = 64;
|
2009-02-18 16:56:42 +00:00
|
|
|
if ((NrAvailablePages + NrSystemPages) >= 8192)
|
|
|
|
{
|
|
|
|
MiMemoryConsumers[MC_CACHE].PagesTarget = NrAvailablePages / 4 * 3;
|
|
|
|
}
|
|
|
|
else if ((NrAvailablePages + NrSystemPages) >= 4096)
|
|
|
|
{
|
|
|
|
MiMemoryConsumers[MC_CACHE].PagesTarget = NrAvailablePages / 3 * 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MiMemoryConsumers[MC_CACHE].PagesTarget = NrAvailablePages / 8;
|
|
|
|
}
|
2010-10-19 16:58:27 +00:00
|
|
|
MiMemoryConsumers[MC_USER].PagesTarget = NrAvailablePages - MiMinimumAvailablePages;
|
2001-12-28 00:04:45 +00:00
|
|
|
}
|
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
VOID
|
|
|
|
INIT_FUNCTION
|
|
|
|
NTAPI
|
2004-04-10 22:36:07 +00:00
|
|
|
MmInitializeMemoryConsumer(ULONG Consumer,
|
|
|
|
NTSTATUS (*Trim)(ULONG Target, ULONG Priority,
|
|
|
|
PULONG NrFreed))
|
2001-12-28 00:04:45 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
MiMemoryConsumers[Consumer].Trim = Trim;
|
2001-12-28 00:04:45 +00:00
|
|
|
}
|
|
|
|
|
2010-09-27 21:58:54 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
MiZeroPhysicalPage(
|
|
|
|
IN PFN_NUMBER PageFrameIndex
|
|
|
|
);
|
|
|
|
|
2001-12-28 00:04:45 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2010-07-15 22:50:12 +00:00
|
|
|
MmReleasePageMemoryConsumer(ULONG Consumer, PFN_NUMBER Page)
|
2001-12-28 00:04:45 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PMM_ALLOCATION_REQUEST Request;
|
|
|
|
PLIST_ENTRY Entry;
|
2009-09-30 18:24:00 +00:00
|
|
|
KIRQL OldIrql;
|
2001-12-31 01:53:46 +00:00
|
|
|
|
2004-08-01 07:24:59 +00:00
|
|
|
if (Page == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2002-01-01 00:21:57 +00:00
|
|
|
DPRINT1("Tried to release page zero.\n");
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2002-01-01 00:21:57 +00:00
|
|
|
|
2009-09-30 18:24:00 +00:00
|
|
|
KeAcquireSpinLock(&AllocationListLock, &OldIrql);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (MmGetReferenceCountPage(Page) == 1)
|
|
|
|
{
|
2006-03-04 17:27:40 +00:00
|
|
|
(void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
|
2009-10-18 13:55:44 +00:00
|
|
|
if (IsListEmpty(&AllocationListHead) || MmAvailablePages < MiMinimumAvailablePages)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2009-09-30 18:24:00 +00:00
|
|
|
KeReleaseSpinLock(&AllocationListLock, OldIrql);
|
2010-02-19 17:55:22 +00:00
|
|
|
if(Consumer == MC_USER) MmRemoveLRUUserPage(Page);
|
2009-09-30 18:24:00 +00:00
|
|
|
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
|
2004-04-10 22:36:07 +00:00
|
|
|
MmDereferencePage(Page);
|
2009-09-30 18:24:00 +00:00
|
|
|
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2002-08-14 20:58:39 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Entry = RemoveHeadList(&AllocationListHead);
|
|
|
|
Request = CONTAINING_RECORD(Entry, MM_ALLOCATION_REQUEST, ListEntry);
|
2009-09-30 18:24:00 +00:00
|
|
|
KeReleaseSpinLock(&AllocationListLock, OldIrql);
|
2008-03-13 15:26:17 +00:00
|
|
|
if(Consumer == MC_USER) MmRemoveLRUUserPage(Page);
|
2010-09-27 21:58:54 +00:00
|
|
|
MiZeroPhysicalPage(Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
Request->Page = Page;
|
|
|
|
KeSetEvent(&Request->Event, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-09-30 18:24:00 +00:00
|
|
|
KeReleaseSpinLock(&AllocationListLock, OldIrql);
|
2008-03-13 15:26:17 +00:00
|
|
|
if(Consumer == MC_USER) MmRemoveLRUUserPage(Page);
|
2009-09-30 18:24:00 +00:00
|
|
|
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
|
2002-08-14 20:58:39 +00:00
|
|
|
MmDereferencePage(Page);
|
2009-09-30 18:24:00 +00:00
|
|
|
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2002-06-10 21:34:38 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2001-12-28 00:04:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2001-12-28 00:04:45 +00:00
|
|
|
MiTrimMemoryConsumer(ULONG Consumer)
|
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
LONG Target;
|
|
|
|
ULONG NrFreedPages;
|
2001-12-28 00:04:45 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
Target = MiMemoryConsumers[Consumer].PagesUsed -
|
|
|
|
MiMemoryConsumers[Consumer].PagesTarget;
|
|
|
|
if (Target < 1)
|
|
|
|
{
|
2001-12-28 00:04:45 +00:00
|
|
|
Target = 1;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-12-28 00:04:45 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
if (MiMemoryConsumers[Consumer].Trim != NULL)
|
|
|
|
{
|
2002-06-10 21:34:38 +00:00
|
|
|
MiMemoryConsumers[Consumer].Trim(Target, 0, &NrFreedPages);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2001-12-28 00:04:45 +00:00
|
|
|
}
|
|
|
|
|
- Create mmsup.c in ReactOS memory manager directory. It hosts misc support functions:
- Copy kmap.c here, since it's the very definition of "misc support function"
- Copy some exported functions in mm.c which were listed as "misc functions"
- Warn that current implementation of MmIsNonPagedSystemAddressValid will kill kittens.
- Rename mm.c to mmfault.c, since other than the misc functions now in mmsup.c, it was all routines to handle page/access faults.
- Warn that MmIsAddressValid, as currently implemented, kills puppies.
- Move WriteWatch functions to virtual.c since they're part of the Virtual API system call set already hosted there.
- Move the global variables that people had been throwing in here to mminit.c, which is slightly more appropriate.
- Move wset.c's MmTrimUserMemory to balance.c, since that's where all other similar functions are located.
- Incidentally, kill wset.c, as this was the only function present.
- No functional changes, just refactoring and cleanup (other than warning the critter murder the two broken functions will achieve if called).
svn path=/trunk/; revision=41659
2009-06-28 07:52:30 +00:00
|
|
|
NTSTATUS
|
|
|
|
MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
|
|
|
|
{
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER CurrentPage;
|
|
|
|
PFN_NUMBER NextPage;
|
- Create mmsup.c in ReactOS memory manager directory. It hosts misc support functions:
- Copy kmap.c here, since it's the very definition of "misc support function"
- Copy some exported functions in mm.c which were listed as "misc functions"
- Warn that current implementation of MmIsNonPagedSystemAddressValid will kill kittens.
- Rename mm.c to mmfault.c, since other than the misc functions now in mmsup.c, it was all routines to handle page/access faults.
- Warn that MmIsAddressValid, as currently implemented, kills puppies.
- Move WriteWatch functions to virtual.c since they're part of the Virtual API system call set already hosted there.
- Move the global variables that people had been throwing in here to mminit.c, which is slightly more appropriate.
- Move wset.c's MmTrimUserMemory to balance.c, since that's where all other similar functions are located.
- Incidentally, kill wset.c, as this was the only function present.
- No functional changes, just refactoring and cleanup (other than warning the critter murder the two broken functions will achieve if called).
svn path=/trunk/; revision=41659
2009-06-28 07:52:30 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
(*NrFreedPages) = 0;
|
|
|
|
|
|
|
|
CurrentPage = MmGetLRUFirstUserPage();
|
|
|
|
while (CurrentPage != 0 && Target > 0)
|
|
|
|
{
|
|
|
|
NextPage = MmGetLRUNextUserPage(CurrentPage);
|
|
|
|
|
|
|
|
Status = MmPageOutPhysicalAddress(CurrentPage);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT("Succeeded\n");
|
|
|
|
Target--;
|
|
|
|
(*NrFreedPages)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
CurrentPage = NextPage;
|
|
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2001-12-28 00:04:45 +00:00
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2003-07-12 01:52:10 +00:00
|
|
|
MmRebalanceMemoryConsumers(VOID)
|
2001-12-28 00:04:45 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
LONG Target;
|
|
|
|
ULONG i;
|
|
|
|
ULONG NrFreedPages;
|
|
|
|
NTSTATUS Status;
|
2001-12-28 00:04:45 +00:00
|
|
|
|
2009-10-18 13:55:44 +00:00
|
|
|
Target = (MiMinimumAvailablePages - MmAvailablePages) + MiPagesRequired;
|
2004-04-10 22:36:07 +00:00
|
|
|
Target = max(Target, (LONG) MiMinimumPagesPerRun);
|
2001-12-28 00:04:45 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
for (i = 0; i < MC_MAXIMUM && Target > 0; i++)
|
|
|
|
{
|
2001-12-28 00:04:45 +00:00
|
|
|
if (MiMemoryConsumers[i].Trim != NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
Status = MiMemoryConsumers[i].Trim(Target, 0, &NrFreedPages);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
Target = Target - NrFreedPages;
|
|
|
|
}
|
|
|
|
}
|
2001-12-28 00:04:45 +00:00
|
|
|
}
|
|
|
|
|
2003-11-16 15:20:39 +00:00
|
|
|
static BOOLEAN
|
|
|
|
MiIsBalancerThread(VOID)
|
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
return MiBalancerThreadHandle != NULL &&
|
|
|
|
PsGetCurrentThread() == MiBalancerThreadId.UniqueThread;
|
2003-11-16 15:20:39 +00:00
|
|
|
}
|
|
|
|
|
2001-12-28 00:04:45 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2004-04-10 22:36:07 +00:00
|
|
|
MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
|
2010-07-15 22:50:12 +00:00
|
|
|
PPFN_NUMBER AllocatedPage)
|
2001-12-28 00:04:45 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
ULONG OldUsed;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2009-09-30 18:24:00 +00:00
|
|
|
KIRQL OldIrql;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure we don't exceed our individual target.
|
|
|
|
*/
|
2004-12-24 17:07:00 +00:00
|
|
|
OldUsed = InterlockedIncrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
|
2004-04-10 22:36:07 +00:00
|
|
|
if (OldUsed >= (MiMemoryConsumers[Consumer].PagesTarget - 1) &&
|
|
|
|
!MiIsBalancerThread())
|
|
|
|
{
|
2001-12-28 00:04:45 +00:00
|
|
|
if (!CanWait)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2006-03-04 17:27:40 +00:00
|
|
|
(void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
|
2004-04-10 22:36:07 +00:00
|
|
|
return(STATUS_NO_MEMORY);
|
|
|
|
}
|
2001-12-28 00:04:45 +00:00
|
|
|
MiTrimMemoryConsumer(Consumer);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-05-09 01:38:29 +00:00
|
|
|
* Allocate always memory for the non paged pool and for the pager thread.
|
2004-04-10 22:36:07 +00:00
|
|
|
*/
|
2010-10-19 16:58:27 +00:00
|
|
|
if ((Consumer == MC_SYSTEM) || MiIsBalancerThread())
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2009-09-30 18:24:00 +00:00
|
|
|
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
|
2010-02-20 14:47:23 +00:00
|
|
|
Page = MmAllocPage(Consumer);
|
2009-09-30 18:24:00 +00:00
|
|
|
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
2004-08-01 07:24:59 +00:00
|
|
|
if (Page == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2008-08-24 15:48:05 +00:00
|
|
|
KeBugCheck(NO_PAGES_AVAILABLE);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2003-11-16 15:20:39 +00:00
|
|
|
*AllocatedPage = Page;
|
2009-10-18 13:55:44 +00:00
|
|
|
if (MmAvailablePages <= MiMinimumAvailablePages &&
|
2004-04-10 22:36:07 +00:00
|
|
|
MiBalancerThreadHandle != NULL)
|
|
|
|
{
|
|
|
|
KeSetEvent(&MiBalancerEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
2003-11-16 15:20:39 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2003-11-16 15:20:39 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
/*
|
|
|
|
* Make sure we don't exceed global targets.
|
|
|
|
*/
|
2009-10-18 13:55:44 +00:00
|
|
|
if (MmAvailablePages <= MiMinimumAvailablePages)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2001-12-31 01:53:46 +00:00
|
|
|
MM_ALLOCATION_REQUEST Request;
|
|
|
|
|
2001-12-28 00:04:45 +00:00
|
|
|
if (!CanWait)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2006-03-04 17:27:40 +00:00
|
|
|
(void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
|
2004-04-10 22:36:07 +00:00
|
|
|
return(STATUS_NO_MEMORY);
|
|
|
|
}
|
2001-12-31 01:53:46 +00:00
|
|
|
|
|
|
|
/* Insert an allocation request. */
|
2004-08-01 07:24:59 +00:00
|
|
|
Request.Page = 0;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2001-12-31 01:53:46 +00:00
|
|
|
KeInitializeEvent(&Request.Event, NotificationEvent, FALSE);
|
2006-03-04 17:27:40 +00:00
|
|
|
(void)InterlockedIncrementUL(&MiPagesRequired);
|
2002-01-01 00:21:57 +00:00
|
|
|
|
2009-09-30 18:24:00 +00:00
|
|
|
KeAcquireSpinLock(&AllocationListLock, &OldIrql);
|
2003-11-16 15:20:39 +00:00
|
|
|
|
|
|
|
if (MiBalancerThreadHandle != NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
KeSetEvent(&MiBalancerEvent, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
2003-07-12 01:52:10 +00:00
|
|
|
InsertTailList(&AllocationListHead, &Request.ListEntry);
|
2009-09-30 18:24:00 +00:00
|
|
|
KeReleaseSpinLock(&AllocationListLock, OldIrql);
|
2003-07-12 01:52:10 +00:00
|
|
|
|
2002-02-28 17:44:48 +00:00
|
|
|
KeWaitForSingleObject(&Request.Event,
|
2004-04-10 22:36:07 +00:00
|
|
|
0,
|
|
|
|
KernelMode,
|
|
|
|
FALSE,
|
|
|
|
NULL);
|
|
|
|
|
2001-12-31 01:53:46 +00:00
|
|
|
Page = Request.Page;
|
2004-08-01 07:24:59 +00:00
|
|
|
if (Page == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2008-08-24 15:48:05 +00:00
|
|
|
KeBugCheck(NO_PAGES_AVAILABLE);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2010-02-11 18:44:28 +00:00
|
|
|
/* Update the Consumer and make the page active */
|
2008-03-13 15:26:17 +00:00
|
|
|
if(Consumer == MC_USER) MmInsertLRULastUserPage(Page);
|
2002-01-01 00:21:57 +00:00
|
|
|
*AllocatedPage = Page;
|
2006-03-04 17:27:40 +00:00
|
|
|
(void)InterlockedDecrementUL(&MiPagesRequired);
|
2002-01-01 00:21:57 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Actually allocate the page.
|
|
|
|
*/
|
2009-09-30 18:24:00 +00:00
|
|
|
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
|
2010-02-20 14:47:23 +00:00
|
|
|
Page = MmAllocPage(Consumer);
|
2009-09-30 18:24:00 +00:00
|
|
|
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
2004-08-01 07:24:59 +00:00
|
|
|
if (Page == 0)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2008-08-24 15:48:05 +00:00
|
|
|
KeBugCheck(NO_PAGES_AVAILABLE);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2008-03-13 15:26:17 +00:00
|
|
|
if(Consumer == MC_USER) MmInsertLRULastUserPage(Page);
|
2004-04-10 22:36:07 +00:00
|
|
|
*AllocatedPage = Page;
|
2001-12-28 00:04:45 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
return(STATUS_SUCCESS);
|
2001-12-28 00:04:45 +00:00
|
|
|
}
|
2003-07-10 21:05:04 +00:00
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
VOID NTAPI
|
2003-11-16 15:20:39 +00:00
|
|
|
MiBalancerThread(PVOID Unused)
|
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID WaitObjects[2];
|
|
|
|
NTSTATUS Status;
|
|
|
|
ULONG i;
|
|
|
|
ULONG NrFreedPages;
|
|
|
|
ULONG NrPagesUsed;
|
|
|
|
ULONG Target;
|
|
|
|
BOOLEAN ShouldRun;
|
2003-11-16 15:20:39 +00:00
|
|
|
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
WaitObjects[0] = &MiBalancerEvent;
|
|
|
|
WaitObjects[1] = &MiBalancerTimer;
|
2003-11-16 15:20:39 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
while (1)
|
|
|
|
{
|
2003-11-16 15:20:39 +00:00
|
|
|
Status = KeWaitForMultipleObjects(2,
|
2004-04-10 22:36:07 +00:00
|
|
|
WaitObjects,
|
|
|
|
WaitAny,
|
|
|
|
Executive,
|
|
|
|
KernelMode,
|
|
|
|
FALSE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2003-11-16 15:20:39 +00:00
|
|
|
|
|
|
|
if (Status == STATUS_SUCCESS)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
/* MiBalancerEvent */
|
2009-10-18 13:55:44 +00:00
|
|
|
while (MmAvailablePages < MiMinimumAvailablePages + 5)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
for (i = 0; i < MC_MAXIMUM; i++)
|
|
|
|
{
|
|
|
|
if (MiMemoryConsumers[i].Trim != NULL)
|
|
|
|
{
|
|
|
|
NrFreedPages = 0;
|
|
|
|
Status = MiMemoryConsumers[i].Trim(MiMinimumPagesPerRun, 0, &NrFreedPages);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
InterlockedExchange(&MiBalancerWork, 0);
|
|
|
|
}
|
2003-11-16 15:20:39 +00:00
|
|
|
else if (Status == STATUS_SUCCESS + 1)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
/* MiBalancerTimer */
|
2009-10-18 13:55:44 +00:00
|
|
|
ShouldRun = MmAvailablePages < MiMinimumAvailablePages + 5 ? TRUE : FALSE;
|
2004-04-10 22:36:07 +00:00
|
|
|
for (i = 0; i < MC_MAXIMUM; i++)
|
|
|
|
{
|
|
|
|
if (MiMemoryConsumers[i].Trim != NULL)
|
|
|
|
{
|
|
|
|
NrPagesUsed = MiMemoryConsumers[i].PagesUsed;
|
|
|
|
if (NrPagesUsed > MiMemoryConsumers[i].PagesTarget || ShouldRun)
|
|
|
|
{
|
|
|
|
if (NrPagesUsed > MiMemoryConsumers[i].PagesTarget)
|
|
|
|
{
|
|
|
|
Target = max (NrPagesUsed - MiMemoryConsumers[i].PagesTarget,
|
|
|
|
MiMinimumPagesPerRun);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Target = MiMinimumPagesPerRun;
|
|
|
|
}
|
|
|
|
NrFreedPages = 0;
|
|
|
|
Status = MiMemoryConsumers[i].Trim(Target, 0, &NrFreedPages);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-11-16 15:20:39 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2004-08-01 21:57:35 +00:00
|
|
|
DPRINT1("KeWaitForMultipleObjects failed, status = %x\n", Status);
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
2003-11-16 15:20:39 +00:00
|
|
|
}
|
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
VOID
|
|
|
|
INIT_FUNCTION
|
|
|
|
NTAPI
|
2003-11-16 15:20:39 +00:00
|
|
|
MiInitBalancerThread(VOID)
|
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
KPRIORITY Priority;
|
|
|
|
NTSTATUS Status;
|
2003-12-30 18:52:06 +00:00
|
|
|
#if !defined(__GNUC__)
|
2004-04-10 22:36:07 +00:00
|
|
|
|
|
|
|
LARGE_INTEGER dummyJunkNeeded;
|
|
|
|
dummyJunkNeeded.QuadPart = -20000000; /* 2 sec */
|
|
|
|
;
|
2003-12-30 18:52:06 +00:00
|
|
|
#endif
|
2003-11-16 15:20:39 +00:00
|
|
|
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
KeInitializeEvent(&MiBalancerEvent, SynchronizationEvent, FALSE);
|
|
|
|
KeInitializeTimerEx(&MiBalancerTimer, SynchronizationTimer);
|
|
|
|
KeSetTimerEx(&MiBalancerTimer,
|
2003-12-30 18:52:06 +00:00
|
|
|
#if defined(__GNUC__)
|
2004-04-10 22:36:07 +00:00
|
|
|
(LARGE_INTEGER)(LONGLONG)-20000000LL, /* 2 sec */
|
2003-12-30 18:52:06 +00:00
|
|
|
#else
|
2004-04-10 22:36:07 +00:00
|
|
|
dummyJunkNeeded,
|
2003-12-30 18:52:06 +00:00
|
|
|
#endif
|
2004-04-10 22:36:07 +00:00
|
|
|
2000, /* 2 sec */
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
Status = PsCreateSystemThread(&MiBalancerThreadHandle,
|
|
|
|
THREAD_ALL_ACCESS,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&MiBalancerThreadId,
|
|
|
|
(PKSTART_ROUTINE) MiBalancerThread,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Priority = LOW_REALTIME_PRIORITY + 1;
|
|
|
|
NtSetInformationThread(MiBalancerThreadHandle,
|
|
|
|
ThreadPriority,
|
|
|
|
&Priority,
|
|
|
|
sizeof(Priority));
|
|
|
|
|
2003-11-16 15:20:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-10 21:05:04 +00:00
|
|
|
/* EOF */
|