summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAditya Mandaleeka <adityam@microsoft.com>2016-03-11 18:39:27 -0800
committerAditya Mandaleeka <adityam@microsoft.com>2016-03-25 17:54:53 -0700
commit1aa1b8ba64365f8b93a505d4f6165c6eaad84a7a (patch)
tree8959cf6022f00a12084aad1c4139d3ba3a5c9501 /src
parent6cbd27ede090e1731b96d4d2b18813adb67e1487 (diff)
downloadcoreclr-1aa1b8ba64365f8b93a505d4f6165c6eaad84a7a.tar.gz
coreclr-1aa1b8ba64365f8b93a505d4f6165c6eaad84a7a.tar.bz2
coreclr-1aa1b8ba64365f8b93a505d4f6165c6eaad84a7a.zip
Add new configuration mechanism for CoreCLR.
Diffstat (limited to 'src')
-rw-r--r--src/dlls/mscoree/unixinterface.cpp110
-rw-r--r--src/inc/clrconfig.h5
-rw-r--r--src/inc/clrconfigvalues.h3
-rw-r--r--src/inc/configuration.h57
-rw-r--r--src/utilcode/CMakeLists.txt1
-rw-r--r--src/utilcode/UtilCode.vcproj3
-rw-r--r--src/utilcode/UtilCode.vcxproj1
-rw-r--r--src/utilcode/clrconfig.cpp128
-rw-r--r--src/utilcode/configuration.cpp125
-rw-r--r--src/utilcode/utilcode.settings.targets1
-rw-r--r--src/vm/ceemain.cpp2
-rw-r--r--src/vm/corhost.cpp5
-rw-r--r--src/vm/eeconfig.cpp21
-rw-r--r--src/vm/win32threadpool.cpp25
14 files changed, 365 insertions, 122 deletions
diff --git a/src/dlls/mscoree/unixinterface.cpp b/src/dlls/mscoree/unixinterface.cpp
index c3156c3a0f..e16f71f66f 100644
--- a/src/dlls/mscoree/unixinterface.cpp
+++ b/src/dlls/mscoree/unixinterface.cpp
@@ -6,7 +6,7 @@
//*****************************************************************************
// unixinterface.cpp
//
-// Implementation for the interface exposed by the libcoreclr.so on Unix
+// Implementation for the interface exposed by libcoreclr.so
//
//*****************************************************************************
@@ -14,6 +14,7 @@
#include "stdafx.h"
#include <utilcode.h>
#include <corhost.h>
+#include <configuration.h>
typedef int (STDMETHODCALLTYPE *HostMain)(
const int argc,
@@ -86,76 +87,47 @@ static LPCWSTR* StringArrayToUnicode(int argc, LPCSTR* argv)
return argvW;
}
-static void ExtractStartupFlagsAndConvertToUnicode(
+static void InitializeStartupFlags(STARTUP_FLAGS* startupFlagsRef)
+{
+ STARTUP_FLAGS startupFlags = static_cast<STARTUP_FLAGS>(
+ STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN |
+ STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN);
+
+ if (Configuration::GetKnobBooleanValue(W("System.GC.Concurrent"), CLRConfig::UNSUPPORTED_gcConcurrent))
+ {
+ startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_CONCURRENT_GC);
+ }
+ if (Configuration::GetKnobBooleanValue(W("System.GC.Server"), CLRConfig::UNSUPPORTED_gcServer))
+ {
+ startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_SERVER_GC);
+ }
+ if (Configuration::GetKnobBooleanValue(W("System.GC.RetainVM"), CLRConfig::UNSUPPORTED_GCRetainVM))
+ {
+ startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | STARTUP_HOARD_GC_VM);
+ }
+
+ *startupFlagsRef = startupFlags;
+}
+
+static void ConvertConfigPropertiesToUnicode(
const char** propertyKeys,
const char** propertyValues,
- int* propertyCountRef,
- STARTUP_FLAGS* startupFlagsRef,
+ int propertyCount,
LPCWSTR** propertyKeysWRef,
LPCWSTR** propertyValuesWRef)
{
- int propertyCount = *propertyCountRef;
-
LPCWSTR* propertyKeysW = new (nothrow) LPCWSTR[propertyCount];
ASSERTE_ALL_BUILDS(propertyKeysW != nullptr);
LPCWSTR* propertyValuesW = new (nothrow) LPCWSTR[propertyCount];
ASSERTE_ALL_BUILDS(propertyValuesW != nullptr);
- // Extract the startup flags from the properties, and convert the remaining properties into unicode
- STARTUP_FLAGS startupFlags =
- static_cast<STARTUP_FLAGS>(
- STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN |
- STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN |
- STARTUP_FLAGS::STARTUP_CONCURRENT_GC);
- int propertyCountW = 0;
for (int propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex)
{
- auto SetFlagValue = [&](STARTUP_FLAGS flag)
- {
- if (strcmp(propertyValues[propertyIndex], "0") == 0)
- {
- startupFlags = static_cast<STARTUP_FLAGS>(startupFlags & ~flag);
- }
- else if (strcmp(propertyValues[propertyIndex], "1") == 0)
- {
- startupFlags = static_cast<STARTUP_FLAGS>(startupFlags | flag);
- }
- };
-
- if (strcmp(propertyKeys[propertyIndex], "CONCURRENT_GC") == 0)
- {
- SetFlagValue(STARTUP_CONCURRENT_GC);
- }
- else if (strcmp(propertyKeys[propertyIndex], "SERVER_GC") == 0)
- {
- SetFlagValue(STARTUP_SERVER_GC);
- }
- else if (strcmp(propertyKeys[propertyIndex], "HOARD_GC_VM") == 0)
- {
- SetFlagValue(STARTUP_HOARD_GC_VM);
- }
- else if (strcmp(propertyKeys[propertyIndex], "TRIM_GC_COMMIT") == 0)
- {
- SetFlagValue(STARTUP_TRIM_GC_COMMIT);
- }
- else
- {
- // This is not a CoreCLR startup flag, convert it to unicode and preserve it for returning
- propertyKeysW[propertyCountW] = StringToUnicode(propertyKeys[propertyIndex]);
- propertyValuesW[propertyCountW] = StringToUnicode(propertyValues[propertyIndex]);
- ++propertyCountW;
- }
- }
-
- for (int propertyIndex = propertyCountW; propertyIndex < propertyCount; ++propertyIndex)
- {
- propertyKeysW[propertyIndex] = nullptr;
- propertyValuesW[propertyIndex] = nullptr;
+ propertyKeysW[propertyIndex] = StringToUnicode(propertyKeys[propertyIndex]);
+ propertyValuesW[propertyIndex] = StringToUnicode(propertyValues[propertyIndex]);
}
- *propertyCountRef = propertyCountW;
- *startupFlagsRef = startupFlags;
*propertyKeysWRef = propertyKeysW;
*propertyValuesWRef = propertyValuesW;
}
@@ -205,22 +177,20 @@ int coreclr_initialize(
ConstWStringHolder appDomainFriendlyNameW = StringToUnicode(appDomainFriendlyName);
- STARTUP_FLAGS startupFlags;
- LPCWSTR* propertyKeysWTemp;
- LPCWSTR* propertyValuesWTemp;
- ExtractStartupFlagsAndConvertToUnicode(
+ LPCWSTR* propertyKeysW;
+ LPCWSTR* propertyValuesW;
+ ConvertConfigPropertiesToUnicode(
propertyKeys,
propertyValues,
- &propertyCount,
- &startupFlags,
- &propertyKeysWTemp,
- &propertyValuesWTemp);
-
- ConstWStringArrayHolder propertyKeysW;
- propertyKeysW.Set(propertyKeysWTemp, propertyCount);
-
- ConstWStringArrayHolder propertyValuesW;
- propertyValuesW.Set(propertyValuesWTemp, propertyCount);
+ propertyCount,
+ &propertyKeysW,
+ &propertyValuesW);
+
+ // This will take ownership of propertyKeysWTemp and propertyValuesWTemp
+ Configuration::InitializeConfigurationKnobs(propertyCount, propertyKeysW, propertyValuesW);
+
+ STARTUP_FLAGS startupFlags;
+ InitializeStartupFlags(&startupFlags);
hr = host->SetStartupFlags(startupFlags);
IfFailRet(hr);
diff --git a/src/inc/clrconfig.h b/src/inc/clrconfig.h
index 2fbc2e1de8..6d8c98190d 100644
--- a/src/inc/clrconfig.h
+++ b/src/inc/clrconfig.h
@@ -171,7 +171,10 @@ public:
// Look up a DWORD config value.
static DWORD GetConfigValue(const ConfigDWORDInfo & info);
-
+
+ // Look up a DWORD config value.
+ static DWORD GetConfigValue(const ConfigDWORDInfo & info, bool acceptExplicitDefaultFromRegutil, /* [Out] */ bool *isDefault);
+
// Look up a string config value.
// You own the string that's returned.
static LPWSTR GetConfigValue(const ConfigStringInfo & info);
diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h
index d792339812..98c5aa5fe0 100644
--- a/src/inc/clrconfigvalues.h
+++ b/src/inc/clrconfigvalues.h
@@ -309,6 +309,7 @@ CONFIG_DWORD_INFO(INTERNAL_FastGCCheckStack, W("FastGCCheckStack"), 0, "")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_FastGCStress, W("FastGCStress"), "reduce the number of GCs done by enabling GCStress")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCBreakOnOOM, W("GCBreakOnOOM"), "Does a DebugBreak at the soonest time we detect an OOM")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_gcConcurrent, W("gcConcurrent"), (DWORD)-1, "Enables/Disables concurrent GC")
+
#ifdef FEATURE_CONSERVATIVE_GC
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_gcConservative, W("gcConservative"), 0, "Enables/Disables conservative GC")
#endif
@@ -335,7 +336,7 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCCompactRatio, W("GCCompactRatio"), 0, "Sp
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_GCPollType, W("GCPollType"), "")
RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_NewGCCalc, W("NewGCCalc"), "", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCprnLvl, W("GCprnLvl"), "Specifies the maximum level of GC logging")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCRetainVM, W("GCRetainVM"), "When set we put the segments that should be deleted on a standby list (instead of releasing them back to the OS) which will be considered to satisfy new segment requests (note that the same thing can be specified via API which is the supported way)")
+RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCRetainVM, W("GCRetainVM"), 0, "When set we put the segments that should be deleted on a standby list (instead of releasing them back to the OS) which will be considered to satisfy new segment requests (note that the same thing can be specified via API which is the supported way)")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCSegmentSize, W("GCSegmentSize"), "Specifies the managed heap segment size")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_GCLOHCompact, W("GCLOHCompact"), "Specifies the LOH compaction mode")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_gcAllowVeryLargeObjects, W("gcAllowVeryLargeObjects"), 0, "allow allocation of 2GB+ objects on GC heap")
diff --git a/src/inc/configuration.h b/src/inc/configuration.h
new file mode 100644
index 0000000000..d8f8dff72b
--- /dev/null
+++ b/src/inc/configuration.h
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// --------------------------------------------------------------------------------------------------
+// configuration.h
+//
+//
+// Access and update configuration values, falling back on legacy CLRConfig methods where necessary.
+//
+// --------------------------------------------------------------------------------------------------
+
+#include "clrconfig.h"
+
+#ifndef __configuration_h__
+#define __configuration_h__
+
+class Configuration
+{
+public:
+ static void InitializeConfigurationKnobs(int numberOfConfigs, LPCWSTR *configNames, LPCWSTR *configValues);
+
+ // Returns (in priority order):
+ // - The value of the ConfigDWORDInfo if it's set
+ // - The value of the ConfigurationKnob (searched by name) if it's set (performs a wcstoul).
+ // - The default set in the ConfigDWORDInfo
+ static DWORD GetKnobDWORDValue(LPCWSTR name, const CLRConfig::ConfigDWORDInfo& dwordInfo);
+
+ // Returns (in priority order):
+ // - The value of the ConfigurationKnob (searched by name) if it's set (performs a wcstoul)
+ // - The default value passed in
+ static DWORD GetKnobDWORDValue(LPCWSTR name, DWORD defaultValue);
+
+ // Returns (in priority order):
+ // - The value of the ConfigStringInfo if it's set
+ // - The value of the ConfigurationKnob (searched by name) if it's set
+ // - nullptr
+ static LPCWSTR GetKnobStringValue(LPCWSTR name, const CLRConfig::ConfigStringInfo& stringInfo);
+
+ // Returns (in priority order):
+ // - The value of the ConfigurationKnob (searched by name) if it's set
+ // - nullptr
+ static LPCWSTR GetKnobStringValue(LPCWSTR name);
+
+ // Returns (in priority order):
+ // - The value of the ConfigDWORDInfo if it's set (1 is true, anything else is false)
+ // - The value of the ConfigurationKnob (searched by name) if it's set (performs a wcscmp with "true").
+ // - The default set in the ConfigDWORDInfo (1 is true, anything else is false)
+ static bool GetKnobBooleanValue(LPCWSTR name, const CLRConfig::ConfigDWORDInfo& dwordInfo);
+
+ // Returns (in priority order):
+ // - The value of the ConfigurationKnob (searched by name) if it's set (performs a wcscmp with "true").
+ // - The default value passed in
+ static bool GetKnobBooleanValue(LPCWSTR name, bool defaultValue);
+};
+
+#endif // __configuration_h__
diff --git a/src/utilcode/CMakeLists.txt b/src/utilcode/CMakeLists.txt
index 001205a62b..9d35a7e641 100644
--- a/src/utilcode/CMakeLists.txt
+++ b/src/utilcode/CMakeLists.txt
@@ -16,6 +16,7 @@ set(UTILCODE_COMMON_SOURCES
makepath.cpp
splitpath.cpp
clrconfig.cpp
+ configuration.cpp
collections.cpp
posterror.cpp
fstream.cpp
diff --git a/src/utilcode/UtilCode.vcproj b/src/utilcode/UtilCode.vcproj
index c12516464a..286456616e 100644
--- a/src/utilcode/UtilCode.vcproj
+++ b/src/utilcode/UtilCode.vcproj
@@ -375,6 +375,9 @@
<File
RelativePath=".\CLRConfig.cpp"
>
+ <File
+ RelativePath=".\configuration.cpp"
+ >
</File>
<File
RelativePath=".\clrhost.cpp"
diff --git a/src/utilcode/UtilCode.vcxproj b/src/utilcode/UtilCode.vcxproj
index 54afef7da4..d3f6add8bb 100644
--- a/src/utilcode/UtilCode.vcxproj
+++ b/src/utilcode/UtilCode.vcxproj
@@ -382,6 +382,7 @@
<ClCompile Include="check.cpp" />
<ClCompile Include="circularlog.cpp" />
<ClCompile Include="CLRConfig.cpp" />
+ <ClCompile Include="configuration.cpp" />
<ClCompile Include="clrhost.cpp" />
<ClCompile Include="COMEx.cpp" />
<ClCompile Include="corimage.cpp" />
diff --git a/src/utilcode/clrconfig.cpp b/src/utilcode/clrconfig.cpp
index c8a82060e9..163974999d 100644
--- a/src/utilcode/clrconfig.cpp
+++ b/src/utilcode/clrconfig.cpp
@@ -297,16 +297,25 @@ BOOL CLRConfig::IsConfigEnabled(const ConfigDWORDInfo & info)
return FALSE;
}
-
-
//
// Look up a DWORD config value.
//
// Arguments:
-// * info - see file:../inc/CLRConfig.h for details
-//
+// * info - see file:../inc/CLRConfig.h for details.
+//
+// * useDefaultIfNotSet - if true, fall back to the default value if the value is not set.
+//
+// * acceptExplicitDefaultFromRegutil - if false, only accept a value returned by REGUTIL if it is
+// different from the default value. This parameter is useful as a way to preserve existing
+// behavior.
+//
+// * result - the result.
+//
+// Return value:
+// * true for success, false otherwise.
+//
// static
-DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
+DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info, bool acceptExplicitDefaultFromRegutil, /* [Out] */ bool *isDefault)
{
CONTRACTL
{
@@ -317,7 +326,7 @@ DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
}
CONTRACTL_END;
- DWORD result = info.defaultValue;
+ _ASSERTE (isDefault != nullptr);
#ifdef FEATURE_WIN_DB_APPCOMPAT
// Windows Shim DB should be the first place to look as it applies microsoft enforced policy
@@ -325,7 +334,6 @@ DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
if(CheckLookupOption(info, IgnoreWindowsQuirkDB) == FALSE &&
s_IsQuirkEnabledCallback != NULL )// Check that IsQuirkEnabledCallback function has been registered.
{
-
BOOL isEnabledInDB = FALSE;
CPT_QUIRK_DATA quirkData;
if(SUCCEEDED(getQuirkEnabledAndValueFromWinDB(info.name, &isEnabledInDB, &quirkData)))
@@ -334,19 +342,21 @@ DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
{
WCHAR *end;
errno = 0;
- result = wcstoul(quirkData.CommandLine, &end, 0);
-
+ DWORD resultMaybe = wcstoul(quirkData.CommandLine, &end, 0);
+
// errno is ERANGE if the number is out of range, and end is set to pvalue if
// no valid conversion exists.
if (errno != ERANGE && end != quirkData.CommandLine)
{
- return result;
+ *isDefault = false;
+ return resultMaybe;
}
else
{
// If an invalid value is defined we treat it as the default value.
// i.e. we don't look further.
- return info.defaultValue;
+ *isDefault = true;
+ return info.defaultValue;
}
}
}
@@ -362,46 +372,64 @@ DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
//
// If we aren't favoring config files, we check REGUTIL here.
//
- if(CheckLookupOption(info, FavorConfigFile) == FALSE)
+ if (CheckLookupOption(info, FavorConfigFile) == FALSE)
{
- REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPlus);
- // TODO: We are ignoring explicitly defined default values to avoid change in behavior.
- // TODO: Ideally, the following should check the hresult for success.
- if(result != info.defaultValue)
+ DWORD resultMaybe;
+ HRESULT hr = REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &resultMaybe, level, prependCOMPlus);
+
+ if (!acceptExplicitDefaultFromRegutil)
{
- return result;
+ // Ignore the default value even if it's set explicitly.
+ if (resultMaybe != info.defaultValue)
+ {
+ *isDefault = false;
+ return resultMaybe;
+ }
+ }
+ else
+ {
+ // If we are willing to accept the default value when it's set explicitly,
+ // checking the HRESULT here is sufficient. E_FAIL is returned when the
+ // default is used.
+ if (SUCCEEDED(hr))
+ {
+ *isDefault = false;
+ return resultMaybe;
+ }
}
}
//
// Check config files through EEConfig.
//
- if(CheckLookupOption(info, IgnoreConfigFiles) == FALSE && // Check that we aren't ignoring config files.
+ if (CheckLookupOption(info, IgnoreConfigFiles) == FALSE && // Check that we aren't ignoring config files.
s_GetConfigValueCallback != NULL)// Check that GetConfigValueCallback function has been registered.
- {
+ {
LPCWSTR pvalue;
// EEConfig lookup options.
BOOL systemOnly = CheckLookupOption(info, ConfigFile_SystemOnly) ? TRUE : FALSE;
BOOL applicationFirst = CheckLookupOption(info, ConfigFile_ApplicationFirst) ? TRUE : FALSE;
-
- if(SUCCEEDED(s_GetConfigValueCallback(info.name, &pvalue, systemOnly, applicationFirst)) && pvalue != NULL)
+
+ if (SUCCEEDED(s_GetConfigValueCallback(info.name, &pvalue, systemOnly, applicationFirst)) && pvalue != NULL)
{
WCHAR * end;
errno = 0;
- result = wcstoul(pvalue, &end, 0);
-
+ DWORD resultMaybe = wcstoul(pvalue, &end, 0);
+
// errno is ERANGE if the number is out of range, and end is set to pvalue if
// no valid conversion exists.
if (errno != ERANGE && end != pvalue)
{
- return result;
+ *isDefault = false;
+ return resultMaybe;
}
else
{
// If an invalid value is defined we treat it as the default value.
// i.e. we don't look further.
- return info.defaultValue;
+ *isDefault = true;
+ return info.defaultValue;
}
}
}
@@ -409,14 +437,30 @@ DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
//
// If we are favoring config files and we don't have a result from EEConfig, we check REGUTIL here.
//
- if(CheckLookupOption(info, FavorConfigFile) == TRUE)
+ if (CheckLookupOption(info, FavorConfigFile) == TRUE)
{
- REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPlus);
- // TODO: We are ignoring explicitly defined default values to avoid change in behavior.
- // TODO: Ideally, the following should check the hresult for success.
- if(result != info.defaultValue)
+ DWORD resultMaybe;
+ HRESULT hr = REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &resultMaybe, level, prependCOMPlus);
+
+ if (!acceptExplicitDefaultFromRegutil)
{
- return result;
+ // Ignore the default value even if it's set explicitly.
+ if (resultMaybe != info.defaultValue)
+ {
+ *isDefault = false;
+ return resultMaybe;
+ }
+ }
+ else
+ {
+ // If we are willing to accept the default value when it's set explicitly,
+ // checking the HRESULT here is sufficient. E_FAIL is returned when the
+ // default is used.
+ if (SUCCEEDED(hr))
+ {
+ *isDefault = false;
+ return resultMaybe;
+ }
}
}
@@ -431,14 +475,34 @@ DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
{
// TODO: We ignore explicitly defined default values above, but we do not want to let performance defaults override these.
// TODO: Ideally, the above would use hresult for success and this check would be removed.
- if (!SUCCEEDED(REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &result, level, prependCOMPlus)))
+ DWORD resultMaybe;
+ if (!SUCCEEDED(REGUTIL::GetConfigDWORD_DontUse_(info.name, info.defaultValue, &resultMaybe, level, prependCOMPlus)))
+ {
+ *isDefault = true;
return performanceDefaultValue;
+ }
}
+ *isDefault = true;
return info.defaultValue;
}
//
+// Look up a DWORD config value.
+//
+// Arguments:
+// * info - see file:../inc/CLRConfig.h for details
+//
+// static
+DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info)
+{
+ // We pass false for 'acceptExplicitDefaultFromRegutil' to maintain the existing behavior of this function.
+ // Callers who don't need that behavior should switch to the other version of this function and pass true.
+ bool unused;
+ return GetConfigValue(info, false /* acceptExplicitDefaultFromRegutil */, &unused);
+}
+
+//
// Look up a String config value.
//
// Arguments:
diff --git a/src/utilcode/configuration.cpp b/src/utilcode/configuration.cpp
new file mode 100644
index 0000000000..817bc06e90
--- /dev/null
+++ b/src/utilcode/configuration.cpp
@@ -0,0 +1,125 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// --------------------------------------------------------------------------------------------------
+// configuration.cpp
+//
+//
+// Access and update configuration values, falling back on legacy CLRConfig methods where necessary.
+//
+// --------------------------------------------------------------------------------------------------
+
+#include "stdafx.h"
+
+#include "clrconfig.h"
+#include "configuration.h"
+
+LPCWSTR *knobNames = nullptr;
+LPCWSTR *knobValues = nullptr;
+int numberOfKnobs = 0;
+
+void Configuration::InitializeConfigurationKnobs(int numberOfConfigs, LPCWSTR *names, LPCWSTR *values)
+{
+ numberOfKnobs = numberOfConfigs;
+
+ // Neither should be null, or both should be null
+ _ASSERT(!((names == nullptr) ^ (values == nullptr)));
+
+ knobNames = names;
+ knobValues = values;
+}
+
+static LPCWSTR GetConfigurationValue(LPCWSTR name)
+{
+ _ASSERT(name != nullptr);
+ if (name == nullptr || knobNames == nullptr || knobValues == nullptr)
+ {
+ return nullptr;
+ }
+
+ for (int i = 0; i < numberOfKnobs; ++i)
+ {
+ _ASSERT(knobNames[i] != nullptr);
+ if (wcscmp(name, knobNames[i]) == 0)
+ {
+ return knobValues[i];
+ }
+ }
+
+ return nullptr;
+}
+
+DWORD Configuration::GetKnobDWORDValue(LPCWSTR name, const CLRConfig::ConfigDWORDInfo& dwordInfo)
+{
+ bool returnedDefaultValue;
+ DWORD legacyValue = CLRConfig::GetConfigValue(dwordInfo, true /* acceptExplicitDefaultFromRegutil */, &returnedDefaultValue);
+ if (!returnedDefaultValue)
+ {
+ return legacyValue;
+ }
+
+ LPCWSTR knobValue = GetConfigurationValue(name);
+ if (knobValue != nullptr)
+ {
+ return wcstoul(knobValue, nullptr, 0);
+ }
+
+ return legacyValue;
+}
+
+DWORD Configuration::GetKnobDWORDValue(LPCWSTR name, DWORD defaultValue)
+{
+ LPCWSTR knobValue = GetConfigurationValue(name);
+ if (knobValue != nullptr)
+ {
+ return wcstoul(knobValue, nullptr, 0);
+ }
+
+ return defaultValue;
+}
+
+LPCWSTR Configuration::GetKnobStringValue(LPCWSTR name, const CLRConfig::ConfigStringInfo& stringInfo)
+{
+ LPCWSTR value = CLRConfig::GetConfigValue(stringInfo);
+ if (value == nullptr)
+ {
+ value = GetConfigurationValue(name);
+ }
+
+ return value;
+}
+
+LPCWSTR Configuration::GetKnobStringValue(LPCWSTR name)
+{
+ return GetConfigurationValue(name);
+}
+
+bool Configuration::GetKnobBooleanValue(LPCWSTR name, const CLRConfig::ConfigDWORDInfo& dwordInfo)
+{
+ bool returnedDefaultValue;
+ DWORD legacyValue = CLRConfig::GetConfigValue(dwordInfo, true /* acceptExplicitDefaultFromRegutil */, &returnedDefaultValue);
+ if (!returnedDefaultValue)
+ {
+ return (legacyValue != 0);
+ }
+
+ LPCWSTR knobValue = GetConfigurationValue(name);
+ if (knobValue != nullptr)
+ {
+ return (wcscmp(knobValue, W("true")) == 0);
+ }
+
+ return (legacyValue != 0);
+}
+
+bool Configuration::GetKnobBooleanValue(LPCWSTR name, bool defaultValue)
+{
+ LPCWSTR knobValue = GetConfigurationValue(name);
+ if (knobValue != nullptr)
+ {
+ return (wcscmp(knobValue, W("true")) == 0);
+ }
+
+ return defaultValue;
+} \ No newline at end of file
diff --git a/src/utilcode/utilcode.settings.targets b/src/utilcode/utilcode.settings.targets
index 7c11fd50b4..7fbcb4d5cc 100644
--- a/src/utilcode/utilcode.settings.targets
+++ b/src/utilcode/utilcode.settings.targets
@@ -45,6 +45,7 @@
<CppCompile Include="$(UtilCodeSrcDir)\SplitPath.cpp" />
<CppCompile Include="$(UtilCodeSrcDir)\ClrConfig.cpp" />
+ <CppCompile Include="$(UtilCodeSrcDir)\configuration.cpp" />
<CppCompile Include="$(UtilCodeSrcDir)\RegUtil.cpp" />
<CppCompile Include="$(UtilCodeSrcDir)\RegistryWrapper.cpp" />
diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp
index dfd2235408..2aaeaec0f0 100644
--- a/src/vm/ceemain.cpp
+++ b/src/vm/ceemain.cpp
@@ -3006,7 +3006,7 @@ static BOOL CacheCommandLine(__in LPWSTR pCmdLine, __in_opt LPWSTR* ArgvW)
}
//*****************************************************************************
-// This entry point is called from the native entry piont of the loaded
+// This entry point is called from the native entry point of the loaded
// executable image. The command line arguments and other entry point data
// will be gathered here. The entry point for the user image will be found
// and handled accordingly.
diff --git a/src/vm/corhost.cpp b/src/vm/corhost.cpp
index f0e90291b7..a37867d009 100644
--- a/src/vm/corhost.cpp
+++ b/src/vm/corhost.cpp
@@ -2004,11 +2004,6 @@ HRESULT CorHost2::SetStartupFlags(STARTUP_FLAGS flag)
return HOST_E_INVALIDOPERATION;
}
- if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_gcServer) != 0)
- {
- flag = (STARTUP_FLAGS)(flag | STARTUP_SERVER_GC);
- }
-
m_dwStartupFlags = flag;
return S_OK;
diff --git a/src/vm/eeconfig.cpp b/src/vm/eeconfig.cpp
index 973a4f4235..ddf2048f33 100644
--- a/src/vm/eeconfig.cpp
+++ b/src/vm/eeconfig.cpp
@@ -33,6 +33,9 @@
#ifdef FEATURE_WIN_DB_APPCOMPAT
#include "QuirksApi.h"
#endif
+#ifdef FEATURE_CORECLR
+#include "configuration.h"
+#endif
using namespace clr;
@@ -789,10 +792,18 @@ HRESULT EEConfig::sync()
g_fEnableARM = TRUE;
}
- int forceGCconcurrent = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_gcConcurrent);
- if ((forceGCconcurrent > 0) || (forceGCconcurrent == -1 && g_IGCconcurrent))
+ bool gcConcurrentWasForced = false;
+#ifdef FEATURE_CORECLR
+ gcConcurrentWasForced = Configuration::GetKnobBooleanValue(W("System.GC.Concurrent"), CLRConfig::UNSUPPORTED_gcConcurrent);
+ if (gcConcurrentWasForced)
iGCconcurrent = TRUE;
-
+#else
+ int gcConcurrentConfigVal = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_gcConcurrent);
+ gcConcurrentWasForced = (gcConcurrentConfigVal > 0);
+ if (gcConcurrentWasForced || (gcConcurrentConfigVal == -1 && g_IGCconcurrent))
+ iGCconcurrent = TRUE;
+#endif
+
// Disable concurrent GC during ngen for the rare case a GC gets triggered, causing problems
if (IsCompilationProcess())
iGCconcurrent = FALSE;
@@ -853,7 +864,7 @@ HRESULT EEConfig::sync()
if (bGCStressAndHeapVerifyAllowed)
{
- if (forceGCconcurrent > 0)
+ if (gcConcurrentWasForced)
{
#ifdef _DEBUG
iFastGCStress = 0;
@@ -901,7 +912,7 @@ HRESULT EEConfig::sync()
if (g_IGCHoardVM)
iGCHoardVM = g_IGCHoardVM;
else
- iGCHoardVM = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCRetainVM, iGCHoardVM);
+ iGCHoardVM = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCRetainVM);
if (!iGCLOHCompactionMode) iGCLOHCompactionMode = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCLOHCompact, iGCLOHCompactionMode);
diff --git a/src/vm/win32threadpool.cpp b/src/vm/win32threadpool.cpp
index 13c10a867f..af7b26c1e2 100644
--- a/src/vm/win32threadpool.cpp
+++ b/src/vm/win32threadpool.cpp
@@ -32,6 +32,7 @@ Revision History:
#include "appdomain.inl"
#include "nativeoverlapped.h"
#include "hillclimbing.h"
+#include "configuration.h"
#ifndef FEATURE_PAL
@@ -302,6 +303,16 @@ DWORD GetDefaultMaxLimitWorkerThreads(DWORD minLimit)
return (DWORD)limit;
}
+DWORD GetForceMinWorkerThreadsValue()
+{
+ return Configuration::GetKnobDWORDValue(W("System.Threading.ThreadPool.MinThreads"), CLRConfig::INTERNAL_ThreadPool_ForceMinWorkerThreads);
+}
+
+DWORD GetForceMaxWorkerThreadsValue()
+{
+ return Configuration::GetKnobDWORDValue(W("System.Threading.ThreadPool.MaxThreads"), CLRConfig::INTERNAL_ThreadPool_ForceMaxWorkerThreads);
+}
+
BOOL ThreadpoolMgr::Initialize()
{
CONTRACTL
@@ -392,11 +403,11 @@ BOOL ThreadpoolMgr::Initialize()
// initialize Worker and CP thread settings
DWORD forceMin;
- forceMin = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ThreadPool_ForceMinWorkerThreads);
+ forceMin = GetForceMinWorkerThreadsValue();
MinLimitTotalWorkerThreads = forceMin > 0 ? (LONG)forceMin : (LONG)NumberOfProcessors;
DWORD forceMax;
- forceMax = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ThreadPool_ForceMaxWorkerThreads);
+ forceMax = GetForceMaxWorkerThreadsValue();
MaxLimitTotalWorkerThreads = forceMax > 0 ? (LONG)forceMax : (LONG)GetDefaultMaxLimitWorkerThreads(MinLimitTotalWorkerThreads);
ThreadCounter::Counts counts;
@@ -511,7 +522,7 @@ BOOL ThreadpoolMgr::SetMaxThreadsHelper(DWORD MaxWorkerThreads,
{
BEGIN_SO_INTOLERANT_CODE(GetThread());
- if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ThreadPool_ForceMaxWorkerThreads) == 0)
+ if (GetForceMaxWorkerThreadsValue() == 0)
{
MaxLimitTotalWorkerThreads = min(MaxWorkerThreads, (DWORD)ThreadCounter::MaxPossibleCount);
@@ -663,11 +674,11 @@ BOOL ThreadpoolMgr::GetMaxThreads(DWORD* MaxWorkerThreads,
NumberOfProcessors = CPUGroupInfo::GetNumActiveProcessors();
else
NumberOfProcessors = GetCurrentProcessCpuCount();
- DWORD min = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ThreadPool_ForceMinWorkerThreads);
+ DWORD min = GetForceMinWorkerThreadsValue();
if (min == 0)
min = NumberOfProcessors;
- DWORD forceMax = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ThreadPool_ForceMaxWorkerThreads);
+ DWORD forceMax = GetForceMaxWorkerThreadsValue();
if (forceMax > 0)
{
*MaxWorkerThreads = forceMax;
@@ -748,7 +759,7 @@ BOOL ThreadpoolMgr::SetMinThreads(DWORD MinWorkerThreads,
{
BEGIN_SO_INTOLERANT_CODE(GetThread());
- if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ThreadPool_ForceMinWorkerThreads) == 0)
+ if (GetForceMinWorkerThreadsValue() == 0)
{
MinLimitTotalWorkerThreads = min(MinWorkerThreads, (DWORD)ThreadCounter::MaxPossibleCount);
@@ -849,7 +860,7 @@ BOOL ThreadpoolMgr::GetMinThreads(DWORD* MinWorkerThreads,
NumberOfProcessors = GetCurrentProcessCpuCount();
DWORD forceMin;
BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), forceMin=0);
- forceMin = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ThreadPool_ForceMinWorkerThreads);
+ forceMin = GetForceMinWorkerThreadsValue();
END_SO_INTOLERANT_CODE;
*MinWorkerThreads = forceMin > 0 ? forceMin : NumberOfProcessors;
*MinIOCompletionThreads = NumberOfProcessors;