diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs index f8e3712b5c3ae..3ec662c40afbc 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs @@ -319,6 +319,8 @@ partial void ThreadNameChanged(string? value) [MethodImpl(MethodImplOptions.InternalCall)] internal static extern DeserializationTracker GetThreadDeserializationTracker(ref StackCrawlMark stackMark); + internal const bool IsThreadStartSupported = true; + /// Returns true if the thread has been started and is not dead. public extern bool IsAlive { diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs index f9c6a07f87309..dc8070ada491b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs @@ -372,7 +372,7 @@ internal static void ResetThreadPoolThread(Thread currentThread) [System.Diagnostics.Conditional("DEBUG")] internal static void CheckThreadPoolAndContextsAreDefault() { - Debug.Assert(Thread.CurrentThread.IsThreadPoolThread); + Debug.Assert(!Thread.IsThreadStartSupported || Thread.CurrentThread.IsThreadPoolThread); // there are no dedicated threadpool threads on runtimes where we can't start threads Debug.Assert(Thread.CurrentThread._executionContext == null, "ThreadPool thread not on Default ExecutionContext."); Debug.Assert(Thread.CurrentThread._synchronizationContext == null, "ThreadPool thread not on Default SynchronizationContext."); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs index dd7b77f71f941..0472f6436171a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs @@ -43,7 +43,7 @@ internal ThreadPoolTaskScheduler() protected internal override void QueueTask(Task task) { TaskCreationOptions options = task.Options; - if ((options & TaskCreationOptions.LongRunning) != 0) + if (Thread.IsThreadStartSupported && (options & TaskCreationOptions.LongRunning) != 0) { // Run LongRunning tasks on their own dedicated thread. Thread thread = new Thread(s_longRunningThreadWork); diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c index 11efa13d3e0e3..3b914a03fddfe 100644 --- a/src/mono/mono/mini/mini-wasm.c +++ b/src/mono/mono/mini/mini-wasm.c @@ -395,6 +395,9 @@ extern void mono_set_timeout (int t, int d); extern void mono_wasm_queue_tp_cb (void); G_END_DECLS +extern void mono_wasm_pump_threadpool (void); +void mono_background_exec (void); + #endif // HOST_WASM gpointer @@ -620,12 +623,21 @@ mono_wasm_queue_tp_cb (void) #endif } +void +mono_wasm_pump_threadpool (void) +{ +#ifdef HOST_WASM + mono_background_exec (); +#endif +} + void mono_arch_register_icall (void) { #ifdef ENABLE_NETCORE mono_add_internal_call_internal ("System.Threading.TimerQueue::SetTimeout", mono_wasm_set_timeout); mono_add_internal_call_internal ("System.Threading.ThreadPool::QueueCallback", mono_wasm_queue_tp_cb); + mono_add_internal_call_internal ("System.Threading.ThreadPool::PumpThreadPool", mono_wasm_pump_threadpool); #else mono_add_internal_call_internal ("System.Threading.WasmRuntime::SetTimeout", mono_wasm_set_timeout); #endif diff --git a/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj index 6c3acdd954b42..dac8da50c332a 100644 --- a/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -304,8 +304,12 @@ + + + + diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Browser.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Browser.Mono.cs new file mode 100644 index 0000000000000..f34909158eb0c --- /dev/null +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.Browser.Mono.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Threading +{ + public partial class Thread + { + internal const bool IsThreadStartSupported = false; + } +} diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.UnixOrWindows.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.UnixOrWindows.Mono.cs new file mode 100644 index 0000000000000..abd2a4425f4ee --- /dev/null +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/Thread.UnixOrWindows.Mono.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Threading +{ + public partial class Thread + { + internal const bool IsThreadStartSupported = true; + } +} diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Threading/ThreadPool.Browser.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/ThreadPool.Browser.Mono.cs index 4b6636f6e34a1..77946c205110b 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Threading/ThreadPool.Browser.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Threading/ThreadPool.Browser.Mono.cs @@ -107,9 +107,13 @@ private static RegisteredWaitHandle RegisterWaitForSingleObject( } [DynamicDependency("Callback")] + [DynamicDependency("PumpThreadPool")] [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern void QueueCallback(); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void PumpThreadPool(); // NOTE: this method is called via reflection by test code + private static void Callback() { _callbackQueued = false;