// Get the physical memory that this process can use. // Return: // non zero if it has succeeded, 0 if it has failed // Remarks: // If a process runs with a restricted memory limit, it returns the limit. If there's no limit // specified, it returns amount of actual physical memory. uint64_t GCToOSInterface::GetPhysicalMemoryLimit() { size_t restricted_limit; // The limit was not cached if (g_RestrictedPhysicalMemoryLimit == 0) { restricted_limit = GetRestrictedPhysicalMemoryLimit(); VolatileStore(&g_RestrictedPhysicalMemoryLimit, restricted_limit); } restricted_limit = g_RestrictedPhysicalMemoryLimit; if (restricted_limit != 0 && restricted_limit != SIZE_T_MAX) return restricted_limit; long pages = sysconf(_SC_PHYS_PAGES); if (pages == -1) { return 0; } long pageSize = sysconf(_SC_PAGE_SIZE); if (pageSize == -1) { return 0; } return pages * pageSize; }
static size_t GetRestrictedPhysicalMemoryLimit() { LIMITED_METHOD_CONTRACT; // The limit was cached already if (g_RestrictedPhysicalMemoryLimit != (size_t)MAX_PTR) return g_RestrictedPhysicalMemoryLimit; size_t memory_limit = PAL_GetRestrictedPhysicalMemoryLimit(); VolatileStore(&g_RestrictedPhysicalMemoryLimit, memory_limit); return g_RestrictedPhysicalMemoryLimit; }
//--------------------------------------------------------------------------------------- // // Initialize the static instance and lock. // HRESULT LOADEDMODULES::InitializeStatics() { HRESULT hr = S_OK; if (VolatileLoad(&s_pLoadedModules) == NULL) { // Initialize global read-write lock { NewHolder<UTSemReadWrite> pSemReadWrite = new (nothrow) UTSemReadWrite(); IfNullGo(pSemReadWrite); IfFailGo(pSemReadWrite->Init()); if (InterlockedCompareExchangeT<UTSemReadWrite *>(&m_pSemReadWrite, pSemReadWrite, NULL) == NULL) { // We won the initialization race pSemReadWrite.SuppressRelease(); } } // Initialize the global instance { NewHolder<LOADEDMODULES> pLoadedModules = new (nothrow) LOADEDMODULES(); IfNullGo(pLoadedModules); { LOCKWRITE(); if (VolatileLoad(&s_pLoadedModules) == NULL) { VolatileStore(&s_pLoadedModules, pLoadedModules.Extract()); } } } } ErrExit: return hr; } // LOADEDMODULES::InitializeStatics
static size_t GetRestrictedPhysicalMemoryLimit() { LIMITED_METHOD_CONTRACT; // The limit was cached already if (g_RestrictedPhysicalMemoryLimit != (size_t)MAX_PTR) return g_RestrictedPhysicalMemoryLimit; 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); MEMORYSTATUSEX ms; ::GetProcessMemoryLoad(&ms); // A sanity check in case someone set a larger limit than there is actual physical memory. job_physical_memory_limit = (size_t) min (job_physical_memory_limit, ms.ullTotalPhys); } } 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 } VolatileStore(&g_RestrictedPhysicalMemoryLimit, job_physical_memory_limit); return g_RestrictedPhysicalMemoryLimit; }
static size_t GetRestrictedPhysicalMemoryLimit() { LIMITED_METHOD_CONTRACT; // The limit was cached already if (g_RestrictedPhysicalMemoryLimit != (size_t)MAX_PTR) return g_RestrictedPhysicalMemoryLimit; size_t job_physical_memory_limit = (size_t)MAX_PTR; BOOL in_job_p = FALSE; HINSTANCE hinstKernel32 = 0; PIS_PROCESS_IN_JOB GCIsProcessInJob = 0; PQUERY_INFORMATION_JOB_OBJECT GCQueryInformationJobObject = 0; GCIsProcessInJob = &(::IsProcessInJob); if (!GCIsProcessInJob(GetCurrentProcess(), NULL, &in_job_p)) goto exit; if (in_job_p) { hinstKernel32 = WszLoadLibrary(L"kernel32.dll"); if (!hinstKernel32) goto exit; GCGetProcessMemoryInfo = (PGET_PROCESS_MEMORY_INFO)GetProcAddress(hinstKernel32, "K32GetProcessMemoryInfo"); if (!GCGetProcessMemoryInfo) goto exit; GCQueryInformationJobObject = &(::QueryInformationJobObject); 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); MEMORYSTATUSEX ms; ::GetProcessMemoryLoad(&ms); // A sanity check in case someone set a larger limit than there is actual physical memory. job_physical_memory_limit = (size_t) min (job_physical_memory_limit, ms.ullTotalPhys); } } exit: if (job_physical_memory_limit == (size_t)MAX_PTR) { job_physical_memory_limit = 0; FreeLibrary(hinstKernel32); } VolatileStore(&g_RestrictedPhysicalMemoryLimit, job_physical_memory_limit); return g_RestrictedPhysicalMemoryLimit; }
ThreadStressLog* StressLog::CreateThreadStressLogHelper(Thread * pThread) { bool skipInsert = FALSE; ThreadStressLog* msgs = NULL; // See if we can recycle a dead thread if (VolatileLoad(&theLog.deadCount) > 0) { unsigned __int64 recycleStamp = getTimeStamp() - RECYCLE_AGE; msgs = VolatileLoad(&theLog.logs); //find out oldest dead ThreadStressLog in case we can't find one within //recycle age but can't create a new chunk ThreadStressLog * oldestDeadMsg = NULL; while(msgs != 0) { if (msgs->isDead) { bool hasTimeStamp = msgs->curPtr != (StressMsg *)msgs->chunkListTail->EndPtr(); if (hasTimeStamp && msgs->curPtr->timeStamp < recycleStamp) { skipInsert = TRUE; PalInterlockedDecrement(&theLog.deadCount); break; } if (!oldestDeadMsg) { oldestDeadMsg = msgs; } else if (hasTimeStamp && oldestDeadMsg->curPtr->timeStamp > msgs->curPtr->timeStamp) { oldestDeadMsg = msgs; } } msgs = msgs->next; } //if the total stress log size limit is already passed and we can't add new chunk, //always reuse the oldest dead msg if (!AllowNewChunk (0) && !msgs) { msgs = oldestDeadMsg; skipInsert = TRUE; PalInterlockedDecrement(&theLog.deadCount); } } if (msgs == 0) { msgs = new (nothrow) ThreadStressLog(); if (msgs == 0 ||!msgs->IsValid ()) { delete msgs; msgs = 0; goto LEAVE; } } msgs->Activate (pThread); if (!skipInsert) { #ifdef _DEBUG ThreadStressLog* walk = VolatileLoad(&theLog.logs); while (walk) { _ASSERTE (walk != msgs); walk = walk->next; } #endif // Put it into the stress log msgs->next = VolatileLoad(&theLog.logs); VolatileStore(&theLog.logs, msgs); } LEAVE: ; return msgs; }