From 7b78063fd2ae98228679f9b5d6f7ba210295650b Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Mon, 12 Jun 2023 21:48:09 +0200 Subject: [PATCH] wip --- .../src/System/Threading/Tasks/Task.cs | 12 ++++++++++++ .../JavaScript/Interop/JavaScriptExports.cs | 2 +- .../JavaScript/JSHostImplementation.cs | 17 ++++++++++++++++- .../InteropServices/JavaScript/WebWorker.cs | 6 +++--- .../wasm/browser-threads-minimal/Program.cs | 2 +- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 22621aa85e26b7..f3e93f4095fb02 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -136,6 +136,10 @@ public class Task : IAsyncResult, IDisposable private int StateFlagsForDebugger => m_stateFlags; // Private property used by a debugger to access this Task's state flags private TaskStateFlags StateFlags => (TaskStateFlags)(m_stateFlags & ~(int)TaskStateFlags.OptionsMask); // Private property used to help with debugging +#if FEATURE_WASM_THREADS + private static Type? s_jsSynchronizationContextType; +#endif + [Flags] internal enum TaskStateFlags { @@ -2515,6 +2519,14 @@ internal void SetContinuationForAwait( goto HaveTaskContinuation; } } +#if FEATURE_WASM_THREADS + // when JSSynchronizationContext is installed, we use it regardless of continueOnCapturedContext + else if (SynchronizationContext.Current is SynchronizationContext syncCtx && syncCtx.GetType() == s_jsSynchronizationContextType) + { + tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, continuationAction, flowExecutionContext); + goto HaveTaskContinuation; + } +#endif if (flowExecutionContext) { 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 9a0c75d78aeacd..6b4b2aba3d5126 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 @@ -225,7 +225,7 @@ public static void InstallSynchronizationContext (JSMarshalerArgument* arguments ref JSMarshalerArgument arg_exc = ref arguments_buffer[0]; // initialized by caller in alloc_stack_frame() try { - JSHostImplementation.InstallWebWorkerInterop(true); + JSHostImplementation.InstallWebWorkerInterop(true, true); } catch (Exception ex) { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs index e844a5d6ac0df9..372adb1649cdf6 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/JSHostImplementation.cs @@ -199,8 +199,12 @@ public static JSObject CreateCSOwnedProxy(nint jsHandle) } #if FEATURE_WASM_THREADS - public static void InstallWebWorkerInterop(bool installJSSynchronizationContext) + public static void InstallWebWorkerInterop(bool installJSSynchronizationContext, bool isMainThread) { + if (isMainThread) + { + SetJSSynchronizationContextType(); + } Interop.Runtime.InstallWebWorkerInterop(installJSSynchronizationContext); if (installJSSynchronizationContext) { @@ -236,6 +240,7 @@ public static void UninstallWebWorkerInterop() private static FieldInfo? thread_id_Field; private static FieldInfo? external_eventloop_Field; + private static FieldInfo? task_s_jsSynchronizationContextType_Field; // FIXME: after https://github.com/dotnet/runtime/issues/86040 replace with // [UnsafeAccessor(UnsafeAccessorKind.Field, Name="external_eventloop")] @@ -261,6 +266,16 @@ public static IntPtr GetNativeThreadId() return (int)(long)thread_id_Field.GetValue(Thread.CurrentThread)!; } + [DynamicDependency(DynamicallyAccessedMemberTypes.NonPublicFields, "System.Threading.Tasks.Task", "System.Private.CoreLib")] + public static void SetJSSynchronizationContextType() + { + if (task_s_jsSynchronizationContextType_Field == null) + { + task_s_jsSynchronizationContextType_Field = typeof(Task).GetField("s_jsSynchronizationContextType", BindingFlags.NonPublic | BindingFlags.Static)!; + } + task_s_jsSynchronizationContextType_Field.SetValue(null, typeof(JSSynchronizationContext)); + } + #endif } diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/WebWorker.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/WebWorker.cs index 9b95c18678687d..b5f15aeb1cd4e9 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/WebWorker.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/WebWorker.cs @@ -31,7 +31,7 @@ public static Task RunAsync(Func> body, CancellationToken cancella return; } - JSHostImplementation.InstallWebWorkerInterop(true); + JSHostImplementation.InstallWebWorkerInterop(true, false); var childScheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task res = body(); // This code is exiting thread main() before all promises are resolved. @@ -68,7 +68,7 @@ public static Task RunAsyncVoid(Func body, CancellationToken cancellationT return; } - JSHostImplementation.InstallWebWorkerInterop(true); + JSHostImplementation.InstallWebWorkerInterop(true, false); var childScheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task res = body(); // This code is exiting thread main() before all promises are resolved. @@ -105,7 +105,7 @@ public static Task Run(Action body, CancellationToken cancellationToken) return; } - JSHostImplementation.InstallWebWorkerInterop(false); + JSHostImplementation.InstallWebWorkerInterop(false, false); try { body(); diff --git a/src/mono/sample/wasm/browser-threads-minimal/Program.cs b/src/mono/sample/wasm/browser-threads-minimal/Program.cs index bd2646a34d2745..af7dff1fc84c4b 100644 --- a/src/mono/sample/wasm/browser-threads-minimal/Program.cs +++ b/src/mono/sample/wasm/browser-threads-minimal/Program.cs @@ -137,7 +137,7 @@ public static async Task FetchBackground(string url) Console.WriteLine($"smoke: FetchBackground 2 ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}, SynchronizationContext: {SynchronizationContext.Current?.GetType().FullName ?? "null"}"); var x=JSHost.ImportAsync(fetchhelper, "./fetchhelper.js"); Console.WriteLine($"smoke: FetchBackground 3A ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}, SynchronizationContext: {SynchronizationContext.Current?.GetType().FullName ?? "null"}"); - using var import = await x; + using var import = await x.ConfigureAwait(false); Console.WriteLine($"smoke: FetchBackground 3B ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}, SynchronizationContext: {SynchronizationContext.Current?.GetType().FullName ?? "null"}"); var r = await GlobalThisFetch(url); Console.WriteLine($"smoke: FetchBackground 4 ManagedThreadId:{Thread.CurrentThread.ManagedThreadId}, SynchronizationContext: {SynchronizationContext.Current?.GetType().FullName ?? "null"}");