summaryrefslogtreecommitdiff
path: root/src/vm/gcenv.os.cpp
diff options
context:
space:
mode:
authorMaoni Stephens <maonis@microsoft.com>2016-03-02 12:23:49 -0800
committerMaoni Stephens <maonis@microsoft.com>2016-03-02 12:23:49 -0800
commitda777e57e0d4625e13f630321fe0defd439f8d61 (patch)
tree215cf1b24df1a5a7761adbff84110f407647fe31 /src/vm/gcenv.os.cpp
parentd4e7e51e023339b833a4423614d64e3b25a72bd5 (diff)
downloadcoreclr-da777e57e0d4625e13f630321fe0defd439f8d61.tar.gz
coreclr-da777e57e0d4625e13f630321fe0defd439f8d61.tar.bz2
coreclr-da777e57e0d4625e13f630321fe0defd439f8d61.zip
Integrate GC changes from full framework
[tfs-changeset: 1580785]
Diffstat (limited to 'src/vm/gcenv.os.cpp')
-rw-r--r--src/vm/gcenv.os.cpp174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/vm/gcenv.os.cpp b/src/vm/gcenv.os.cpp
index 051508eed3..95550728de 100644
--- a/src/vm/gcenv.os.cpp
+++ b/src/vm/gcenv.os.cpp
@@ -14,6 +14,12 @@
#include "common.h"
#include "gcenv.h"
+#ifndef FEATURE_PAL
+#include <Psapi.h>
+#endif
+
+#define MAX_PTR ((uint8_t*)(~(ptrdiff_t)0))
+
// Initialize the interface implementation
// Return:
// true if it has succeeded, false if it has failed
@@ -334,6 +340,174 @@ uint32_t GCToOSInterface::GetCurrentProcessCpuCount()
return ::GetCurrentProcessCpuCount();
}
+#ifndef FEATURE_PAL
+typedef BOOL (WINAPI *PGET_PROCESS_MEMORY_INFO)(HANDLE handle, PROCESS_MEMORY_COUNTERS* memCounters, uint32_t cb);
+static PGET_PROCESS_MEMORY_INFO GCGetProcessMemoryInfo = 0;
+
+typedef BOOL (WINAPI *PIS_PROCESS_IN_JOB)(HANDLE processHandle, HANDLE jobHandle, BOOL* result);
+typedef BOOL (WINAPI *PQUERY_INFORMATION_JOB_OBJECT)(HANDLE jobHandle, JOBOBJECTINFOCLASS jobObjectInfoClass, void* lpJobObjectInfo, DWORD cbJobObjectInfoLength, LPDWORD lpReturnLength);
+#endif
+
+#if defined(FEATURE_CORECLR) && !defined(FEATURE_PAL)
+// For coresys we need to look for an API in some apiset dll on win8 if we can't find it
+// in the traditional dll.
+HINSTANCE LoadDllForAPI(WCHAR* dllTraditional, WCHAR* dllApiSet)
+{
+ HINSTANCE hinst = WszLoadLibrary(dllTraditional);
+
+ if (!hinst)
+ {
+ if(RunningOnWin8())
+ hinst = WszLoadLibrary(dllApiSet);
+ }
+
+ return hinst;
+}
+#endif
+
+// If the process's memory is restricted (ie, beyond what's available on the machine), return that limit.
+// Return:
+// 0 if it has failed for some reason, the real value if it has succeeded
+// Remarks:
+// If a process runs with a restricted memory limit, and we are successful at getting
+// that limit, it returns the limit. If there's no limit specified, or there's an error
+// at getting that limit, it returns 0.
+uint64_t GCToOSInterface::GetRestrictedPhysicalMemoryLimit()
+{
+#ifdef FEATURE_PAL
+ return 0;
+#else
+ size_t job_physical_memory_limit = (size_t)MAX_PTR;
+ BOOL in_job_p = FALSE;
+#ifdef FEATURE_CORECLR
+ HINSTANCE hinstApiSetPsapiOrKernel32 = 0;
+ // these 2 modules will need to be freed no matter what as we only use them locally in this method.
+ HINSTANCE hinstApiSetJob1OrKernel32 = 0;
+ HINSTANCE hinstApiSetJob2OrKernel32 = 0;
+#else
+ HINSTANCE hinstPsapi = 0;
+#endif
+
+ PIS_PROCESS_IN_JOB GCIsProcessInJob = 0;
+ PQUERY_INFORMATION_JOB_OBJECT GCQueryInformationJobObject = 0;
+
+#ifdef FEATURE_CORECLR
+ hinstApiSetJob1OrKernel32 = LoadDllForAPI(L"kernel32.dll", L"api-ms-win-core-job-l1-1-0.dll");
+ if (!hinstApiSetJob1OrKernel32)
+ goto exit;
+
+ GCIsProcessInJob = (PIS_PROCESS_IN_JOB)GetProcAddress(hinstApiSetJob1OrKernel32, "IsProcessInJob");
+ if (!GCIsProcessInJob)
+ goto exit;
+#else
+ GCIsProcessInJob = &(::IsProcessInJob);
+#endif
+
+ if (!GCIsProcessInJob(GetCurrentProcess(), NULL, &in_job_p))
+ goto exit;
+
+ if (in_job_p)
+ {
+#ifdef FEATURE_CORECLR
+ hinstApiSetPsapiOrKernel32 = LoadDllForAPI(L"kernel32.dll", L"api-ms-win-core-psapi-l1-1-0");
+ if (!hinstApiSetPsapiOrKernel32)
+ goto exit;
+
+ GCGetProcessMemoryInfo = (PGET_PROCESS_MEMORY_INFO)GetProcAddress(hinstApiSetPsapiOrKernel32, "K32GetProcessMemoryInfo");
+#else
+ // We need a way to get the working set in a job object and GetProcessMemoryInfo
+ // is the way to get that. According to MSDN, we should use GetProcessMemoryInfo In order to
+ // compensate for the incompatibility that psapi.dll introduced we are getting this dynamically.
+ hinstPsapi = WszLoadLibrary(L"psapi.dll");
+ if (!hinstPsapi)
+ return 0;
+ GCGetProcessMemoryInfo = (PGET_PROCESS_MEMORY_INFO)GetProcAddress(hinstPsapi, "GetProcessMemoryInfo");
+#endif
+
+ if (!GCGetProcessMemoryInfo)
+ goto exit;
+
+#ifdef FEATURE_CORECLR
+ hinstApiSetJob2OrKernel32 = LoadDllForAPI(L"kernel32.dll", L"api-ms-win-core-job-l2-1-0");
+ if (!hinstApiSetJob2OrKernel32)
+ goto exit;
+
+ GCQueryInformationJobObject = (PQUERY_INFORMATION_JOB_OBJECT)GetProcAddress(hinstApiSetJob2OrKernel32, "QueryInformationJobObject");
+#else
+ GCQueryInformationJobObject = &(::QueryInformationJobObject);
+#endif
+
+ if (!GCQueryInformationJobObject)
+ goto exit;
+
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
+ if (GCQueryInformationJobObject (NULL, JobObjectExtendedLimitInformation, &limit_info,
+ sizeof(limit_info), NULL))
+ {
+ size_t job_memory_limit = (size_t)MAX_PTR;
+ size_t job_process_memory_limit = (size_t)MAX_PTR;
+ size_t job_workingset_limit = (size_t)MAX_PTR;
+
+ // Notes on the NT job object:
+ //
+ // You can specific a bigger process commit or working set limit than
+ // job limit which is pointless so we use the smallest of all 3 as
+ // to calculate our "physical memory load" or "available physical memory"
+ // when running inside a job object, ie, we treat this as the amount of physical memory
+ // our process is allowed to use.
+ //
+ // The commit limit is already reflected by default when you run in a
+ // job but the physical memory load is not.
+ //
+ if ((limit_info.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_JOB_MEMORY) != 0)
+ job_memory_limit = limit_info.JobMemoryLimit;
+ if ((limit_info.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_PROCESS_MEMORY) != 0)
+ job_process_memory_limit = limit_info.ProcessMemoryLimit;
+ if ((limit_info.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_WORKINGSET) != 0)
+ job_workingset_limit = limit_info.BasicLimitInformation.MaximumWorkingSetSize;
+
+ job_physical_memory_limit = min (job_memory_limit, job_process_memory_limit);
+ job_physical_memory_limit = min (job_physical_memory_limit, job_workingset_limit);
+ }
+ }
+
+exit:
+#ifdef FEATURE_CORECLR
+ if (hinstApiSetJob1OrKernel32)
+ FreeLibrary(hinstApiSetJob1OrKernel32);
+ if (hinstApiSetJob2OrKernel32)
+ FreeLibrary(hinstApiSetJob2OrKernel32);
+#endif
+
+ if (job_physical_memory_limit == (size_t)MAX_PTR)
+ {
+ job_physical_memory_limit = 0;
+
+#ifdef FEATURE_CORECLR
+ FreeLibrary(hinstApiSetPsapiOrKernel32);
+#else
+ FreeLibrary(hinstPsapi);
+#endif
+ }
+
+ return job_physical_memory_limit;
+#endif
+}
+
+// Get the current physical memory this process is using.
+// Return:
+// 0 if it has failed, the real value if it has succeeded
+size_t GCToOSInterface::GetCurrentPhysicalMemory()
+{
+#ifndef FEATURE_PAL
+ PROCESS_MEMORY_COUNTERS pmc;
+ if (GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
+ return pmc.WorkingSetSize;
+#endif
+
+ return 0;
+}
+
// Get global memory status
// Parameters:
// ms - pointer to the structure that will be filled in with the memory status