From 9b07458c4dec01ab881ae166ce31587cc422284f Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Thu, 20 Feb 2014 23:03:04 +0000 Subject: [PATCH] [NTOSKRNL] Implement MmAdjustWorkingSetSize svn path=/trunk/; revision=62275 --- reactos/ntoskrnl/mm/ARM3/mmsup.c | 113 ++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 2 deletions(-) diff --git a/reactos/ntoskrnl/mm/ARM3/mmsup.c b/reactos/ntoskrnl/mm/ARM3/mmsup.c index 0ec4999bb4f..b1e61323562 100644 --- a/reactos/ntoskrnl/mm/ARM3/mmsup.c +++ b/reactos/ntoskrnl/mm/ARM3/mmsup.c @@ -15,6 +15,12 @@ #define MODULE_INVOLVED_IN_ARM3 #include "../ARM3/miarm.h" +/* GLOBALS ********************************************************************/ + +SIZE_T MmMinimumWorkingSetSize; +SIZE_T MmMaximumWorkingSetSize; +SIZE_T MmPagesAboveWsMinimum; + /* PUBLIC FUNCTIONS ***********************************************************/ /* @@ -40,8 +46,111 @@ MmAdjustWorkingSetSize(IN SIZE_T WorkingSetMinimumInBytes, IN ULONG SystemCache, IN BOOLEAN IncreaseOkay) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + SIZE_T MinimumWorkingSetSize, MaximumWorkingSetSize; + 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; } /* -- 2.17.1