From 62bf3da88f0082f182b508685a1bf6c47f685187 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 24 Dec 2020 10:11:54 -0800 Subject: [PATCH 1/2] Partial rollback of #46244 to workaround #46389 --- .../src/System/Threading/Thread.cs | 2 + .../src/System/Threading/Thread.Mono.cs | 192 ++++++++++++++++-- 2 files changed, 179 insertions(+), 15 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs index 96048ecdf4837b..113dee97d0c660 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs @@ -94,6 +94,7 @@ private void InitializeCulture() } } +#if !MONO // Workaround for #46389 public Thread(ThreadStart start) { if (start == null) @@ -236,6 +237,7 @@ private void SetCultureOnUnstartedThread(CultureInfo value, bool uiCulture) startHelper._culture = value; } } +#endif // Workaround for #46389 partial void ThreadNameChanged(string? value); diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index 0e469831b75e72..f0f02176a587e0 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -74,7 +74,9 @@ keep as an object to avoid triggering its class constructor when not needed */ #pragma warning restore 169, 414, 649 private string? _name; - private StartHelper? _startHelper; + private Delegate? m_start; + private object? m_start_arg; + private CultureInfo? culture, ui_culture; internal ExecutionContext? _executionContext; internal SynchronizationContext? _synchronizationContext; @@ -176,6 +178,90 @@ public ThreadPriority Priority public ThreadState ThreadState => GetState(this); + public Thread(ThreadStart start) + : this() + { + if (start == null) + { + throw new ArgumentNullException(nameof(start)); + } + + Create(start); + } + + public Thread(ThreadStart start, int maxStackSize) + : this() + { + if (start == null) + { + throw new ArgumentNullException(nameof(start)); + } + if (maxStackSize < 0) + { + throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum); + } + + Create(start, maxStackSize); + } + + public Thread(ParameterizedThreadStart start) + : this() + { + if (start == null) + { + throw new ArgumentNullException(nameof(start)); + } + + Create(start); + } + + public Thread(ParameterizedThreadStart start, int maxStackSize) + : this() + { + if (start == null) + { + throw new ArgumentNullException(nameof(start)); + } + if (maxStackSize < 0) + { + throw new ArgumentOutOfRangeException(nameof(maxStackSize), SR.ArgumentOutOfRange_NeedNonNegNum); + } + + Create(start, maxStackSize); + } + + private void RequireCurrentThread() + { + if (this != CurrentThread) + { + throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread); + } + } + + private void SetCultureOnUnstartedThread(CultureInfo value, bool uiCulture) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + if ((ThreadState & ThreadState.Unstarted) == 0) + { + throw new InvalidOperationException(SR.Thread_Operation_RequiresCurrentThread); + } + if (uiCulture) + ui_culture = value; + else + culture = value; + } + + private void Create(ThreadStart start) => SetStartHelper((Delegate)start, 0); // 0 will setup Thread with default stackSize + + private void Create(ThreadStart start, int maxStackSize) => SetStartHelper((Delegate)start, maxStackSize); + + private void Create(ParameterizedThreadStart start) => SetStartHelper((Delegate)start, 0); + + private void Create(ParameterizedThreadStart start, int maxStackSize) => SetStartHelper((Delegate)start, maxStackSize); + public ApartmentState GetApartmentState() => ApartmentState.Unknown; public void DisableComObjectEagerCleanup() @@ -208,12 +294,10 @@ public bool Join(int millisecondsTimeout) return JoinInternal(this, millisecondsTimeout); } - private void Initialize() + private void SetStartHelper(Delegate start, int maxStackSize) { - InitInternal(this); - - // TODO: This can go away once the mono/mono mirror is disabled - stack_size = _startHelper!._maxStackSize; + m_start = start; + stack_size = maxStackSize; } public static void SpinWait(int iterations) @@ -235,28 +319,103 @@ public static void Sleep(int millisecondsTimeout) internal static void UninterruptibleSleep0() => SleepInternal(0, false); - // Called from the runtime - internal void StartCallback() +#if !TARGET_BROWSER + internal const bool IsThreadStartSupported = true; + + [UnsupportedOSPlatform("browser")] + public void Start() + { + _executionContext = ExecutionContext.Capture(); + StartInternal(this); + } + + [UnsupportedOSPlatform("browser")] + public void Start(object parameter) + { + if (m_start is ThreadStart) + throw new InvalidOperationException(SR.InvalidOperation_ThreadWrongThreadStart); + + m_start_arg = parameter; + Start(); + } + + [UnsupportedOSPlatform("browser")] + internal void UnsafeStart() + { + StartInternal(this); + } + + [UnsupportedOSPlatform("browser")] + internal void UnsafeStart(object parameter) { - StartHelper? startHelper = _startHelper; - Debug.Assert(startHelper != null); - _startHelper = null; + Debug.Assert(m_start is ThreadStart); - startHelper.Run(); + m_start_arg = parameter; + UnsafeStart(); } // Called from the runtime - internal static void ThrowThreadStartException(Exception ex) => throw new ThreadStartException(ex); + internal void StartCallback() + { + ExecutionContext? context = _executionContext; + _executionContext = null; + if (context != null && !context.IsDefault) + { + ExecutionContext.RunInternal(context, s_threadStartContextCallback, this); + } + else + { + StartCallbackWorker(); + } + } + + private static readonly ContextCallback s_threadStartContextCallback = new ContextCallback(StartCallback_Context); - private void StartCore() + private static void StartCallback_Context(object? state) { - StartInternal(this); + Debug.Assert(state is Thread); + ((Thread)state).StartCallbackWorker(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] // otherwise an unnecessary long-lived stack frame in many threads + private void StartCallbackWorker() + { + if (culture != null) + { + CultureInfo.CurrentCulture = culture; + culture = null; + } + + if (ui_culture != null) + { + CultureInfo.CurrentUICulture = ui_culture; + ui_culture = null; + } + + if (m_start is ThreadStart del) + { + m_start = null; + del(); + } + else + { + Debug.Assert(m_start is ParameterizedThreadStart); + var pdel = (ParameterizedThreadStart)m_start!; + object? arg = m_start_arg; + m_start = null; + m_start_arg = null; + pdel(arg); + } + } + + // Called from the runtime + internal static void ThrowThreadStartException(Exception ex) => throw new ThreadStartException(ex); + [DynamicDependency(nameof(StartCallback))] [DynamicDependency(nameof(ThrowThreadStartException))] [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern void StartInternal(Thread runtime_thread); +#endif partial void ThreadNameChanged(string? value) { @@ -344,6 +503,9 @@ private static void SpinWait_nop() { } + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern Thread CreateInternal(); + [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern bool JoinInternal(Thread thread, int millisecondsTimeout); From aac80becf6f6b9f57cb5fdafbbe53e8266c67244 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 24 Dec 2020 18:35:36 -0800 Subject: [PATCH 2/2] Delete unnecessary CreateInternal --- .../System.Private.CoreLib/src/System/Threading/Thread.Mono.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs index f0f02176a587e0..24662e2f38c5f3 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Mono.cs @@ -503,9 +503,6 @@ private static void SpinWait_nop() { } - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern Thread CreateInternal(); - [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern bool JoinInternal(Thread thread, int millisecondsTimeout);