From b049c6a51f4db78f4b72808a7c8eb85fdf9cb879 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 16 Jan 2024 23:22:13 +0100 Subject: [PATCH 01/16] [wasm][mt] throw from blocking wait on JS interop threads Also add test --- .../src/System.Net.Http.csproj | 22 +++++++++++++------ .../src/System.Net.WebSockets.Client.csproj | 14 ++++++++---- .../ref/System.Private.CoreLib.ExtraApis.cs | 8 +++++++ .../ref/System.Private.CoreLib.ExtraApis.txt | 1 + .../System.Private.CoreLib.Shared.projitems | 1 + .../JavaScript/JSProxyContextBase.cs | 14 ++++++++++++ ....Runtime.InteropServices.JavaScript.csproj | 16 ++++---------- .../JavaScript/JSProxyContext.cs | 8 ++++--- ...me.InteropServices.JavaScript.Tests.csproj | 7 +++++- .../JavaScript/WebWorkerTest.cs | 19 ++++++++++++++++ .../JavaScript/WebWorkerTestHelper.cs | 16 ++++++++++++++ .../src/System/Threading/Monitor.Mono.cs | 6 +++++ 12 files changed, 105 insertions(+), 27 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index 54991bd5a4d33..109f4aba860dc 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -446,37 +446,45 @@ - - - - - - - + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj b/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj index 294a9bceb4f12..f017401d6aa99 100644 --- a/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj +++ b/src/libraries/System.Net.WebSockets.Client/src/System.Net.WebSockets.Client.csproj @@ -38,7 +38,6 @@ - @@ -46,15 +45,22 @@ - - - + + + + + + + + + + diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs index 84e99da5aa050..58cc14c108f9a 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs @@ -37,3 +37,11 @@ public static partial class Debug public static System.Diagnostics.DebugProvider SetProvider(System.Diagnostics.DebugProvider provider) { throw null; } } } + +namespace System.Runtime.InteropServices.JavaScript +{ + public class JSProxyContextBase { + [ThreadStatic] + public static JSProxyContextBase? CurrentThreadContextBase; + } +} diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt index 0babd819e25d0..f84a54fdb65b8 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt @@ -5,3 +5,4 @@ T:System.Runtime.Serialization.DeserializationToken M:System.Runtime.Serialization.SerializationInfo.StartDeserialization T:System.Diagnostics.DebugProvider M:System.Diagnostics.Debug.SetProvider(System.Diagnostics.DebugProvider) +T:System.Runtime.InteropServices.JavaScript.JSProxyContextBase diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index e166a7c85a09d..b7c7b56c2fd2e 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -972,6 +972,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs new file mode 100644 index 0000000000000..6b120661eec59 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.Versioning; +using System.Threading; + +namespace System.Runtime.InteropServices.JavaScript +{ + public class JSProxyContextBase + { + [ThreadStatic] + public static JSProxyContextBase? CurrentThreadContextBase; + } +} diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj index 1b8664dc43591..59e499dc29e90 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System.Runtime.InteropServices.JavaScript.csproj @@ -90,18 +90,10 @@ - - - - - - - - - - - - + + + + diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs index dcb99ed1d3d4e..873b2e50a9982 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs @@ -8,7 +8,7 @@ namespace System.Runtime.InteropServices.JavaScript { - internal sealed class JSProxyContext : IDisposable + internal sealed class JSProxyContext : JSProxyContextBase, IDisposable { private bool _isDisposed; @@ -182,8 +182,10 @@ public static JSProxyContext? ExecutionContext set => _currentThreadContext.Value = value; } - [ThreadStatic] - public static JSProxyContext? CurrentThreadContext; + public static JSProxyContext? CurrentThreadContext { + get => CurrentThreadContextBase as JSProxyContext; + set => CurrentThreadContextBase = value; + } // This is context to dispatch into. In order of preference // - captured context by arguments of current/pending JSImport call diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj index ab0e7ac77251e..f4d8bfba695a3 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj @@ -30,6 +30,12 @@ + + + + + + @@ -37,6 +43,5 @@ - diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTest.cs index cd8e24d6343e7..ad142e225feb2 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTest.cs @@ -419,6 +419,25 @@ await executor.Execute(async () => }, cts.Token); } + [Theory, MemberData(nameof(GetTargetThreads))] + public async Task WaitAssertsOnJSInteropThreads(Executor executor) + { + var cts = new CancellationTokenSource(TimeoutMilliseconds); + await executor.Execute(Task () => + { + Exception? exception = null; + try { + Task.Delay(10, cts.Token).Wait(); + } catch (Exception ex) { + exception = ex; + } + + executor.AssertBlockingWait(exception); + + return Task.CompletedTask; + }, cts.Token); + } + [Theory, MemberData(nameof(GetTargetThreads))] public async Task ManagedYield(Executor executor) { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTestHelper.cs index 91fa40695e1be..eea381a866a52 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTestHelper.cs @@ -230,6 +230,22 @@ public void AssertAwaitCapturedContext() } } + public void AssertBlockingWait(Exception? exception) + { + switch (Type) + { + case ExecutorType.Main: + case ExecutorType.JSWebWorker: + Assert.NotNull(exception); + Assert.IsType(exception); + break; + case ExecutorType.NewThread: + case ExecutorType.ThreadPool: + Assert.Null(exception); + break; + } + } + public void AssertInteropThread() { switch (Type) diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Monitor.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Monitor.Mono.cs index 07aea6c347929..bae3ebc666f90 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Monitor.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Monitor.Mono.cs @@ -77,6 +77,12 @@ public static bool IsEntered(object obj) public static bool Wait(object obj, int millisecondsTimeout) { ArgumentNullException.ThrowIfNull(obj); +#if FEATURE_WASM_THREADS + if (System.Runtime.InteropServices.JavaScript.JSProxyContextBase.CurrentThreadContextBase != null) + { + throw new PlatformNotSupportedException("blocking Wait is not supported on the JS interop thread."); + } +#endif return ObjWait(millisecondsTimeout, obj); } From 150a1779837ecf95c3ca542bb7ec8fc8d1a9d905 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Wed, 17 Jan 2024 17:05:46 +0100 Subject: [PATCH 02/16] Fix typo --- .../src/System.Private.CoreLib.Shared.projitems | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index b7c7b56c2fd2e..e8e5d3278d6d5 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -972,7 +972,7 @@ - From a88e4938b57688959b9fe5fabb9122f3a51fd39b Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Wed, 17 Jan 2024 19:38:58 +0100 Subject: [PATCH 03/16] Add JSProxyContextBase conditionally --- .../ref/System.Private.CoreLib.ExtraApis.cs | 2 ++ .../Runtime/InteropServices/JavaScript/JSProxyContextBase.cs | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs index 58cc14c108f9a..97989bd498946 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs @@ -38,6 +38,7 @@ public static partial class Debug } } +#if FEATURE_WASM_THREADS namespace System.Runtime.InteropServices.JavaScript { public class JSProxyContextBase { @@ -45,3 +46,4 @@ public class JSProxyContextBase { public static JSProxyContextBase? CurrentThreadContextBase; } } +#endif diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs index 6b120661eec59..d389a44cd11a5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if FEATURE_WASM_THREADS + using System.Runtime.Versioning; using System.Threading; @@ -12,3 +14,4 @@ public class JSProxyContextBase public static JSProxyContextBase? CurrentThreadContextBase; } } +#endif From 61b797cae8e62c73f49200e39ca0fa8da90d453d Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Wed, 17 Jan 2024 19:51:38 +0100 Subject: [PATCH 04/16] Fix non-mt browser build --- .../Runtime/InteropServices/JavaScript/JSProxyContext.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs index 873b2e50a9982..8bb3ee7aa2dcb 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs @@ -8,7 +8,11 @@ namespace System.Runtime.InteropServices.JavaScript { - internal sealed class JSProxyContext : JSProxyContextBase, IDisposable + internal sealed class JSProxyContext : +#if FEATURE_WASM_THREADS + JSProxyContextBase, +#endif + IDisposable { private bool _isDisposed; From 1ed5faa2e16ced34ebfa0aa244191161994157b4 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Wed, 17 Jan 2024 20:46:30 +0100 Subject: [PATCH 05/16] Fix tests build --- .../System.Runtime.InteropServices.JavaScript.Tests.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj index f4d8bfba695a3..3abf51a0c2a7c 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj @@ -31,6 +31,7 @@ + From dbe7c4cca762488b8baf0f0232564c6be282c315 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Fri, 19 Jan 2024 15:55:21 +0100 Subject: [PATCH 06/16] Do not add JS interop project reference To not mix intree references and source project --- .../browser/debugger/tests/debugger-test/debugger-test.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/mono/browser/debugger/tests/debugger-test/debugger-test.csproj b/src/mono/browser/debugger/tests/debugger-test/debugger-test.csproj index f762d30bc5b80..be87407a47183 100644 --- a/src/mono/browser/debugger/tests/debugger-test/debugger-test.csproj +++ b/src/mono/browser/debugger/tests/debugger-test/debugger-test.csproj @@ -119,9 +119,5 @@ - - - - From eb995fb8334bcf8cffb0ef71a3ec6e7f18bbc104 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Fri, 19 Jan 2024 15:57:46 +0100 Subject: [PATCH 07/16] Add new flag to Monitor This replaces the previous context base and makes it possible to disable throw for blocking calls in JS interop --- .../ref/System.Private.CoreLib.ExtraApis.cs | 7 ++++--- .../ref/System.Private.CoreLib.ExtraApis.txt | 2 +- .../src/System.Private.CoreLib.Shared.projitems | 1 - .../JavaScript/Interop/JavaScriptExports.cs | 3 +++ .../InteropServices/JavaScript/JSProxyContext.cs | 12 +++--------- .../JavaScript/JSSynchronizationContext.cs | 1 + .../src/CompatibilitySuppressions.Threading.xml | 4 ++++ .../src/System/Threading/Monitor.Mono.cs | 9 +++++++-- 8 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs index 97989bd498946..dedbdd6e27692 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs @@ -39,11 +39,12 @@ public static partial class Debug } #if FEATURE_WASM_THREADS -namespace System.Runtime.InteropServices.JavaScript +namespace System.Threading { - public class JSProxyContextBase { + public partial class Monitor + { [ThreadStatic] - public static JSProxyContextBase? CurrentThreadContextBase; + public static bool ThrowOnBlockingWaitOnJSInteropThread; } } #endif diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt index f84a54fdb65b8..b09aabbd2decc 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt @@ -5,4 +5,4 @@ T:System.Runtime.Serialization.DeserializationToken M:System.Runtime.Serialization.SerializationInfo.StartDeserialization T:System.Diagnostics.DebugProvider M:System.Diagnostics.Debug.SetProvider(System.Diagnostics.DebugProvider) -T:System.Runtime.InteropServices.JavaScript.JSProxyContextBase +F:System.Threading.Monitor.ThrowOnBlockingWaitOnJSInteropThread diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index e8e5d3278d6d5..e166a7c85a09d 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -972,7 +972,6 @@ - diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs index 47e999d704786..687707631fb88 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs @@ -220,7 +220,10 @@ public static void CompleteTask(JSMarshalerArgument* arguments_buffer) { if (holder.Callback == null) { + var threadFlag = Monitor.ThrowOnBlockingWaitOnJSInteropThread; + Monitor.ThrowOnBlockingWaitOnJSInteropThread = false; holder.CallbackReady = new ManualResetEventSlim(false); + Monitor.ThrowOnBlockingWaitOnJSInteropThread = threadFlag; } } if (holder.CallbackReady != null) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs index 8bb3ee7aa2dcb..dcb99ed1d3d4e 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSProxyContext.cs @@ -8,11 +8,7 @@ namespace System.Runtime.InteropServices.JavaScript { - internal sealed class JSProxyContext : -#if FEATURE_WASM_THREADS - JSProxyContextBase, -#endif - IDisposable + internal sealed class JSProxyContext : IDisposable { private bool _isDisposed; @@ -186,10 +182,8 @@ public static JSProxyContext? ExecutionContext set => _currentThreadContext.Value = value; } - public static JSProxyContext? CurrentThreadContext { - get => CurrentThreadContextBase as JSProxyContext; - set => CurrentThreadContextBase = value; - } + [ThreadStatic] + public static JSProxyContext? CurrentThreadContext; // This is context to dispatch into. In order of preference // - captured context by arguments of current/pending JSImport call diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSSynchronizationContext.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSSynchronizationContext.cs index f7fbb7fb5a79c..39a6cc78b7c04 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSSynchronizationContext.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSSynchronizationContext.cs @@ -49,6 +49,7 @@ public static JSSynchronizationContext InstallWebWorkerInterop(bool isMainThread var ctx = new JSSynchronizationContext(isMainThread, cancellationToken); ctx.previousSynchronizationContext = SynchronizationContext.Current; SynchronizationContext.SetSynchronizationContext(ctx); + Monitor.ThrowOnBlockingWaitOnJSInteropThread = true; var proxyContext = ctx.ProxyContext; JSProxyContext.CurrentThreadContext = proxyContext; diff --git a/src/libraries/System.Threading/src/CompatibilitySuppressions.Threading.xml b/src/libraries/System.Threading/src/CompatibilitySuppressions.Threading.xml index 9c9a072a248df..33789a1982062 100644 --- a/src/libraries/System.Threading/src/CompatibilitySuppressions.Threading.xml +++ b/src/libraries/System.Threading/src/CompatibilitySuppressions.Threading.xml @@ -100,4 +100,8 @@ CP0014 M:System.Threading.Monitor.Wait(System.Object):[T:System.Runtime.Versioning.UnsupportedOSPlatformAttribute] + + CP0002 + F:System.Threading.Monitor.ThrowOnBlockingWaitOnJSInteropThread + diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Monitor.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Monitor.Mono.cs index bae3ebc666f90..78038d8769e4c 100644 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Monitor.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Threading/Monitor.Mono.cs @@ -9,6 +9,11 @@ namespace System.Threading { public static partial class Monitor { +#if FEATURE_WASM_THREADS + [ThreadStatic] + public static bool ThrowOnBlockingWaitOnJSInteropThread; +#endif + [Intrinsic] [MethodImplAttribute(MethodImplOptions.InternalCall)] // Interpreter is missing this intrinsic public static void Enter(object obj) => Enter(obj); @@ -78,9 +83,9 @@ public static bool Wait(object obj, int millisecondsTimeout) { ArgumentNullException.ThrowIfNull(obj); #if FEATURE_WASM_THREADS - if (System.Runtime.InteropServices.JavaScript.JSProxyContextBase.CurrentThreadContextBase != null) + if (ThrowOnBlockingWaitOnJSInteropThread) { - throw new PlatformNotSupportedException("blocking Wait is not supported on the JS interop thread."); + throw new PlatformNotSupportedException("blocking Wait is not supported on the JS interop threads."); } #endif return ObjWait(millisecondsTimeout, obj); From 4009ae3bbc1f53f8919188c8743d660d24e140f7 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Fri, 19 Jan 2024 16:44:44 +0100 Subject: [PATCH 08/16] Remove old file --- .../JavaScript/JSProxyContextBase.cs | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs deleted file mode 100644 index d389a44cd11a5..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/JavaScript/JSProxyContextBase.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#if FEATURE_WASM_THREADS - -using System.Runtime.Versioning; -using System.Threading; - -namespace System.Runtime.InteropServices.JavaScript -{ - public class JSProxyContextBase - { - [ThreadStatic] - public static JSProxyContextBase? CurrentThreadContextBase; - } -} -#endif From dd82372263932f4d860ba811ae3f41d773ca4914 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Fri, 19 Jan 2024 16:51:02 +0100 Subject: [PATCH 09/16] Changes from unsaved file --- .../InteropServices/JavaScript/Interop/JavaScriptExports.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs index 687707631fb88..aa71fb50f6c69 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs @@ -220,17 +220,17 @@ public static void CompleteTask(JSMarshalerArgument* arguments_buffer) { if (holder.Callback == null) { - var threadFlag = Monitor.ThrowOnBlockingWaitOnJSInteropThread; - Monitor.ThrowOnBlockingWaitOnJSInteropThread = false; holder.CallbackReady = new ManualResetEventSlim(false); - Monitor.ThrowOnBlockingWaitOnJSInteropThread = threadFlag; } } if (holder.CallbackReady != null) { + var threadFlag = Monitor.ThrowOnBlockingWaitOnJSInteropThread; + Monitor.ThrowOnBlockingWaitOnJSInteropThread = false; #pragma warning disable CA1416 // Validate platform compatibility holder.CallbackReady?.Wait(); #pragma warning restore CA1416 // Validate platform compatibility + Monitor.ThrowOnBlockingWaitOnJSInteropThread = threadFlag; } #endif var callback = holder.Callback!; From 5c955148739f0069a7ed1e3ac28dda79e4998208 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Fri, 19 Jan 2024 17:02:40 +0100 Subject: [PATCH 10/16] Wrap another blocking wait in JS interop --- .../InteropServices/JavaScript/JSSynchronizationContext.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSSynchronizationContext.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSSynchronizationContext.cs index 39a6cc78b7c04..e6623cce82636 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSSynchronizationContext.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSSynchronizationContext.cs @@ -216,7 +216,10 @@ public override void Send(SendOrPostCallback d, object? state) Environment.FailFast($"JSSynchronizationContext.Send failed, ManagedThreadId: {Environment.CurrentManagedThreadId}. {Environment.NewLine} {Environment.StackTrace}"); } + var threadFlag = Monitor.ThrowOnBlockingWaitOnJSInteropThread; + Monitor.ThrowOnBlockingWaitOnJSInteropThread = false; signal.Wait(); + Monitor.ThrowOnBlockingWaitOnJSInteropThread = threadFlag; if (_isCancellationRequested) { From e1af48a01746039f5a17a04bbef67f64aac67069 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 23 Jan 2024 17:12:44 +0100 Subject: [PATCH 11/16] Do not reference src/System.Runtime.InteropServices.JavaScript.csproj --- src/tests/FunctionalTests/WebAssembly/Directory.Build.props | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/tests/FunctionalTests/WebAssembly/Directory.Build.props b/src/tests/FunctionalTests/WebAssembly/Directory.Build.props index 3f19205474672..e0eb44a860c46 100644 --- a/src/tests/FunctionalTests/WebAssembly/Directory.Build.props +++ b/src/tests/FunctionalTests/WebAssembly/Directory.Build.props @@ -12,10 +12,6 @@ 42 - - - - From 9ec32c1a63a86cce39d5aeeb8e11ead2aeb3b62c Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 29 Jan 2024 17:41:03 +0100 Subject: [PATCH 12/16] Disable failing test with blocking Wait --- .../debugger/DebuggerTestSuite/DebuggerTestSuite.csproj | 3 +++ src/mono/browser/debugger/DebuggerTestSuite/SteppingTests.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj b/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj index cb58cc51407c5..6137ac51d98c2 100644 --- a/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj +++ b/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj @@ -7,6 +7,9 @@ chrome $(DefineConstants);RUN_IN_CHROME $(DefineConstants);RELEASE_RUNTIME + $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) + true + $(DefineConstants);FEATURE_WASM_THREADS windows <_ProvisionBrowser Condition="'$(ContinuousIntegrationBuild)' == 'true' or Exists('/.dockerenv')">true diff --git a/src/mono/browser/debugger/DebuggerTestSuite/SteppingTests.cs b/src/mono/browser/debugger/DebuggerTestSuite/SteppingTests.cs index b97122033f96b..754539591f56d 100644 --- a/src/mono/browser/debugger/DebuggerTestSuite/SteppingTests.cs +++ b/src/mono/browser/debugger/DebuggerTestSuite/SteppingTests.cs @@ -957,6 +957,9 @@ await EvaluateAndCheck( } [Fact] +#if FEATURE_WASM_THREADS + [ActiveIssue("https://github.com/dotnet/runtime/issues/97652")] +#endif public async Task StepOverWithMoreThanOneCommandInSameLineAsync() { await SetBreakpoint("dotnet://debugger-test.dll/debugger-test.cs", 710, 0); From 4f74e02cbff18bb930f8a6352e1efe37ea6c23a1 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 30 Jan 2024 13:31:36 +0100 Subject: [PATCH 13/16] Update the test condition --- .../debugger/DebuggerTestSuite/DebuggerTestSuite.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj b/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj index 19f5c3ea112c9..374ac2c0faf6f 100644 --- a/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj +++ b/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj @@ -7,8 +7,7 @@ chrome $(DefineConstants);RUN_IN_CHROME $(DefineConstants);RELEASE_RUNTIME - $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) - true + true $(DefineConstants);FEATURE_WASM_THREADS windows From 00e6b4b6c99a12b7a2d8940ad268ac4ec2217135 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 30 Jan 2024 13:37:45 +0100 Subject: [PATCH 14/16] Add missing line after conflict resolution --- .../System.Runtime.InteropServices.JavaScript.Tests.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj index 514d7480108d1..e49a2bb455a50 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System.Runtime.InteropServices.JavaScript.Tests.csproj @@ -52,5 +52,6 @@ + From 1dd3af25383fb93c176a95ffa8f23b556f78918f Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 30 Jan 2024 13:39:50 +0100 Subject: [PATCH 15/16] Fix build --- .../System/Runtime/InteropServices/JavaScript/WebWorkerTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTest.cs index 1f4a6021f3fb9..607560162b9e3 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/WebWorkerTest.cs @@ -414,7 +414,7 @@ await executor.Execute(async () => [Theory, MemberData(nameof(GetTargetThreads))] public async Task WaitAssertsOnJSInteropThreads(Executor executor) { - var cts = new CancellationTokenSource(TimeoutMilliseconds); + var cts = CreateTestCaseTimeoutSource(); await executor.Execute(Task () => { Exception? exception = null; From 7f067df792f953ec87e351841f30016165739592 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 30 Jan 2024 17:16:27 +0100 Subject: [PATCH 16/16] Update the active issue and don't use define --- .../debugger/DebuggerTestSuite/DebuggerTestSuite.csproj | 2 -- src/mono/browser/debugger/DebuggerTestSuite/SteppingTests.cs | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj b/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj index 374ac2c0faf6f..87cfb17bbc047 100644 --- a/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj +++ b/src/mono/browser/debugger/DebuggerTestSuite/DebuggerTestSuite.csproj @@ -7,8 +7,6 @@ chrome $(DefineConstants);RUN_IN_CHROME $(DefineConstants);RELEASE_RUNTIME - true - $(DefineConstants);FEATURE_WASM_THREADS windows <_ProvisionBrowser Condition="'$(ContinuousIntegrationBuild)' == 'true' or Exists('/.dockerenv')">true diff --git a/src/mono/browser/debugger/DebuggerTestSuite/SteppingTests.cs b/src/mono/browser/debugger/DebuggerTestSuite/SteppingTests.cs index 754539591f56d..0074c536db81a 100644 --- a/src/mono/browser/debugger/DebuggerTestSuite/SteppingTests.cs +++ b/src/mono/browser/debugger/DebuggerTestSuite/SteppingTests.cs @@ -957,9 +957,7 @@ await EvaluateAndCheck( } [Fact] -#if FEATURE_WASM_THREADS - [ActiveIssue("https://github.com/dotnet/runtime/issues/97652")] -#endif + [ActiveIssue("https://github.com/dotnet/runtime/issues/97652", typeof(DebuggerTests), nameof(DebuggerTests.WasmMultiThreaded))] public async Task StepOverWithMoreThanOneCommandInSameLineAsync() { await SetBreakpoint("dotnet://debugger-test.dll/debugger-test.cs", 710, 0);