diff options
author | Steve MacLean <Steve.MacLean@microsoft.com> | 2019-05-14 20:34:39 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-14 20:34:39 -0400 |
commit | 6a85ca560a7dfa109c6f17c0b76d93373dbd5a00 (patch) | |
tree | 593b18340d46fbddf17ff803c9760a6e4df36df2 | |
parent | 75addddd0601ab4e57ff41fada17128df47842ef (diff) | |
download | coreclr-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.md | 1 | ||||
-rw-r--r-- | src/inc/clrconfigvalues.h | 1 | ||||
-rw-r--r-- | src/vm/corhost.cpp | 6 | ||||
-rw-r--r-- | src/vm/threads.cpp | 59 |
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()) { |