mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 01:24:38 +00:00
Memory balancer
svn path=/trunk/; revision=2439
This commit is contained in:
parent
47ba969751
commit
aee376797f
1 changed files with 212 additions and 0 deletions
212
reactos/ntoskrnl/mm/balance.c
Normal file
212
reactos/ntoskrnl/mm/balance.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* ReactOS kernel
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* 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.1 2001/12/28 00:04:45 dwelch Exp $
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/mm/balance.c
|
||||
* PURPOSE: kernel memory managment functions
|
||||
* PROGRAMMER: David Welch (welch@cwcom.net)
|
||||
* UPDATE HISTORY:
|
||||
* Created 27/12/01
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ddk/ntddk.h>
|
||||
#include <internal/mm.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* TYPES ********************************************************************/
|
||||
|
||||
typedef struct _MM_MEMORY_CONSUMER
|
||||
{
|
||||
ULONG PagesUsed;
|
||||
ULONG PagesTarget;
|
||||
NTSTATUS (*Trim)(ULONG Target, ULONG Priority, PULONG NrFreed, PVOID* FreedPages);
|
||||
} MM_MEMORY_CONSUMER, *PMM_MEMORY_CONSUMER;
|
||||
|
||||
#define MC_CACHE (0)
|
||||
#define MC_USER (1)
|
||||
#define MC_PPOOL (2)
|
||||
#define MC_NPPOOL (3)
|
||||
#define MC_MAXIMUM (4)
|
||||
|
||||
/* GLOBALS ******************************************************************/
|
||||
|
||||
static MM_MEMORY_CONSUMER MiMemoryConsumers[MC_MAXIMUM];
|
||||
static ULONG MiMinimumAvailablePages;
|
||||
static ULONG MiNrAvailablePages;
|
||||
static ULONG MiNrTotalPages;
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
VOID
|
||||
MmInitializeBalancer(ULONG NrAvailablePages)
|
||||
{
|
||||
memset(MiMemoryConsumers, 0, sizeof(MiMemoryConsumers));
|
||||
|
||||
MiNrAvailablePages = MiNrTotalPages = NrAvailablePages;
|
||||
|
||||
/* Set up targets. */
|
||||
MiMinimumAvailablePages = 64;
|
||||
MiMemoryConsumers[MC_CACHE].PagesTarget = NrAvailablePages / 2;
|
||||
MiMemoryConsumers[MC_USER].PagesTarget = NrAvailablePages - MiMinimumAvailablePages;
|
||||
MiMemoryConsumers[MC_PPOOL].PagesTarget = NrAvailablePages / 2;
|
||||
MiMemoryConsumers[MC_NPPOOL].PagesTarget = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
VOID
|
||||
MmInitializeMemoryConsumer(ULONG Consumer,
|
||||
NTSTATUS (*Trim)(ULONG Target, ULONG Priority,
|
||||
PULONG NrFreed, PVOID* FreedPages))
|
||||
{
|
||||
MiMemoryConsumers[Consumer].Trim = Trim;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
MmReleasePageMemoryConsumer(ULONG Consumer, PVOID Page)
|
||||
{
|
||||
InterlockedDecrement(&MiMemoryConsumers[Consumer].PagesUsed);
|
||||
InterlockedIncrement(&MiNrAvailablePages);
|
||||
MmDereferencePage(Page);
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
VOID
|
||||
MiTrimMemoryConsumer(ULONG Consumer)
|
||||
{
|
||||
LONG Target;
|
||||
|
||||
Target = MiMemoryConsumers[Consumer].PagesUsed - MiMemoryConsumers[Consumer].PagesTarget;
|
||||
if (Target < 0)
|
||||
{
|
||||
Target = 1;
|
||||
}
|
||||
|
||||
if (MiMemoryConsumers[Consumer].Trim != NULL)
|
||||
{
|
||||
MiMemoryConsumers[Consumer].Trim(Target, 0, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
MiRebalanceMemoryConsumers(PVOID* Page)
|
||||
{
|
||||
LONG Target;
|
||||
ULONG i;
|
||||
PVOID* FreedPages;
|
||||
ULONG NrFreedPages;
|
||||
ULONG TotalFreedPages;
|
||||
|
||||
Target = MiMinimumAvailablePages - MiNrAvailablePages;
|
||||
if (Target < 0)
|
||||
{
|
||||
Target = 1;
|
||||
}
|
||||
|
||||
FreedPages = alloca(sizeof(PVOID) * Target);
|
||||
TotalFreedPages = 0;
|
||||
|
||||
for (i = 0; i < MC_MAXIMUM && Target > 0; i++)
|
||||
{
|
||||
if (MiMemoryConsumers[i].Trim != NULL)
|
||||
{
|
||||
MiMemoryConsumers[i].Trim(Target, 0, &NrFreedPages, FreedPages);
|
||||
Target = Target - NrFreedPages;
|
||||
FreedPages = FreedPages + NrFreedPages;
|
||||
TotalFreedPages = TotalFreedPages + NrFreedPages;
|
||||
}
|
||||
}
|
||||
if (Target > 0)
|
||||
{
|
||||
KeBugCheck(0);
|
||||
}
|
||||
if (Page != NULL)
|
||||
{
|
||||
*Page = FreedPages[0];
|
||||
i = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
for (; i < TotalFreedPages; i++)
|
||||
{
|
||||
MmDereferencePage(FreedPages[i]);
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
MmRequestPageMemoryConsumer(ULONG Consumer, BOOLEAN CanWait, PVOID* AllocatedPage)
|
||||
{
|
||||
ULONG OldUsed;
|
||||
ULONG OldAvailable;
|
||||
PVOID Page;
|
||||
|
||||
/*
|
||||
* Make sure we don't exceed our individual target.
|
||||
*/
|
||||
OldUsed = InterlockedIncrement(&MiMemoryConsumers[Consumer].PagesUsed);
|
||||
if (OldUsed >= (MiMemoryConsumers[Consumer].PagesTarget - 1))
|
||||
{
|
||||
if (!CanWait)
|
||||
{
|
||||
InterlockedDecrement(&MiMemoryConsumers[Consumer].PagesUsed);
|
||||
return(STATUS_NO_MEMORY);
|
||||
}
|
||||
MiTrimMemoryConsumer(Consumer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we don't exceed global targets.
|
||||
*/
|
||||
OldAvailable = InterlockedDecrement(&MiNrAvailablePages);
|
||||
if (OldAvailable < MiMinimumAvailablePages)
|
||||
{
|
||||
if (!CanWait)
|
||||
{
|
||||
InterlockedIncrement(&MiNrAvailablePages);
|
||||
InterlockedDecrement(&MiMemoryConsumers[Consumer].PagesUsed);
|
||||
return(STATUS_NO_MEMORY);
|
||||
}
|
||||
MiRebalanceMemoryConsumers(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Actually allocate the page.
|
||||
*/
|
||||
Page = MmAllocPage(0);
|
||||
if (Page == NULL)
|
||||
{
|
||||
/* Still not trimmed enough. */
|
||||
if (!CanWait)
|
||||
{
|
||||
InterlockedIncrement(&MiNrAvailablePages);
|
||||
InterlockedDecrement(&MiMemoryConsumers[Consumer].PagesUsed);
|
||||
return(STATUS_NO_MEMORY);
|
||||
}
|
||||
MiRebalanceMemoryConsumers(&Page);
|
||||
}
|
||||
*AllocatedPage = Page;
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
Loading…
Reference in a new issue