Skip to content

Commit e1d6402

Browse files
Allow stack size to be configured (#110455)
1 parent b7db8f4 commit e1d6402

File tree

10 files changed

+61
-6
lines changed

10 files changed

+61
-6
lines changed

src/coreclr/inc/clrconfigvalues.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_ThreadSuspendInjection, W("INTERNAL_ThreadSusp
453453
///
454454
/// Thread (miscellaneous)
455455
///
456-
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).")
456+
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Thread_DefaultStackSize, W("Thread_DefaultStackSize"), 0, "Stack size to use for new VM threads when thread is created with default stack size (dwStackSize == 0).")
457457
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.")
458458
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")
459459
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Thread_UseAllCpuGroups, W("Thread_UseAllCpuGroups"), 0, "Specifies whether to query and use CPU group information for determining the processor count.")

src/coreclr/nativeaot/Runtime/RhConfig.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,4 +195,23 @@ bool RhConfig::GetEmbeddedVariable(Config* config, _In_z_ const char* configName
195195
return false;
196196
}
197197

198+
size_t GetDefaultStackSizeSetting()
199+
{
200+
// Keep the same arbitrary minimum and maximum from the CoreCLR VM layer.
201+
const size_t minStack = 0x10000; // 64K
202+
const size_t maxStack = 0x80000000; // 2G
203+
204+
uint64_t uiStacksize;
205+
if (g_pRhConfig->ReadConfigValue("Thread_DefaultStackSize", &uiStacksize)
206+
|| g_pRhConfig->ReadKnobUInt64Value("System.Threading.DefaultStackSize", &uiStacksize))
207+
{
208+
if (uiStacksize < maxStack || uiStacksize >= minStack)
209+
{
210+
return (size_t)uiStacksize;
211+
}
212+
}
213+
214+
return 0;
215+
}
216+
198217
#endif

src/coreclr/nativeaot/Runtime/RhConfig.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ class RhConfig
109109

110110
extern RhConfig * g_pRhConfig;
111111

112+
size_t GetDefaultStackSizeSetting();
113+
112114
#endif //!DACCESS_COMPILE
113115

114116
#endif // RHCONFIG_H

src/coreclr/nativeaot/Runtime/thread.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,12 @@ FCIMPL0(uint64_t, RhCurrentOSThreadId)
13171317
}
13181318
FCIMPLEND
13191319

