summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve MacLean <Steve.MacLean@microsoft.com>2019-05-14 20:34:39 -0400
committerGitHub <noreply@github.com>2019-05-14 20:34:39 -0400
commit6a85ca560a7dfa109c6f17c0b76d93373dbd5a00 (patch)
tree593b18340d46fbddf17ff803c9760a6e4df36df2
parent75addddd0601ab4e57ff41fada17128df47842ef (diff)
downloadcoreclr-6a85ca560a7dfa109c6f17c0b76d93373dbd5a00.tar.gz
coreclr-6a85ca560a7dfa109c6f17c0b76d93373dbd5a00.tar.bz2
coreclr-6a85ca560a7dfa109c6f17c0b76d93373dbd5a00.zip
Stack size override (#24532)
Add ability to override stack size on all platforms * Add DEFAULT_STACK_SIZE property * Make environment variable affect all platforms
-rw-r--r--Documentation/project-docs/clr-configuration-knobs.md1
-rw-r--r--src/inc/clrconfigvalues.h1
-rw-r--r--src/vm/corhost.cpp6
-rw-r--r--src/vm/threads.cpp59
4 files changed, 67 insertions, 0 deletions
diff --git a/Documentation/project-docs/clr-configuration-knobs.md b/Documentation/project-docs/clr-configuration-knobs.md
index 61f4d00e41..42f1b647e3 100644
--- a/Documentation/project-docs/clr-configuration-knobs.md
+++ b/Documentation/project-docs/clr-configuration-knobs.md
@@ -759,6 +759,7 @@ Name | Description | Type | Class | Default Value | Flags
Name | Description | Type | Class | Default Value | Flags
-----|-------------|------|-------|---------------|-------
+`DefaultStackSize` | Stack size to use for new VM threads when thread is created with default stack size (dwStackSize == 0). | `DWORD` | `INTERNAL` | `0` |
`Thread_DeadThreadCountThresholdForGCTrigger` | In the heuristics to clean up dead threads, this threshold must be reached before triggering a GC will be considered. Set to 0 to disable triggering a GC based on dead threads. | `DWORD` | `INTERNAL` | `75` |
`Thread_DeadThreadGCTriggerPeriodMilliseconds` | In the heuristics to clean up dead threads, this much time must have elapsed since the previous max-generation GC before triggering another GC will be considered | `DWORD` | `INTERNAL` | `1000 * 60 * 30` |
diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h
index 17188b8c27..9dcb5da790 100644
--- a/src/inc/clrconfigvalues.h
+++ b/src/inc/clrconfigvalues.h
@@ -607,6 +607,7 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_ThreadSuspendInjection, W("INTERNAL_ThreadSusp
///
/// Thread (miscellaneous)
///
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_DefaultStackSize, W("DefaultStackSize"), 0, "Stack size to use for new VM threads when thread is created with default stack size (dwStackSize == 0).")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_Thread_DeadThreadCountThresholdForGCTrigger, W("Thread_DeadThreadCountThresholdForGCTrigger"), 75, "In the heuristics to clean up dead threads, this threshold must be reached before triggering a GC will be considered. Set to 0 to disable triggering a GC based on dead threads.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_Thread_DeadThreadGCTriggerPeriodMilliseconds, W("Thread_DeadThreadGCTriggerPeriodMilliseconds"), 1000 * 60 * 30, "In the heuristics to clean up dead threads, this much time must have elapsed since the previous max-generation GC before triggering another GC will be considered")
diff --git a/src/vm/corhost.cpp b/src/vm/corhost.cpp
index cbba60dc61..025f708fe5 100644
--- a/src/vm/corhost.cpp
+++ b/src/vm/corhost.cpp
@@ -742,6 +742,12 @@ HRESULT CorHost2::_CreateAppDomain(
pwzAppNiPaths = pPropertyValues[i];
}
else
+ if (wcscmp(pPropertyNames[i], W("DEFAULT_STACK_SIZE")) == 0)
+ {
+ extern void ParseDefaultStackSize(LPCWSTR value);
+ ParseDefaultStackSize(pPropertyValues[i]);
+ }
+ else
if (wcscmp(pPropertyNames[i], W("USE_ENTRYPOINT_FILTER")) == 0)
{
extern void ParseUseEntryPointFilter(LPCWSTR value);
diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp
index beb09f21b9..020f318684 100644
--- a/src/vm/threads.cpp
+++ b/src/vm/threads.cpp
@@ -2144,6 +2144,48 @@ HANDLE Thread::CreateUtilityThread(Thread::StackSizeBucket stackSizeBucket, LPTH
}
+// Represent the value of DEFAULT_STACK_SIZE as passed in the property bag to the host during construction
+static unsigned long s_defaultStackSizeProperty = 0;
+
+void ParseDefaultStackSize(LPCWSTR valueStr)
+{
+ if (valueStr)
+ {
+ LPWSTR end;
+ errno = 0;
+ unsigned long value = wcstoul(valueStr, &end, 16); // Base 16 without a prefix
+
+ if ((errno == ERANGE) // Parsed value doesn't fit in an unsigned long
+ || (valueStr == end) // No characters parsed
+ || (end == nullptr) // Unexpected condition (should never happen)
+ || (end[0] != 0)) // Unprocessed terminal characters
+ {
+ ThrowHR(E_INVALIDARG);
+ }
+ else
+ {
+ s_defaultStackSizeProperty = value;
+ }
+ }
+}
+
+SIZE_T GetDefaultStackSizeSetting()
+{
+ static DWORD s_defaultStackSizeEnv = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DefaultStackSize);
+
+ uint64_t value = s_defaultStackSizeEnv ? s_defaultStackSizeEnv : s_defaultStackSizeProperty;
+
+ SIZE_T minStack = 0x10000; // 64K - Somewhat arbitrary minimum thread stack size
+ SIZE_T maxStack = 0x80000000; // 2G - Somewhat arbitrary maximum thread stack size
+
+ if ((value >= maxStack) || ((value != 0) && (value < minStack)))
+ {
+ ThrowHR(E_INVALIDARG);
+ }
+
+ return (SIZE_T) value;
+}
+
BOOL Thread::GetProcessDefaultStackSize(SIZE_T* reserveSize, SIZE_T* commitSize)
{
CONTRACTL
@@ -2161,6 +2203,18 @@ BOOL Thread::GetProcessDefaultStackSize(SIZE_T* reserveSize, SIZE_T* commitSize)
static BOOL fSizesGot = FALSE;
+ if (!fSizesGot)
+ {
+ SIZE_T defaultStackSizeSetting = GetDefaultStackSizeSetting();
+
+ if (defaultStackSizeSetting != 0)
+ {
+ ExeSizeOfStackReserve = defaultStackSizeSetting;
+ ExeSizeOfStackCommit = defaultStackSizeSetting;
+ fSizesGot = TRUE;
+ }
+ }
+
#ifndef FEATURE_PAL
if (!fSizesGot)
{
@@ -2206,6 +2260,11 @@ BOOL Thread::CreateNewOSThread(SIZE_T sizeToCommitOrReserve, LPTHREAD_START_ROUT
dwCreationFlags |= STACK_SIZE_PARAM_IS_A_RESERVATION;
+ if (sizeToCommitOrReserve == 0)
+ {
+ sizeToCommitOrReserve = GetDefaultStackSizeSetting();
+ }
+
#ifndef FEATURE_PAL // the PAL does its own adjustments as necessary
if (sizeToCommitOrReserve != 0 && sizeToCommitOrReserve <= GetOsPageSize())
{