[NTOSKRNL]

Implement MmAdjustWorkingSetSize

svn path=/trunk/; revision=62275
This commit is contained in:
Timo Kreuzer 2014-02-20 23:03:04 +00:00
parent feedae2fff
commit 9b07458c4d

View file

@ -15,6 +15,12 @@
#define MODULE_INVOLVED_IN_ARM3 #define MODULE_INVOLVED_IN_ARM3
#include "../ARM3/miarm.h" #include "../ARM3/miarm.h"
/* GLOBALS ********************************************************************/
SIZE_T MmMinimumWorkingSetSize;
SIZE_T MmMaximumWorkingSetSize;
SIZE_T MmPagesAboveWsMinimum;
/* PUBLIC FUNCTIONS ***********************************************************/ /* PUBLIC FUNCTIONS ***********************************************************/
/* /*
@ -40,8 +46,111 @@ MmAdjustWorkingSetSize(IN SIZE_T WorkingSetMinimumInBytes,
IN ULONG SystemCache, IN ULONG SystemCache,
IN BOOLEAN IncreaseOkay) IN BOOLEAN IncreaseOkay)
{ {
UNIMPLEMENTED; SIZE_T MinimumWorkingSetSize, MaximumWorkingSetSize;
return STATUS_NOT_IMPLEMENTED; SSIZE_T Delta;
PMMSUPPORT Ws;
NTSTATUS Status;
/* Check for special case: empty the working set */
if ((WorkingSetMinimumInBytes == -1) &&
(WorkingSetMaximumInBytes == -1))
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/* Assume success */
Status = STATUS_SUCCESS;
/* Get the working set and lock it */
Ws = &PsGetCurrentProcess()->Vm;
MiLockWorkingSet(PsGetCurrentThread(), Ws);
/* Calculate the actual minimum and maximum working set size to set */
MinimumWorkingSetSize = (WorkingSetMinimumInBytes != 0) ?
(WorkingSetMinimumInBytes / PAGE_SIZE) : Ws->MinimumWorkingSetSize;
MaximumWorkingSetSize = (WorkingSetMaximumInBytes != 0) ?
(WorkingSetMaximumInBytes / PAGE_SIZE) : Ws->MaximumWorkingSetSize;
/* Check if the new maximum exceeds the global maximum */
if (MaximumWorkingSetSize > MmMaximumWorkingSetSize)
{
MaximumWorkingSetSize = MmMaximumWorkingSetSize;
Status = STATUS_WORKING_SET_LIMIT_RANGE;
}
/* Check if the new minimum is below the global minimum */
if (MinimumWorkingSetSize < MmMinimumWorkingSetSize)
{
MinimumWorkingSetSize = MmMinimumWorkingSetSize;
Status = STATUS_WORKING_SET_LIMIT_RANGE;
}
/* Check if the new minimum exceeds the new maximum */
if (MinimumWorkingSetSize > MaximumWorkingSetSize)
{
DPRINT1("MinimumWorkingSetSize > MaximumWorkingSetSize\n");
Status = STATUS_BAD_WORKING_SET_LIMIT;
goto Cleanup;
}
/* Calculate the minimum WS size adjustment and check if we increase */
Delta = MinimumWorkingSetSize - Ws->MinimumWorkingSetSize;
if (Delta > 0)
{
/* Is increasing ok? */
if (!IncreaseOkay)
{
DPRINT1("Privilege for WS size increase not held\n");
Status = STATUS_PRIVILEGE_NOT_HELD;
goto Cleanup;
}
/* Check if the number of available pages is large enough */
if (((SIZE_T)Delta / 1024) > (MmAvailablePages - 128))
{
DPRINT1("Not enough available pages\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
/* Check if there are enough resident available pages */
if ((SIZE_T)Delta >
(MmResidentAvailablePages - MmSystemLockPagesCount - 256))
{
DPRINT1("Not enough resident pages\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
}
/* Update resident available pages */
if (Delta != 0)
{
InterlockedExchangeAddSizeT(&MmResidentAvailablePages, -Delta);
}
/* Calculate new pages above minimum WS size */
Delta += max((SSIZE_T)Ws->WorkingSetSize - MinimumWorkingSetSize, 0);
/* Subtract old pages above minimum WS size */
Delta -= max((SSIZE_T)Ws->WorkingSetSize - Ws->MinimumWorkingSetSize, 0);
/* If it changed, add it to the global variable */
if (Delta != 0)
{
InterlockedExchangeAddSizeT(&MmPagesAboveWsMinimum, Delta);
}
/* Set the new working set size */
Ws->MinimumWorkingSetSize = MinimumWorkingSetSize;
Ws->MaximumWorkingSetSize = MaximumWorkingSetSize;
Cleanup:
/* Unlock the working set and return the status */
MiUnlockWorkingSet(PsGetCurrentThread(), Ws);
return Status;
} }
/* /*