1320+
FCIMPL0(size_t, RhGetDefaultStackSize)
1321+
{
1322+
return GetDefaultStackSizeSetting();
1323+
}
1324+
FCIMPLEND
1325+
13201326
// Standard calling convention variant and actual implementation for RhpReversePInvokeAttachOrTrapThread
13211327
EXTERN_C NOINLINE void FASTCALL RhpReversePInvokeAttachOrTrapThread2(ReversePInvokeFrame* pFrame)
13221328
{

src/coreclr/nativeaot/Runtime/unix/PalUnix.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,13 @@ bool PalStartBackgroundWork(_In_ BackgroundCallback callback, _In_opt_ void* pCa
765765

766766
int st = pthread_attr_init(&attrs);
767767
ASSERT(st == 0);
768+
769+
size_t stacksize = GetDefaultStackSizeSetting();
770+
if (stacksize != 0)
771+
{
772+
st = pthread_attr_setstacksize(&attrs, stacksize);
773+
ASSERT(st == 0);
774+
}
768775

769776
static const int NormalPriority = 0;
770777
static const int HighestPriority = -20;

src/coreclr/nativeaot/Runtime/windows/PalMinWin.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,9 +846,11 @@ static pfnSetThreadDescription g_pfnSetThreadDescription = SET_THREAD_DESCRIPTIO
846846

847847
bool PalStartBackgroundWork(_In_ BackgroundCallback callback, _In_opt_ void* pCallbackContext, BOOL highPriority)
848848
{
849+
DWORD stacksize = (DWORD)GetDefaultStackSizeSetting();
850+
849851
HANDLE hThread = CreateThread(
850852
NULL,
851-
0,
853+
(DWORD)stacksize,
852854
(LPTHREAD_START_ROUTINE)callback,
853855
pCallbackContext,
854856
highPriority ? CREATE_SUSPENDED : 0,

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,10 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe
583583
[RuntimeImport(RuntimeLibrary, "RhCurrentOSThreadId")]
584584
internal static extern unsafe ulong RhCurrentOSThreadId();
585585

586+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
587+
[RuntimeImport(RuntimeLibrary, "RhGetDefaultStackSize")]
588+
internal static extern unsafe IntPtr RhGetDefaultStackSize();
589+
586590
[MethodImplAttribute(MethodImplOptions.InternalCall)]
587591
[RuntimeImport("*", "RhGetCurrentThunkContext")]
588592
internal static extern IntPtr GetCurrentInteropThunkContext();

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Unix.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,14 @@ private unsafe bool CreateThread(GCHandle<Thread> thisThreadHandle)
9494
// This also avoids OOM after creating the thread.
9595
_stopped = new ManualResetEvent(false);
9696

97-
if (!Interop.Sys.CreateThread((IntPtr)_startHelper!._maxStackSize, &ThreadEntryPoint, GCHandle<Thread>.ToIntPtr(thisThreadHandle)))
97+
nint stackSize = _startHelper!._maxStackSize;
98+
99+
if (stackSize <= 0)
100+
{
101+
stackSize = RuntimeImports.RhGetDefaultStackSize();
102+
}
103+
104+
if (!Interop.Sys.CreateThread(stackSize, &ThreadEntryPoint, GCHandle<Thread>.ToIntPtr(thisThreadHandle)))
98105
{
99106
return false;
100107
}

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.Windows.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,13 @@ private bool JoinInternal(int millisecondsTimeout)
176176
private unsafe bool CreateThread(GCHandle<Thread> thisThreadHandle)
177177
{
178178
const int AllocationGranularity = 0x10000; // 64 KiB
179-
180179
int stackSize = _startHelper._maxStackSize;
180+
181+
if (stackSize <= 0)
182+
{
183+
stackSize = (int)RuntimeImports.RhGetDefaultStackSize();
184+
}
185+
181186
if ((0 < stackSize) && (stackSize < AllocationGranularity))
182187
{
183188
// If StackSizeParamIsAReservation flag is set and the reserve size specified by CreateThread's

src/coreclr/vm/threads.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "comutilnative.h"
2626
#include "finalizerthread.h"
2727
#include "threadsuspend.h"
28+
#include "configuration.h"
2829

2930
#include "wrappers.h"
3031

@@ -2078,9 +2079,11 @@ void ParseDefaultStackSize(LPCWSTR valueStr)
20782079

20792080
SIZE_T GetDefaultStackSizeSetting()
20802081
{
2081-
static DWORD s_defaultStackSizeEnv = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DefaultStackSize);
2082+
static DWORD s_defaultStackSizeEnv = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Thread_DefaultStackSize);
2083+
static DWORD s_defaultStackSizeProp = Configuration::GetKnobDWORDValue(W("System.Threading.DefaultStackSize"), 0);
20822084

2083-
uint64_t value = s_defaultStackSizeEnv ? s_defaultStackSizeEnv : s_defaultStackSizeProperty;
2085+
uint64_t value = s_defaultStackSizeEnv ? s_defaultStackSizeEnv
2086+
: (s_defaultStackSizeProperty ? s_defaultStackSizeProperty : s_defaultStackSizeProp);
20842087

20852088
SIZE_T minStack = 0x10000; // 64K - Somewhat arbitrary minimum thread stack size
20862089
SIZE_T maxStack = 0x80000000; // 2G - Somewhat arbitrary maximum thread stack size

0 commit comments

Comments
 (0)