windows-nt/Source/XPSP1/NT/base/ntos/mm/zeropage.c
2020-09-26 16:20:57 +08:00

263 lines
6.4 KiB
C

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
zeropage.c
Abstract:
This module contains the zero page thread for memory management.
Author:
Lou Perazzoli (loup) 6-Apr-1991
Landy Wang (landyw) 02-June-1997
Revision History:
--*/
#include "mi.h"
#define MM_ZERO_PAGE_OBJECT 0
#define PO_SYS_IDLE_OBJECT 1
#define NUMBER_WAIT_OBJECTS 2
#define MACHINE_ZERO_PAGE() KeZeroPageFromIdleThread(ZeroBase)
LOGICAL MiZeroingDisabled = FALSE;
ULONG MmLastNodeZeroing = 0;
VOID
MmZeroPageThread (
VOID
)
/*++
Routine Description:
Implements the NT zeroing page thread. This thread runs
at priority zero and removes a page from the free list,
zeroes it, and places it on the zeroed page list.
Arguments:
StartContext - not used.
Return Value:
None.
Environment:
Kernel mode.
--*/
{
KIRQL OldIrql;
PFN_NUMBER PageFrame;
PMMPFN Pfn1;
PKTHREAD Thread;
PVOID ZeroBase;
PFN_NUMBER NewPage;
PVOID WaitObjects[NUMBER_WAIT_OBJECTS];
NTSTATUS Status;
PVOID StartVa;
PVOID EndVa;
#if defined(MI_MULTINODE)
ULONG i, n;
ULONG Color = 0;
ULONG StartColor;
#endif
//
// Before this becomes the zero page thread, free the kernel
// initialization code.
//
MiFindInitializationCode (&StartVa, &EndVa);
if (StartVa != NULL) {
MiFreeInitializationCode (StartVa, EndVa);
}
//
// The following code sets the current thread's base priority to zero
// and then sets its current priority to zero. This ensures that the
// thread always runs at a priority of zero.
//
Thread = KeGetCurrentThread();
Thread->BasePriority = 0;
KeSetPriorityThread (Thread, 0);
//
// Initialize wait object array for multiple wait
//
WaitObjects[MM_ZERO_PAGE_OBJECT] = &MmZeroingPageEvent;
WaitObjects[PO_SYS_IDLE_OBJECT] = &PoSystemIdleTimer;
//
// Loop forever zeroing pages.
//
do {
//
// Wait until there are at least MmZeroPageMinimum pages
// on the free list.
//
Status = KeWaitForMultipleObjects (NUMBER_WAIT_OBJECTS,
WaitObjects,
WaitAny,
WrFreePage,
KernelMode,
FALSE,
(PLARGE_INTEGER) NULL,
(PKWAIT_BLOCK) NULL
);
if (Status == PO_SYS_IDLE_OBJECT) {
PoSystemIdleWorker (TRUE);
continue;
}
LOCK_PFN_WITH_TRY (OldIrql);
do {
if (*(PFN_NUMBER volatile*)&MmFreePageListHead.Total == 0) {
//
// No pages on the free list at this time, wait for
// some more.
//
MmZeroingPageThreadActive = FALSE;
UNLOCK_PFN (OldIrql);
break;
}
if (MiZeroingDisabled == TRUE) {
MmZeroingPageThreadActive = FALSE;
UNLOCK_PFN (OldIrql);
KeDelayExecutionThread (KernelMode, FALSE, (PLARGE_INTEGER)&MmHalfSecond);
break;
}
//
// In a multinode system, zero pages by node. Starting with
// the last node examined, find a node with free pages that
// need to be zeroed.
//
#if defined(MI_MULTINODE)
if (KeNumberNodes > 1) {
n = MmLastNodeZeroing;
for (i = 0; i < KeNumberNodes; i += 1) {
if (KeNodeBlock[n]->FreeCount[FreePageList] != 0) {
break;
}
n = (n + 1) % KeNumberNodes;
}
ASSERT (KeNodeBlock[n]->FreeCount[FreePageList]);
if (n != MmLastNodeZeroing) {
Color = KeNodeBlock[n]->MmShiftedColor;
}
//
// Must start with a color MiRemoveAnyPage will
// satisfy from the free list otherwise it will
// return an already zeroed page.
//
StartColor = Color;
do {
if (MmFreePagesByColor[FreePageList][Color].Flink !=
MM_EMPTY_LIST) {
break;
}
Color = (Color & ~MmSecondaryColorMask) |
((Color + 1) & MmSecondaryColorMask);
ASSERT(StartColor != Color);
} while (TRUE);
PageFrame = MiRemoveAnyPage(Color);
}
else {
n = 0;
#endif
PageFrame = MmFreePageListHead.Flink;
ASSERT (PageFrame != MM_EMPTY_LIST);
Pfn1 = MI_PFN_ELEMENT(PageFrame);
NewPage = MiRemoveAnyPage(MI_GET_COLOR_FROM_LIST_ENTRY(PageFrame, Pfn1));
if (NewPage != PageFrame) {
//
// Someone has removed a page from the colored lists
// chain without updating the freelist chain.
//
KeBugCheckEx (PFN_LIST_CORRUPT,
0x8F,
NewPage,
PageFrame,
0);
}
#if defined(MI_MULTINODE)
}
#endif
//
// Zero the page using the last color used to map the page.
//
UNLOCK_PFN (OldIrql);
ZeroBase = MiMapPageToZeroInHyperSpace (PageFrame);
//
// If a node switch is in order, do it now that the PFN
// lock has been released.
//
#if defined(MI_MULTINODE)
if ((KeNumberNodes > 1) && (n != MmLastNodeZeroing)) {
MmLastNodeZeroing = n;
KeFindFirstSetLeftAffinity(KeNodeBlock[n]->ProcessorMask, &i);
KeSetIdealProcessorThread(Thread, (UCHAR)i);
}
#endif
MACHINE_ZERO_PAGE();
MiUnmapPageInZeroSpace (ZeroBase);
LOCK_PFN_WITH_TRY (OldIrql);
MiInsertPageInList (&MmZeroedPageListHead, PageFrame);
} while(TRUE);
} while (TRUE);
}