Skip to content

Commit ce4c725

Browse files
authored
Mono: use shared StartHelper object (#46896)
* Revert "Partial rollback of #46244 to workaround #46389 (#46390)" This reverts commit 43d0780. * [threads] Check for null longlived thread data This might happen on netcore if the managed Thread constructor throws an exception before calling InitInternal. In that case the finalizer may see a partially initialized object.
1 parent 725f29b commit ce4c725

File tree

3 files changed

+20
-178
lines changed

3 files changed

+20
-178
lines changed

src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ private void InitializeCulture()
9494
}
9595
}
9696

97-
#if !MONO // Workaround for #46389
9897
public Thread(ThreadStart start)
9998
{
10099
if (start == null)
@@ -237,7 +236,6 @@ private void SetCultureOnUnstartedThread(CultureInfo value, bool uiCulture)
237236
startHelper._culture = value;
238237
}
239238
}
240-
#endif // Workaround for #46389
241239

242240
partial void ThreadNameChanged(string? value);
243241

src/mono/mono/metadata/threads.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1940,8 +1940,11 @@ ves_icall_System_Threading_InternalThread_Thread_free_internal (MonoInternalThre
19401940
mono_threads_close_native_thread_handle (MONO_GPOINTER_TO_NATIVE_THREAD_HANDLE (this_obj->native_handle));
19411941
this_obj->native_handle = NULL;
19421942

1943-
/* Possibly free synch_cs, if the thread already detached also. */
1944-
dec_longlived_thread_data (this_obj->longlived);
1943+
/* might be null if the constructor threw an exception */
1944+
if (this_obj->longlived) {
1945+
/* Possibly free synch_cs, if the thread already detached also. */
1946+
dec_longlived_thread_data (this_obj->longlived);
1947+
}
19451948

19461949
mono_thread_name_cleanup (&this_obj->name);
19471950
}

src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs

Lines changed: 15 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,7 @@ public partial class Thread
7171
#pragma warning restore 169, 414, 649
7272

7373
private string? _name;
74-
private Delegate? m_start;
75-
private object? m_start_arg;
76-
private CultureInfo? culture, ui_culture;
74+
private StartHelper? _startHelper;
7775
internal ExecutionContext? _executionContext;
7876
internal SynchronizationContext? _synchronizationContext;
7977

@@ -175,90 +173,6 @@ public ThreadPriority Priority
175173

176174
public ThreadState ThreadState => GetState(this);
177175

178-
public Thread(ThreadStart start)
179-
: this()
180-
{
181-
if (start == null)
182-
{
183-
throw new ArgumentNullException(nameof(start));
184-
}
185-
186-
Create(start);
187-
}
188-
189-
public Thread(ThreadStart start, int maxStackSize)
190-
: this()
191-
{
192-
if (start == null)
193-
{
194-
throw new ArgumentNullException(nameof(start));
195-
}
196-
if (maxStackSize < 0)
197-
{
198-
throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum);
199-
}
200-
201-
Create(start, maxStackSize);
202-
}
203-
204-
public Thread(ParameterizedThreadStart start)
205-
: this()
206-
{
207-
if (start == null)
208-
{
209-
throw new ArgumentNullException(nameof(start));
210-
}
211-
212-
Create(start);
213-
}
214-
215-
public Thread(ParameterizedThreadStart start, int maxStackSize)
216-
: this()
217-
{
218-
if (start == null)
219-
{
220-
throw new ArgumentNullException(nameof(start));
221-
}
222-
if (maxStackSize < 0)
223-
{
224-
throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum);
225-
}
226-
227-
Create(start, maxStackSize);
228-
}
229-
230-
private void RequireCurrentThread()
231-
{
232-
if (this != CurrentThread)
233-
{
234-
throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread);
235-
}
236-
}
237-
238-
private void SetCultureOnUnstartedThread(CultureInfo value, bool uiCulture)
239-
{
240-
if (value == null)
241-
{
242-
throw new ArgumentNullException(nameof(value));
243-
}
244-
if ((ThreadState & ThreadState.Unstarted) == 0)
245-
{
246-
throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread);
247-
}
248-
if (uiCulture)
249-
ui_culture = value;
250-
else
251-
culture = value;
252-
}
253-
254-
private void Create(ThreadStart start) => SetStartHelper((Delegate)start, 0); // 0 will setup Thread with default stackSize
255-
256-
private void Create(ThreadStart start, int maxStackSize) => SetStartHelper((Delegate)start, maxStackSize);
257-
258-
private void Create(ParameterizedThreadStart start) => SetStartHelper((Delegate)start, 0);
259-
260-
private void Create(ParameterizedThreadStart start, int maxStackSize) => SetStartHelper((Delegate)start, maxStackSize);
261-
262176
public ApartmentState GetApartmentState() => ApartmentState.Unknown;
263177

