#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, MmInitializeBalancer)
VOID MmPrintMemoryStatistic(VOID)
{
- DbgPrint("MC_CACHE %d, MC_USER %d, MC_PPOOL %d, MC_NPPOOL %d, MmStats.NrFreePages %d\n",
+ DbgPrint("MC_CACHE %d, MC_USER %d, MC_PPOOL %d, MC_NPPOOL %d, MmAvailablePages %d\n",
MiMemoryConsumers[MC_CACHE].PagesUsed, MiMemoryConsumers[MC_USER].PagesUsed,
MiMemoryConsumers[MC_PPOOL].PagesUsed, MiMemoryConsumers[MC_NPPOOL].PagesUsed,
- MmStats.NrFreePages);
+ MmAvailablePages);
}
VOID
/* Set up targets. */
MiMinimumAvailablePages = 64;
- MiMemoryConsumers[MC_CACHE].PagesTarget = NrAvailablePages / 2;
+ 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;
+ }
MiMemoryConsumers[MC_USER].PagesTarget =
NrAvailablePages - MiMinimumAvailablePages;
MiMemoryConsumers[MC_PPOOL].PagesTarget = NrAvailablePages / 2;
MiMemoryConsumers[MC_NPPOOL].PagesTarget = 0xFFFFFFFF;
MiMemoryConsumers[MC_NPPOOL].PagesUsed = NrSystemPages;
+ MiMemoryConsumers[MC_SYSTEM].PagesTarget = 0xFFFFFFFF;
+ MiMemoryConsumers[MC_SYSTEM].PagesUsed = 0;
}
VOID
{
PMM_ALLOCATION_REQUEST Request;
PLIST_ENTRY Entry;
- KIRQL oldIrql;
+ KIRQL OldIrql;
if (Page == 0)
{
DPRINT1("Tried to release page zero.\n");
- KEBUGCHECK(0);
+ KeBugCheck(MEMORY_MANAGEMENT);
}
- KeAcquireSpinLock(&AllocationListLock, &oldIrql);
+ KeAcquireSpinLock(&AllocationListLock, &OldIrql);
if (MmGetReferenceCountPage(Page) == 1)
{
(void)InterlockedDecrementUL(&MiMemoryConsumers[Consumer].PagesUsed);
- if (IsListEmpty(&AllocationListHead) || MmStats.NrFreePages < MiMinimumAvailablePages)
+ if (IsListEmpty(&AllocationListHead) || MmAvailablePages < MiMinimumAvailablePages)
{
- KeReleaseSpinLock(&AllocationListLock, oldIrql);
+ KeReleaseSpinLock(&AllocationListLock, OldIrql);
+ if(Consumer == MC_USER) MmRemoveLRUUserPage(Page);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
MmDereferencePage(Page);
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
}
else
{
Entry = RemoveHeadList(&AllocationListHead);
Request = CONTAINING_RECORD(Entry, MM_ALLOCATION_REQUEST, ListEntry);
- KeReleaseSpinLock(&AllocationListLock, oldIrql);
+ KeReleaseSpinLock(&AllocationListLock, OldIrql);
if(Consumer == MC_USER) MmRemoveLRUUserPage(Page);
MiZeroPage(Page);
Request->Page = Page;
}
else
{
- KeReleaseSpinLock(&AllocationListLock, oldIrql);
+ KeReleaseSpinLock(&AllocationListLock, OldIrql);
if(Consumer == MC_USER) MmRemoveLRUUserPage(Page);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
MmDereferencePage(Page);
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
}
return(STATUS_SUCCESS);
}
}
+NTSTATUS
+MmTrimUserMemory(ULONG Target, ULONG Priority, PULONG NrFreedPages)
+{
+ PFN_TYPE CurrentPage;
+ PFN_TYPE NextPage;
+ 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);
+}
+
VOID
NTAPI
MmRebalanceMemoryConsumers(VOID)
ULONG NrFreedPages;
NTSTATUS Status;
- Target = (MiMinimumAvailablePages - MmStats.NrFreePages) + MiPagesRequired;
+ Target = (MiMinimumAvailablePages - MmAvailablePages) + MiPagesRequired;
Target = max(Target, (LONG) MiMinimumPagesPerRun);
for (i = 0; i < MC_MAXIMUM && Target > 0; i++)
Status = MiMemoryConsumers[i].Trim(Target, 0, &NrFreedPages);
if (!NT_SUCCESS(Status))
{
- KEBUGCHECK(0);
+ KeBugCheck(MEMORY_MANAGEMENT);
}
Target = Target - NrFreedPages;
}
PsGetCurrentThread() == MiBalancerThreadId.UniqueThread;
}
+VOID NTAPI MiSetConsumer(IN PFN_TYPE Pfn, IN ULONG Consumer);
+
NTSTATUS
NTAPI
MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
{
ULONG OldUsed;
PFN_TYPE Page;
- KIRQL oldIrql;
+ KIRQL OldIrql;
/*
* Make sure we don't exceed our individual target.
/*
* Allocate always memory for the non paged pool and for the pager thread.
*/
- if (Consumer == MC_NPPOOL || MiIsBalancerThread())
+ if ((Consumer == MC_NPPOOL) || (Consumer == MC_SYSTEM) || MiIsBalancerThread())
{
- Page = MmAllocPage(Consumer, 0);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ Page = MmAllocPage(Consumer);
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
if (Page == 0)
{
- KEBUGCHECK(NO_PAGES_AVAILABLE);
+ KeBugCheck(NO_PAGES_AVAILABLE);
}
*AllocatedPage = Page;
- if (MmStats.NrFreePages <= MiMinimumAvailablePages &&
+ if (MmAvailablePages <= MiMinimumAvailablePages &&
MiBalancerThreadHandle != NULL)
{
KeSetEvent(&MiBalancerEvent, IO_NO_INCREMENT, FALSE);
/*
* Make sure we don't exceed global targets.
*/
- if (MmStats.NrFreePages <= MiMinimumAvailablePages)
+ if (MmAvailablePages <= MiMinimumAvailablePages)
{
MM_ALLOCATION_REQUEST Request;
KeInitializeEvent(&Request.Event, NotificationEvent, FALSE);
(void)InterlockedIncrementUL(&MiPagesRequired);
- KeAcquireSpinLock(&AllocationListLock, &oldIrql);
+ KeAcquireSpinLock(&AllocationListLock, &OldIrql);
if (MiBalancerThreadHandle != NULL)
{
KeSetEvent(&MiBalancerEvent, IO_NO_INCREMENT, FALSE);
}
InsertTailList(&AllocationListHead, &Request.ListEntry);
- KeReleaseSpinLock(&AllocationListLock, oldIrql);
+ KeReleaseSpinLock(&AllocationListLock, OldIrql);
KeWaitForSingleObject(&Request.Event,
0,
Page = Request.Page;
if (Page == 0)
{
- KEBUGCHECK(NO_PAGES_AVAILABLE);
+ KeBugCheck(NO_PAGES_AVAILABLE);
}
- /* Update the Consumer */
- MiGetPfnEntry(Page)->Flags.Consumer = Consumer;
+ /* Update the Consumer and make the page active */
+ MiSetConsumer(Page, Consumer);
if(Consumer == MC_USER) MmInsertLRULastUserPage(Page);
*AllocatedPage = Page;
(void)InterlockedDecrementUL(&MiPagesRequired);
/*
* Actually allocate the page.
*/
- Page = MmAllocPage(Consumer, 0);
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ Page = MmAllocPage(Consumer);
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
if (Page == 0)
{
- KEBUGCHECK(NO_PAGES_AVAILABLE);
+ KeBugCheck(NO_PAGES_AVAILABLE);
}
if(Consumer == MC_USER) MmInsertLRULastUserPage(Page);
*AllocatedPage = Page;
return(STATUS_SUCCESS);
}
-VOID STDCALL
+VOID NTAPI
MiBalancerThread(PVOID Unused)
{
PVOID WaitObjects[2];
if (Status == STATUS_SUCCESS)
{
/* MiBalancerEvent */
- CHECKPOINT;
- while (MmStats.NrFreePages < MiMinimumAvailablePages + 5)
+ while (MmAvailablePages < MiMinimumAvailablePages + 5)
{
for (i = 0; i < MC_MAXIMUM; i++)
{
Status = MiMemoryConsumers[i].Trim(MiMinimumPagesPerRun, 0, &NrFreedPages);
if (!NT_SUCCESS(Status))
{
- KEBUGCHECK(0);
+ KeBugCheck(MEMORY_MANAGEMENT);
}
}
}
}
InterlockedExchange(&MiBalancerWork, 0);
- CHECKPOINT;
}
else if (Status == STATUS_SUCCESS + 1)
{
/* MiBalancerTimer */
- ShouldRun = MmStats.NrFreePages < MiMinimumAvailablePages + 5 ? TRUE : FALSE;
+ ShouldRun = MmAvailablePages < MiMinimumAvailablePages + 5 ? TRUE : FALSE;
for (i = 0; i < MC_MAXIMUM; i++)
{
if (MiMemoryConsumers[i].Trim != NULL)
Status = MiMemoryConsumers[i].Trim(Target, 0, &NrFreedPages);
if (!NT_SUCCESS(Status))
{
- KEBUGCHECK(0);
+ KeBugCheck(MEMORY_MANAGEMENT);
}
}
}
else
{
DPRINT1("KeWaitForMultipleObjects failed, status = %x\n", Status);
- KEBUGCHECK(0);
+ KeBugCheck(MEMORY_MANAGEMENT);
}
}
}
;
#endif
- CHECKPOINT;
KeInitializeEvent(&MiBalancerEvent, SynchronizationEvent, FALSE);
KeInitializeTimerEx(&MiBalancerTimer, SynchronizationTimer);
NULL);
if (!NT_SUCCESS(Status))
{
- KEBUGCHECK(0);
+ KeBugCheck(MEMORY_MANAGEMENT);
}
Priority = LOW_REALTIME_PRIORITY + 1;