- Moved the pager thread as balancer thread to balance.c.

- Fixed some deadlock conditions for low memory situations.

svn path=/trunk/; revision=6665
This commit is contained in:
Hartmut Birr 2003-11-16 15:20:39 +00:00
parent 29e31c6fb0
commit d0455ad11e
3 changed files with 169 additions and 19 deletions

View file

@ -334,7 +334,10 @@ VOID MmInit1(ULONG FirstKernelPhysAddress,
VOID MmInit2(VOID);
VOID MmInit3(VOID);
VOID MiFreeInitMemory(VOID);
#if 0
NTSTATUS MmInitPagerThread(VOID);
#endif
VOID MiInitBalancerThread(VOID);
NTSTATUS MmInitZeroPageThread(VOID);
VOID MiInitKernelMap(VOID);

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: balance.c,v 1.22 2003/10/23 20:28:08 hbirr Exp $
/* $Id: balance.c,v 1.23 2003/11/16 15:20:39 hbirr Exp $
*
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/balance.c
@ -62,6 +62,12 @@ static KSPIN_LOCK AllocationListLock;
static ULONG MiPagesRequired = 0;
static ULONG MiMinimumPagesPerRun = 10;
static CLIENT_ID MiBalancerThreadId;
static HANDLE MiBalancerThreadHandle = NULL;
static KEVENT MiBalancerEvent;
static KTIMER MiBalancerTimer;
static LONG MiBalancerWork = 0;
/* FUNCTIONS ****************************************************************/
VOID MmPrintMemoryStatistic(VOID)
@ -184,6 +190,13 @@ MmRebalanceMemoryConsumers(VOID)
}
}
static BOOLEAN
MiIsBalancerThread(VOID)
{
return MiBalancerThreadHandle != NULL &&
PsGetCurrentThread() == MiBalancerThreadId.UniqueThread;
}
NTSTATUS
MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
PHYSICAL_ADDRESS* AllocatedPage)
@ -198,7 +211,7 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
*/
OldUsed = InterlockedIncrement((LONG *)&MiMemoryConsumers[Consumer].PagesUsed);
if (OldUsed >= (MiMemoryConsumers[Consumer].PagesTarget - 1) &&
!MiIsPagerThread())
!MiIsBalancerThread())
{
if (!CanWait)
{
@ -208,10 +221,29 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
MiTrimMemoryConsumer(Consumer);
}
OldAvailable = InterlockedDecrement((LONG *)&MiNrAvailablePages);
/*
* Allocate always memory for the non paged pool and for the pager thread.
*/
if (Consumer == MC_NPPOOL || MiIsBalancerThread())
{
Page = MmAllocPage(Consumer, 0);
if (Page.QuadPart == 0LL)
{
KEBUGCHECK(0);
}
*AllocatedPage = Page;
if (OldAvailable < MiMinimumAvailablePages &&
MiBalancerThreadHandle != NULL)
{
KeSetEvent(&MiBalancerEvent, IO_NO_INCREMENT, FALSE);
}
return(STATUS_SUCCESS);
}
/*
* Make sure we don't exceed global targets.
*/
OldAvailable = InterlockedDecrement((LONG *)&MiNrAvailablePages);
if (OldAvailable < MiMinimumAvailablePages)
{
MM_ALLOCATION_REQUEST Request;
@ -229,21 +261,11 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
InterlockedIncrement((LONG *)&MiPagesRequired);
KeAcquireSpinLock(&AllocationListLock, &oldIrql);
/* Always let the pager thread itself allocate memory. */
if (MiIsPagerThread())
{
Page = MmAllocPage(Consumer, 0);
KeReleaseSpinLock(&AllocationListLock, oldIrql);
if (Page.QuadPart == 0LL)
{
KEBUGCHECK(0);
}
*AllocatedPage = Page;
InterlockedDecrement((LONG *)&MiPagesRequired);
return(STATUS_SUCCESS);
if (MiBalancerThreadHandle != NULL)
{
KeSetEvent(&MiBalancerEvent, IO_NO_INCREMENT, FALSE);
}
/* Otherwise start the pager thread if it isn't already working. */
MiStartPagerThread();
InsertTailList(&AllocationListHead, &Request.ListEntry);
KeReleaseSpinLock(&AllocationListLock, oldIrql);
@ -261,7 +283,6 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
MmTransferOwnershipPage(Page, Consumer);
*AllocatedPage = Page;
InterlockedDecrement((LONG *)&MiPagesRequired);
MiStopPagerThread();
return(STATUS_SUCCESS);
}
@ -278,4 +299,126 @@ MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait,
return(STATUS_SUCCESS);
}
VOID STDCALL
MiBalancerThread(PVOID Unused)
{
PVOID WaitObjects[2];
NTSTATUS Status;
ULONG i;
ULONG NrFreedPages;
ULONG NrPagesUsed;
ULONG Target;
BOOLEAN ShouldRun;
WaitObjects[0] = &MiBalancerEvent;
WaitObjects[1] = &MiBalancerTimer;
while (1)
{
Status = KeWaitForMultipleObjects(2,
WaitObjects,
WaitAny,
Executive,
KernelMode,
FALSE,
NULL,
NULL);
if (Status == STATUS_SUCCESS)
{
/* MiBalancerEvent */
CHECKPOINT;
while (MiNrAvailablePages < MiMinimumAvailablePages)
{
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))
{
KEBUGCHECK(0);
}
}
}
}
InterlockedExchange(&MiBalancerWork, 0);
CHECKPOINT;
}
else if (Status == STATUS_SUCCESS + 1)
{
/* MiBalancerTimer */
ShouldRun = MiNrAvailablePages < MiMinimumAvailablePages ? TRUE : FALSE;
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))
{
KEBUGCHECK(0);
}
}
}
}
}
else
{
DPRINT1("KeWaitForMultipleObjects failt, status = %x\n", Status);
KEBUGCHECK(0);
}
}
}
VOID INIT_FUNCTION
MiInitBalancerThread(VOID)
{
KPRIORITY Priority;
NTSTATUS Status;
CHECKPOINT1;
KeInitializeEvent(&MiBalancerEvent, SynchronizationEvent, FALSE);
KeInitializeTimerEx(&MiBalancerTimer, SynchronizationTimer);
KeSetTimerEx(&MiBalancerTimer,
(LARGE_INTEGER)(LONGLONG)-20000000LL, /* 2 sec */
2000, /* 2 sec */
NULL);
Status = PsCreateSystemThread(&MiBalancerThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
&MiBalancerThreadId,
(PKSTART_ROUTINE) MiBalancerThread,
NULL);
if (!NT_SUCCESS(Status))
{
KEBUGCHECK(0);
}
Priority = LOW_REALTIME_PRIORITY + 1;
NtSetInformationThread(MiBalancerThreadHandle,
ThreadPriority,
&Priority,
sizeof(Priority));
}
/* EOF */

View file

@ -1,4 +1,4 @@
/* $Id: pager.c,v 1.15 2003/07/21 21:53:53 royce Exp $
/* $Id: pager.c,v 1.16 2003/11/16 15:20:39 hbirr Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -21,14 +21,17 @@
/* GLOBALS *******************************************************************/
#if 0
static HANDLE PagerThreadHandle;
static CLIENT_ID PagerThreadId;
static KEVENT PagerThreadEvent;
static BOOLEAN PagerThreadShouldTerminate;
static ULONG PagerThreadWorkCount;
#endif
/* FUNCTIONS *****************************************************************/
#if 0
BOOLEAN
MiIsPagerThread(VOID)
{
@ -108,3 +111,4 @@ NTSTATUS MmInitPagerThread(VOID)
return(STATUS_SUCCESS);
}
#endif