264178
public void DisableComObjectEagerCleanup()
@@ -291,10 +205,12 @@ public bool Join(int millisecondsTimeout)
291205
return JoinInternal(this, millisecondsTimeout);
292206
}
293207

294-
private void SetStartHelper(Delegate start, int maxStackSize)
208+
private void Initialize()
295209
{
296-
m_start = start;
297-
stack_size = maxStackSize;
210+
InitInternal(this);
211+
212+
// TODO: This can go away once the mono/mono mirror is disabled
213+
stack_size = _startHelper!._maxStackSize;
298214
}
299215

300216
public static void SpinWait(int iterations)
@@ -316,103 +232,28 @@ public static void Sleep(int millisecondsTimeout)
316232

317233
internal static void UninterruptibleSleep0() => SleepInternal(0, false);
318234

319-
#if !TARGET_BROWSER
320-
internal const bool IsThreadStartSupported = true;
321-
322-
[UnsupportedOSPlatform("browser")]
323-
public void Start()
324-
{
325-
_executionContext = ExecutionContext.Capture();
326-
StartInternal(this);
327-
}
328-
329-
[UnsupportedOSPlatform("browser")]
330-
public void Start(object parameter)
331-
{
332-
if (m_start is ThreadStart)
333-
throw new InvalidOperationException(SR.InvalidOperation_ThreadWrongThreadStart);
334-
335-
m_start_arg = parameter;
336-
Start();
337-
}
338-
339-
[UnsupportedOSPlatform("browser")]
340-
internal void UnsafeStart()
341-
{
342-
StartInternal(this);
343-
}
344-
345-
[UnsupportedOSPlatform("browser")]
346-
internal void UnsafeStart(object parameter)
347-
{
348-
Debug.Assert(m_start is ThreadStart);
349-
350-
m_start_arg = parameter;
351-
UnsafeStart();
352-
}
353-
354235
// Called from the runtime
355236
internal void StartCallback()
356237
{
357-
ExecutionContext? context = _executionContext;
358-
_executionContext = null;
359-
if (context != null && !context.IsDefault)
360-
{
361-
ExecutionContext.RunInternal(context, s_threadStartContextCallback, this);
362-
}
363-
else
364-
{
365-
StartCallbackWorker();
366-
}
367-
}
368-
369-
private static readonly ContextCallback s_threadStartContextCallback = new ContextCallback(StartCallback_Context);
370-
371-
private static void StartCallback_Context(object? state)
372-
{
373-
Debug.Assert(state is Thread);
374-
((Thread)state).StartCallbackWorker();
375-
}
376-
377-
[MethodImpl(MethodImplOptions.AggressiveInlining)] // otherwise an unnecessary long-lived stack frame in many threads
378-
private void StartCallbackWorker()
379-
{
380-
if (culture != null)
381-
{
382-
CultureInfo.CurrentCulture = culture;
383-
culture = null;
384-
}
238+
StartHelper? startHelper = _startHelper;
239+
Debug.Assert(startHelper != null);
240+
_startHelper = null;
385241

386-
if (ui_culture != null)
387-
{
388-
CultureInfo.CurrentUICulture = ui_culture;
389-
ui_culture = null;
390-
}
391-
392-
if (m_start is ThreadStart del)
393-
{
394-
m_start = null;
395-
del();
396-
}
397-
else
398-
{
399-
Debug.Assert(m_start is ParameterizedThreadStart);
400-
var pdel = (ParameterizedThreadStart)m_start!;
401-
object? arg = m_start_arg;
402-
m_start = null;
403-
m_start_arg = null;
404-
pdel(arg);
405-
}
242+
startHelper.Run();
406243
}
407244

408245
// Called from the runtime
409246
internal static void ThrowThreadStartException(Exception ex) => throw new ThreadStartException(ex);
410247

248+
private void StartCore()
249+
{
250+
StartInternal(this);
251+
}
252+
411253
[DynamicDependency(nameof(StartCallback))]
412254
[DynamicDependency(nameof(ThrowThreadStartException))]
413255
[MethodImplAttribute(MethodImplOptions.InternalCall)]
414256
private static extern void StartInternal(Thread runtime_thread);
415-
#endif
416257

417258
partial void ThreadNameChanged(string? value)
418259
{

0 commit comments

Comments
 (0)