diff --git a/eng/references.targets b/eng/references.targets index bdb7faeed36b2b..5b7418b38e61f1 100644 --- a/eng/references.targets +++ b/eng/references.targets @@ -91,4 +91,20 @@ Condition="$(NetCoreAppLibraryNoReference.Contains('%(Filename);'))" /> + + + + + <_FileVersionMaj>$(FileVersion.Split('.')[0]) + <_FileVersionMin>$(FileVersion.Split('.')[1]) + <_FileVersionBld>$(FileVersion.Split('.')[2]) + <_FileVersionRev>$(FileVersion.Split('.')[3]) + $(_FileVersionMaj).$([MSBuild]::Add($(_FileVersionMin), 100)).$(_FileVersionBld).$(_FileVersionRev) + + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/ThreadPool.Windows.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/ThreadPool.Windows.cs index d478eb62e6ed92..391148cf1cd07c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/ThreadPool.Windows.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/ThreadPool.Windows.cs @@ -13,7 +13,6 @@ namespace System.Threading // // Windows-specific implementation of ThreadPool // - [UnsupportedOSPlatform("browser")] public sealed class RegisteredWaitHandle : MarshalByRefObject { private readonly Lock _lock; diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props index 18b7a886f2aeb8..e98978abda49f3 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props @@ -211,6 +211,7 @@ + @@ -237,6 +238,7 @@ + diff --git a/src/libraries/Microsoft.NET.WebAssembly.Threading/src/Microsoft.NET.WebAssembly.Threading.proj b/src/libraries/Microsoft.NET.WebAssembly.Threading/src/Microsoft.NET.WebAssembly.Threading.proj new file mode 100644 index 00000000000000..c9b7e5207f0f4b --- /dev/null +++ b/src/libraries/Microsoft.NET.WebAssembly.Threading/src/Microsoft.NET.WebAssembly.Threading.proj @@ -0,0 +1,25 @@ + + + $(NetCoreAppCurrent) + true + false + none + false + true + true + Exposes Threading APIs for WebAssembly projects + + $(NoWarn);NU5128;NU5131 + + ref + + + + + + + diff --git a/src/libraries/System.Diagnostics.Tracing.WebAssembly.PerfTracing/ref/System.Diagnostics.Tracing.WebAssembly.PerfTracing.csproj b/src/libraries/System.Diagnostics.Tracing.WebAssembly.PerfTracing/ref/System.Diagnostics.Tracing.WebAssembly.PerfTracing.csproj new file mode 100644 index 00000000000000..f639277acdb371 --- /dev/null +++ b/src/libraries/System.Diagnostics.Tracing.WebAssembly.PerfTracing/ref/System.Diagnostics.Tracing.WebAssembly.PerfTracing.csproj @@ -0,0 +1,22 @@ + + + true + $(NetCoreAppCurrent) + true + System.Diagnostics.Tracing + + true + + false + Microsoft + true + $(DefineConstants);FEATURE_WASM_PERFTRACING + + + + + + + + + diff --git a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs index 56c748f026e3e2..79a8e9ddd909ca 100644 --- a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs +++ b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs @@ -3,7 +3,9 @@ namespace System.Diagnostics.Tracing { +#if !FEATURE_WASM_PERFTRACING [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] +#endif public abstract partial class DiagnosticCounter : System.IDisposable { internal DiagnosticCounter() { } @@ -14,13 +16,17 @@ internal DiagnosticCounter() { } public void AddMetadata(string key, string? value) { } public void Dispose() { } } +#if !FEATURE_WASM_PERFTRACING [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] +#endif public partial class PollingCounter : System.Diagnostics.Tracing.DiagnosticCounter { public PollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func metricProvider) { } public override string ToString() { throw null; } } +#if !FEATURE_WASM_PERFTRACING [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] +#endif public partial class IncrementingEventCounter : System.Diagnostics.Tracing.DiagnosticCounter { public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { } @@ -28,14 +34,18 @@ public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSou public void Increment(double increment = 1) { } public override string ToString() { throw null; } } +#if !FEATURE_WASM_PERFTRACING [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] +#endif public partial class IncrementingPollingCounter : System.Diagnostics.Tracing.DiagnosticCounter { public IncrementingPollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func totalValueProvider) { } public System.TimeSpan DisplayRateTimeScale { get { throw null; } set { } } public override string ToString() { throw null; } } +#if !FEATURE_WASM_PERFTRACING [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] +#endif public partial class EventCounter : System.Diagnostics.Tracing.DiagnosticCounter { public EventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { } diff --git a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.csproj b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.csproj index cfc2c469399c3c..ca04d307f917f5 100644 --- a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.csproj +++ b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.csproj @@ -2,6 +2,8 @@ true $(NetCoreAppCurrent) + false + $(DefineConstants);FEATURE_WASM_PERFTRACING diff --git a/src/libraries/System.Diagnostics.Tracing/src/ApiCompatBaseline.txt b/src/libraries/System.Diagnostics.Tracing/src/ApiCompatBaseline.txt new file mode 100644 index 00000000000000..6c542177701265 --- /dev/null +++ b/src/libraries/System.Diagnostics.Tracing/src/ApiCompatBaseline.txt @@ -0,0 +1,7 @@ +Compat issues with assembly System.Diagnostics.Tracing: +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Diagnostics.Tracing.DiagnosticCounter' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Diagnostics.Tracing.EventCounter' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Diagnostics.Tracing.IncrementingEventCounter' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Diagnostics.Tracing.IncrementingPollingCounter' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Diagnostics.Tracing.PollingCounter' in the contract but not the implementation. +Total Issues: 4 diff --git a/src/libraries/System.Diagnostics.Tracing/src/MatchingRefApiCompatBaseline.txt b/src/libraries/System.Diagnostics.Tracing/src/MatchingRefApiCompatBaseline.txt index 754bf028a45ad8..d5f2617641ea37 100644 --- a/src/libraries/System.Diagnostics.Tracing/src/MatchingRefApiCompatBaseline.txt +++ b/src/libraries/System.Diagnostics.Tracing/src/MatchingRefApiCompatBaseline.txt @@ -1,6 +1,11 @@ Compat issues with assembly System.Diagnostics.Tracing: +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Diagnostics.Tracing.DiagnosticCounter' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Diagnostics.Tracing.EventCounter' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Diagnostics.Tracing.IncrementingEventCounter' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Diagnostics.Tracing.IncrementingPollingCounter' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Diagnostics.Tracing.PollingCounter' in the contract but not the implementation. MembersMustExist : Member 'protected void System.Diagnostics.Tracing.EventCounter.Flush()' does not exist in the reference but it does exist in the implementation. CannotMakeTypeAbstract : Type 'System.Diagnostics.Tracing.EventListener' is abstract in the reference but is not abstract in the implementation. CannotMakeMoreVisible : Visibility of member 'System.Diagnostics.Tracing.EventListener..ctor()' is 'protected' in the reference but 'public' in the implementation. CannotMakeMoreVisible : Visibility of member 'System.Diagnostics.Tracing.EventListener.EventSourceIndex(System.Diagnostics.Tracing.EventSource)' is 'protected' in the reference but 'public' in the implementation. -Total Issues: 4 +Total Issues: 8 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 b2a4460e5909ea..b6c8e95fc10d20 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 @@ -74,7 +74,7 @@ - + @@ -2329,7 +2329,7 @@ - + @@ -2346,7 +2346,7 @@ - + diff --git a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs index 25bda986d7408b..9fdaf0e9181128 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AppContext.AnyOS.cs @@ -12,6 +12,7 @@ namespace System { public static partial class AppContext { +#if !TARGET_BROWSER [UnconditionalSuppressMessage("SingleFile", "IL3000: Avoid accessing Assembly file path when publishing as a single file", Justification = "Single File apps should always set APP_CONTEXT_BASE_DIRECTORY therefore code handles Assembly.Location equals null")] private static string GetBaseDirectoryCore() @@ -33,6 +34,7 @@ private static string GetBaseDirectoryCore() return directory; } +#endif #if FEATURE_PERFTRACING internal static void LogSwitchValues(RuntimeEventSource ev) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs index aec84922437a36..cf7b4471ff7e61 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs @@ -15,9 +15,6 @@ namespace Microsoft.Diagnostics.Tracing namespace System.Diagnostics.Tracing #endif { -#if NETCOREAPP - [UnsupportedOSPlatform("browser")] -#endif internal sealed class CounterGroup { private readonly EventSource _eventSource; diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs index c03c9c5cdd94b5..aae0333497c0f8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs @@ -20,9 +20,6 @@ namespace System.Diagnostics.Tracing /// DiagnosticCounter is an abstract class that serves as the parent class for various Counter* classes, /// namely EventCounter, PollingCounter, IncrementingEventCounter, and IncrementingPollingCounter. /// -#if NETCOREAPP - [UnsupportedOSPlatform("browser")] -#endif public abstract class DiagnosticCounter : IDisposable { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs index 0c4460facc30f2..6fea134739756b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs @@ -24,9 +24,6 @@ namespace System.Diagnostics.Tracing /// See https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs /// which shows tests, which are also useful in seeing actual use. /// -#if NETCOREAPP - [UnsupportedOSPlatform("browser")] -#endif public partial class EventCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs index 13e5f1906ec327..3d20263b80f4d2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs @@ -21,9 +21,6 @@ namespace System.Diagnostics.Tracing /// It does not calculate statistics like mean, standard deviation, etc. because it only accumulates /// the counter value. /// -#if NETCOREAPP - [UnsupportedOSPlatform("browser")] -#endif public partial class IncrementingEventCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs index 21d14e6b0b044f..4b209901093e21 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs @@ -22,9 +22,6 @@ namespace System.Diagnostics.Tracing /// Unlike IncrementingEventCounter, this takes in a polling callback that it can call to update /// its own metric periodically. /// -#if NETCOREAPP - [UnsupportedOSPlatform("browser")] -#endif public partial class IncrementingPollingCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs index a2a4244fd13ad3..e19f1f37fdb64f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs @@ -20,9 +20,6 @@ namespace System.Diagnostics.Tracing /// function to collect metrics on its own rather than the user having to call WriteMetric() /// every time. /// -#if NETCOREAPP - [UnsupportedOSPlatform("browser")] -#endif public partial class PollingCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/RegisteredWaitHandle.Portable.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/RegisteredWaitHandle.Portable.cs index 5fea9dda9246eb..de31539b74b0fa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/RegisteredWaitHandle.Portable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/RegisteredWaitHandle.Portable.cs @@ -10,12 +10,12 @@ namespace System.Threading /// /// An object representing the registration of a via . /// - [UnsupportedOSPlatform("browser")] public sealed partial class RegisteredWaitHandle : MarshalByRefObject { internal RegisteredWaitHandle(WaitHandle waitHandle, _ThreadPoolWaitOrTimerCallback callbackHelper, int millisecondsTimeout, bool repeating) { + Thread.ThrowIfNoThreadStart(); Handle = waitHandle.SafeWaitHandle; Callback = callbackHelper; TimeoutDurationMs = millisecondsTimeout; 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 3d4b2d480e6a2d..7efa9b6a2a0126 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs @@ -154,15 +154,25 @@ public Thread(ParameterizedThreadStart start, int maxStackSize) } #if !TARGET_BROWSER - [UnsupportedOSPlatformGuard("browser")] internal static bool IsThreadStartSupported => true; +#else +#if FEATURE_WASM_THREADS + internal static bool IsThreadStartSupported => true; +#else + internal static bool IsThreadStartSupported => false; +#endif +#endif + + internal static void ThrowIfNoThreadStart() { + if (!IsThreadStartSupported) + throw new PlatformNotSupportedException(); + } /// Causes the operating system to change the state of the current instance to , and optionally supplies an object containing data to be used by the method the thread executes. /// An object that contains data to be used by the method the thread executes. /// The thread has already been started. /// There is not enough memory available to start this thread. /// This thread was created using a delegate instead of a delegate. - [UnsupportedOSPlatform("browser")] public void Start(object? parameter) => Start(parameter, captureContext: true); /// Causes the operating system to change the state of the current instance to , and optionally supplies an object containing data to be used by the method the thread executes. @@ -174,11 +184,12 @@ public Thread(ParameterizedThreadStart start, int maxStackSize) /// Unlike , which captures the current and uses that context to invoke the thread's delegate, /// explicitly avoids capturing the current context and flowing it to the invocation. /// - [UnsupportedOSPlatform("browser")] public void UnsafeStart(object? parameter) => Start(parameter, captureContext: false); private void Start(object? parameter, bool captureContext) { + ThrowIfNoThreadStart(); + StartHelper? startHelper = _startHelper; // In the case of a null startHelper (second call to start on same thread) @@ -201,7 +212,6 @@ private void Start(object? parameter, bool captureContext) /// Causes the operating system to change the state of the current instance to . /// The thread has already been started. /// There is not enough memory available to start this thread. - [UnsupportedOSPlatform("browser")] public void Start() => Start(captureContext: true); /// Causes the operating system to change the state of the current instance to . @@ -211,11 +221,11 @@ private void Start(object? parameter, bool captureContext) /// Unlike , which captures the current and uses that context to invoke the thread's delegate, /// explicitly avoids capturing the current context and flowing it to the invocation. /// - [UnsupportedOSPlatform("browser")] public void UnsafeStart() => Start(captureContext: false); private void Start(bool captureContext) { + ThrowIfNoThreadStart(); StartHelper? startHelper = _startHelper; // In the case of a null startHelper (second call to start on same thread) @@ -228,7 +238,6 @@ private void Start(bool captureContext) StartCore(); } -#endif private void RequireCurrentThread() { diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.Portable.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.Portable.cs index 2b62413a048278..25ab1e6fcb72d1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.Portable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.Portable.cs @@ -107,6 +107,7 @@ private static RegisteredWaitHandle RegisterWaitForSingleObject( ArgumentNullException.ThrowIfNull(waitObject); ArgumentNullException.ThrowIfNull(callBack); + Thread.ThrowIfNoThreadStart(); RegisteredWaitHandle registeredHandle = new RegisteredWaitHandle( waitObject, new _ThreadPoolWaitOrTimerCallback(callBack, state, flowExecutionContext), diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs index bed31df066c1a6..840e0b68e7bf59 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs @@ -1169,7 +1169,6 @@ public static partial class ThreadPool internal static bool EnableWorkerTracking => IsWorkerTrackingEnabledInConfig && EventSource.IsSupported; [CLSCompliant(false)] - [UnsupportedOSPlatform("browser")] public static RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callBack, @@ -1184,7 +1183,6 @@ public static RegisteredWaitHandle RegisterWaitForSingleObject( } [CLSCompliant(false)] - [UnsupportedOSPlatform("browser")] public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callBack, @@ -1198,7 +1196,6 @@ public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( return RegisterWaitForSingleObject(waitObject, callBack, state, millisecondsTimeOutInterval, executeOnlyOnce, false); } - [UnsupportedOSPlatform("browser")] public static RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callBack, @@ -1212,7 +1209,6 @@ public static RegisteredWaitHandle RegisterWaitForSingleObject( return RegisterWaitForSingleObject(waitObject, callBack, state, (uint)millisecondsTimeOutInterval, executeOnlyOnce, true); } - [UnsupportedOSPlatform("browser")] public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callBack, @@ -1226,7 +1222,6 @@ public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( return RegisterWaitForSingleObject(waitObject, callBack, state, (uint)millisecondsTimeOutInterval, executeOnlyOnce, false); } - [UnsupportedOSPlatform("browser")] public static RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callBack, @@ -1242,7 +1237,6 @@ public static RegisteredWaitHandle RegisterWaitForSingleObject( return RegisterWaitForSingleObject(waitObject, callBack, state, (uint)millisecondsTimeOutInterval, executeOnlyOnce, true); } - [UnsupportedOSPlatform("browser")] public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callBack, @@ -1258,7 +1252,6 @@ public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( return RegisterWaitForSingleObject(waitObject, callBack, state, (uint)millisecondsTimeOutInterval, executeOnlyOnce, false); } - [UnsupportedOSPlatform("browser")] public static RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callBack, @@ -1275,7 +1268,6 @@ bool executeOnlyOnce return RegisterWaitForSingleObject(waitObject, callBack, state, (uint)tm, executeOnlyOnce, true); } - [UnsupportedOSPlatform("browser")] public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callBack, diff --git a/src/libraries/System.Threading.Thread.WebAssembly.Threading/ref/System.Threading.Thread.WebAssembly.Threading.csproj b/src/libraries/System.Threading.Thread.WebAssembly.Threading/ref/System.Threading.Thread.WebAssembly.Threading.csproj new file mode 100644 index 00000000000000..341b1140e37782 --- /dev/null +++ b/src/libraries/System.Threading.Thread.WebAssembly.Threading/ref/System.Threading.Thread.WebAssembly.Threading.csproj @@ -0,0 +1,24 @@ + + + $(NetCoreAppCurrent) + true + System.Threading.Thread + true + + true + + false + Microsoft + true + $(DefineConstants);FEATURE_WASM_THREADS + + + + + + + + + + + diff --git a/src/libraries/System.Threading.Thread/ref/System.Threading.Thread.cs b/src/libraries/System.Threading.Thread/ref/System.Threading.Thread.cs index c34b32cc8aff71..d764627ce63651 100644 --- a/src/libraries/System.Threading.Thread/ref/System.Threading.Thread.cs +++ b/src/libraries/System.Threading.Thread/ref/System.Threading.Thread.cs @@ -89,16 +89,24 @@ public static void SetData(System.LocalDataStoreSlot slot, object? data) { } public static void Sleep(int millisecondsTimeout) { } public static void Sleep(System.TimeSpan timeout) { } public static void SpinWait(int iterations) { } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public void Start() { } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public void Start(object? parameter) { } [System.ObsoleteAttribute("Thread.Suspend has been deprecated. Use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources.")] public void Suspend() { } public bool TrySetApartmentState(System.Threading.ApartmentState state) { throw null; } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public void UnsafeStart() { } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public void UnsafeStart(object? parameter) { } public static byte VolatileRead(ref byte address) { throw null; } public static double VolatileRead(ref double address) { throw null; } diff --git a/src/libraries/System.Threading.Thread/ref/System.Threading.Thread.csproj b/src/libraries/System.Threading.Thread/ref/System.Threading.Thread.csproj index 8a2b6b27d720e3..c0668c328e24e4 100644 --- a/src/libraries/System.Threading.Thread/ref/System.Threading.Thread.csproj +++ b/src/libraries/System.Threading.Thread/ref/System.Threading.Thread.csproj @@ -1,6 +1,8 @@ $(NetCoreAppCurrent) + false + $(DefineConstants);FEATURE_WASM_THREADS @@ -11,4 +13,4 @@ - \ No newline at end of file + diff --git a/src/libraries/System.Threading.Thread/src/ApiCompatBaseline.txt b/src/libraries/System.Threading.Thread/src/ApiCompatBaseline.txt new file mode 100644 index 00000000000000..33ad3c96ed62bb --- /dev/null +++ b/src/libraries/System.Threading.Thread/src/ApiCompatBaseline.txt @@ -0,0 +1,6 @@ +Compat issues with assembly System.Threading.Thread: +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.Thread.Start()' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.Thread.Start(System.Object)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.Thread.UnsafeStart()' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.Thread.UnsafeStart(System.Object)' in the contract but not the implementation. +Total Issues: 4 diff --git a/src/libraries/System.Threading.Thread/src/MatchingRefApiCompatBaseline.txt b/src/libraries/System.Threading.Thread/src/MatchingRefApiCompatBaseline.txt new file mode 100644 index 00000000000000..33ad3c96ed62bb --- /dev/null +++ b/src/libraries/System.Threading.Thread/src/MatchingRefApiCompatBaseline.txt @@ -0,0 +1,6 @@ +Compat issues with assembly System.Threading.Thread: +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.Thread.Start()' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.Thread.Start(System.Object)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.Thread.UnsafeStart()' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.Thread.UnsafeStart(System.Object)' in the contract but not the implementation. +Total Issues: 4 diff --git a/src/libraries/System.Threading.Thread/src/System.Threading.Thread.csproj b/src/libraries/System.Threading.Thread/src/System.Threading.Thread.csproj index 49a3f302b2ef6c..319f6f543bd997 100644 --- a/src/libraries/System.Threading.Thread/src/System.Threading.Thread.csproj +++ b/src/libraries/System.Threading.Thread/src/System.Threading.Thread.csproj @@ -2,8 +2,9 @@ true $(NetCoreAppCurrent) + false - \ No newline at end of file + diff --git a/src/libraries/System.Threading.ThreadPool.WebAssembly.Threading/ref/System.Threading.ThreadPool.WebAssembly.Threading.csproj b/src/libraries/System.Threading.ThreadPool.WebAssembly.Threading/ref/System.Threading.ThreadPool.WebAssembly.Threading.csproj new file mode 100644 index 00000000000000..8afbfd514f9b24 --- /dev/null +++ b/src/libraries/System.Threading.ThreadPool.WebAssembly.Threading/ref/System.Threading.ThreadPool.WebAssembly.Threading.csproj @@ -0,0 +1,22 @@ + + + System.Threading.ThreadPool + true + $(NetCoreAppCurrent) + true + + true + + false + Microsoft + true + $(DefineConstants);FEATURE_WASM_THREADS + + + + + + + + + diff --git a/src/libraries/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.cs b/src/libraries/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.cs index 23411ce260f332..20ca9318b980c4 100644 --- a/src/libraries/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.cs +++ b/src/libraries/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.cs @@ -10,7 +10,9 @@ public partial interface IThreadPoolWorkItem { void Execute(); } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public sealed partial class RegisteredWaitHandle : System.MarshalByRefObject { internal RegisteredWaitHandle() { } @@ -32,14 +34,22 @@ public static partial class ThreadPool public static bool QueueUserWorkItem(System.Threading.WaitCallback callBack) { throw null; } public static bool QueueUserWorkItem(System.Threading.WaitCallback callBack, object? state) { throw null; } public static bool QueueUserWorkItem(System.Action callBack, TState state, bool preferLocal) { throw null; } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public static System.Threading.RegisteredWaitHandle RegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object? state, int millisecondsTimeOutInterval, bool executeOnlyOnce) { throw null; } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public static System.Threading.RegisteredWaitHandle RegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object? state, long millisecondsTimeOutInterval, bool executeOnlyOnce) { throw null; } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public static System.Threading.RegisteredWaitHandle RegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object? state, System.TimeSpan timeout, bool executeOnlyOnce) { throw null; } [System.CLSCompliantAttribute(false)] +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public static System.Threading.RegisteredWaitHandle RegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object? state, uint millisecondsTimeOutInterval, bool executeOnlyOnce) { throw null; } public static bool SetMaxThreads(int workerThreads, int completionPortThreads) { throw null; } public static bool SetMinThreads(int workerThreads, int completionPortThreads) { throw null; } @@ -49,14 +59,22 @@ public static partial class ThreadPool public static bool UnsafeQueueUserWorkItem(System.Threading.IThreadPoolWorkItem callBack, bool preferLocal) { throw null; } public static bool UnsafeQueueUserWorkItem(System.Threading.WaitCallback callBack, object? state) { throw null; } public static bool UnsafeQueueUserWorkItem(System.Action callBack, TState state, bool preferLocal) { throw null; } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public static System.Threading.RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object? state, int millisecondsTimeOutInterval, bool executeOnlyOnce) { throw null; } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public static System.Threading.RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object? state, long millisecondsTimeOutInterval, bool executeOnlyOnce) { throw null; } +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public static System.Threading.RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object? state, System.TimeSpan timeout, bool executeOnlyOnce) { throw null; } [System.CLSCompliantAttribute(false)] +#if !FEATURE_WASM_THREADS [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] +#endif public static System.Threading.RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object? state, uint millisecondsTimeOutInterval, bool executeOnlyOnce) { throw null; } } public delegate void WaitCallback(object? state); diff --git a/src/libraries/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.csproj b/src/libraries/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.csproj index 6978db726d7ff1..8db89a9f99d7dd 100644 --- a/src/libraries/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.csproj +++ b/src/libraries/System.Threading.ThreadPool/ref/System.Threading.ThreadPool.csproj @@ -2,6 +2,8 @@ true $(NetCoreAppCurrent) + false + $(DefineConstants);FEATURE_WASM_THREADS diff --git a/src/libraries/System.Threading.ThreadPool/src/ApiCompatBaseline.txt b/src/libraries/System.Threading.ThreadPool/src/ApiCompatBaseline.txt new file mode 100644 index 00000000000000..3dfbafeadd916d --- /dev/null +++ b/src/libraries/System.Threading.ThreadPool/src/ApiCompatBaseline.txt @@ -0,0 +1,11 @@ +Compat issues with assembly System.Threading.ThreadPool: +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.RegisteredWaitHandle' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.RegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.Int32, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.RegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.Int64, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.RegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.TimeSpan, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.RegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.UInt32, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.Int32, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.Int64, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.TimeSpan, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.UInt32, System.Boolean)' in the contract but not the implementation. +Total Issues: 9 diff --git a/src/libraries/System.Threading.ThreadPool/src/MatchingRefApiCompatBaseline.txt b/src/libraries/System.Threading.ThreadPool/src/MatchingRefApiCompatBaseline.txt new file mode 100644 index 00000000000000..3dfbafeadd916d --- /dev/null +++ b/src/libraries/System.Threading.ThreadPool/src/MatchingRefApiCompatBaseline.txt @@ -0,0 +1,11 @@ +Compat issues with assembly System.Threading.ThreadPool: +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.RegisteredWaitHandle' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.RegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.Int32, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.RegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.Int64, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.RegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.TimeSpan, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.RegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.UInt32, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.Int32, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.Int64, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.TimeSpan, System.Boolean)' in the contract but not the implementation. +CannotRemoveAttribute : Attribute 'System.Runtime.Versioning.UnsupportedOSPlatformAttribute' exists on 'System.Threading.ThreadPool.UnsafeRegisterWaitForSingleObject(System.Threading.WaitHandle, System.Threading.WaitOrTimerCallback, System.Object, System.UInt32, System.Boolean)' in the contract but not the implementation. +Total Issues: 9 diff --git a/src/libraries/testPackages/packageSettings/Microsoft.NET.WebAssembly.Threading/settings.targets b/src/libraries/testPackages/packageSettings/Microsoft.NET.WebAssembly.Threading/settings.targets new file mode 100644 index 00000000000000..a5e5b2e06a0731 --- /dev/null +++ b/src/libraries/testPackages/packageSettings/Microsoft.NET.WebAssembly.Threading/settings.targets @@ -0,0 +1,5 @@ + + + true + + diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index a2e7b80edfce70..344e383b58cf84 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -50,6 +50,11 @@ + + + + + diff --git a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj index 8a16000e3f5e15..18ec40cc3ca0b2 100644 --- a/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -113,11 +113,13 @@ $(DefineConstants);MONO_FEATURE_SRE true + true + true true true true - true - true + true + true true @@ -126,6 +128,8 @@ $(DefineConstants);FEATURE_MANAGED_ETW_CHANNELS $(DefineConstants);FEATURE_PERFTRACING $(DefineConstants);FEATURE_OBJCMARSHAL + $(DefineConstants);FEATURE_WASM_THREADS + $(DefineConstants);FEATURE_WASM_PERFTRACING @@ -284,11 +288,15 @@ - - + + + + + - + + diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Browser.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Browser.Mono.cs deleted file mode 100644 index 435a155c4ed164..00000000000000 --- a/src/mono/System.Private.CoreLib/src/System/Threading/Thread.Browser.Mono.cs +++ /dev/null @@ -1,25 +0,0 @@ -// 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; - -namespace System.Threading -{ - public partial class Thread - { - [UnsupportedOSPlatformGuard("browser")] - internal static bool IsThreadStartSupported => false; - - [UnsupportedOSPlatform("browser")] - public void Start() => throw new PlatformNotSupportedException(); - - [UnsupportedOSPlatform("browser")] - public void Start(object parameter) => throw new PlatformNotSupportedException(); - - [UnsupportedOSPlatform("browser")] - public void UnsafeStart() => throw new PlatformNotSupportedException(); - - [UnsupportedOSPlatform("browser")] - public void UnsafeStart(object parameter) => throw new PlatformNotSupportedException(); - } -} diff --git a/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPoolBoundHandle.Browser.Threads.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPoolBoundHandle.Browser.Threads.Mono.cs new file mode 100644 index 00000000000000..c1bcfa75b8c2f0 --- /dev/null +++ b/src/mono/System.Private.CoreLib/src/System/Threading/ThreadPoolBoundHandle.Browser.Threads.Mono.cs @@ -0,0 +1,15 @@ +// 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.InteropServices; + +namespace System.Threading +{ + public sealed partial class ThreadPoolBoundHandle : IDisposable + { + private static ThreadPoolBoundHandle BindHandleCore(SafeHandle handle) + { + throw new PlatformNotSupportedException(SR.PlatformNotSupported_OverlappedIO); + } + } +} diff --git a/src/mono/mono.proj b/src/mono/mono.proj index e025820e33f579..83c32e6df65cc5 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -9,6 +9,8 @@ - MonoAOTLLVMDir - [optional] the directory where LLVM is located, for an AOT-only Mono - MonoVerboseBuild - enable verbose build - MonoThreadSuspend - coop,hybrid,preemptive - default thread suspend mode + - MonoWasmThreads - build runtime with threading support for wasm + - MonoWasmThreadsNoUser - build runtime with threading support for wasm, but with only internal utility threads (MonoWasmThreads must be defined too) --> @@ -50,6 +52,8 @@ <_CompilerTargetArch Condition="'$(RealTargetArchitecture)' != ''">$(RealTargetArchitecture) $([MSBuild]::NormalizeDirectory('$(RepositoryEngineeringDir)', 'common')) $([MSBuild]::NormalizePath('$(RepositoryEngineeringCommonDir)', 'cross', 'toolchain.cmake')) + true + true @@ -321,17 +325,25 @@ <_MonoMinimal Condition="'$(Configuration)' == 'Release'">,debugger_agent,log_dest <_MonoMinimal Condition="'$(Configuration)' == 'Release' and '$(MonoEnableAssertMessages)' != 'true'">$(_MonoMinimal),assert_messages + <_MonoMinimal Condition="'$(MonoWasmThreads)' != 'true'">$(_MonoMinimal),threads + <_MonoMinimal Condition="'$(MonoWasmThreadsNoUser)' == 'true'">$(_MonoMinimal),wasm_user_threads - <_MonoCMakeArgs Include="-DENABLE_MINIMAL=jit,sgen_major_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,sgen_toggleref,sgen_debug_helpers,sgen_binary_protocol,logging,interpreter,threads,qcalls$(_MonoMinimal)"/> + <_MonoCMakeArgs Include="-DENABLE_MINIMAL=jit,sgen_major_marksweep_conc,sgen_split_nursery,sgen_gc_bridge,sgen_toggleref,sgen_debug_helpers,sgen_binary_protocol,logging,interpreter,qcalls$(_MonoMinimal)"/> <_MonoCMakeArgs Include="-DENABLE_INTERP_LIB=1"/> <_MonoCMakeArgs Include="-DDISABLE_ICALL_TABLES=1"/> <_MonoCMakeArgs Include="-DENABLE_ICALL_EXPORT=1"/> <_MonoCMakeArgs Include="-DENABLE_LAZY_GC_THREAD_CREATION=1"/> <_MonoCMakeArgs Include="-DENABLE_LLVM_RUNTIME=1"/> <_MonoCFLAGS Include="-fexceptions"/> + <_MonoCFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-pthread"/> + <_MonoCFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-D_GNU_SOURCE=1" /> <_MonoCXXFLAGS Include="-fexceptions"/> - <_MonoCFLAGS Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm', 'native', 'include'))$(EscapedQuoteW)"/> + <_MonoCXXFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-pthread"/> + <_MonoCXXFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="-D_GNU_SOURCE=1" /> + <_MonoCFLAGS Condition="'$(MonoWasmThreads)' == 'true'" Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm-threads', 'native', 'include'))$(EscapedQuoteW)"/> + + <_MonoCFLAGS Condition="'$(MonoWasmThreads)' != 'true'" Include="$(EscapedQuoteW)-I$([MSBuild]::NormalizePath('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm', 'native', 'include'))$(EscapedQuoteW)"/> @@ -457,6 +469,11 @@ <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT=1"/> + + <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_PERFTRACING_LISTEN_PORTS=1"/> + <_MonoCMakeArgs Include="-DFEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT=1"/> + + <_MonoCMakeArgs Include="-DSTATIC_COMPONENTS=1" /> diff --git a/src/mono/mono/eventpipe/CMakeLists.txt b/src/mono/mono/eventpipe/CMakeLists.txt index fe64183c449056..30d3139e5879ad 100644 --- a/src/mono/mono/eventpipe/CMakeLists.txt +++ b/src/mono/mono/eventpipe/CMakeLists.txt @@ -10,9 +10,9 @@ if(ENABLE_PERFTRACING) add_definitions(-DENABLE_PERFTRACING_PAL_TCP) endif (FEATURE_PERFTRACING_PAL_TCP) - if (FEATURE_PERFTRACING_DISABLE_LISTEN_PORTS) + if (FEATURE_PERFTRACING_DISABLE_PERFTRACING_LISTEN_PORTS) add_definitions(-DDISABLE_PERFTRACING_LISTEN_PORTS) - endif (FEATURE_PERFTRACING_DISABLE_LISTEN_PORTS) + endif (FEATURE_PERFTRACING_DISABLE_PERFTRACING_LISTEN_PORTS) if (FEATURE_PERFTRACING_DISABLE_DEFAULT_LISTEN_PORT) add_definitions(-DDISABLE_PERFTRACING_DEFAULT_LISTEN_PORT) diff --git a/src/mono/mono/eventpipe/ep-rt-mono.h b/src/mono/mono/eventpipe/ep-rt-mono.h index 3cf0214b351fb9..40a7e15d3d26f7 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-mono.h @@ -23,6 +23,7 @@ #include #include #include +#include "mono/utils/mono-logger-internals.h" #include #include diff --git a/src/mono/mono/metadata/assembly.c b/src/mono/mono/metadata/assembly.c index ba5f28a8bc2e6e..8f74d2bfd5826c 100644 --- a/src/mono/mono/metadata/assembly.c +++ b/src/mono/mono/metadata/assembly.c @@ -1511,6 +1511,7 @@ mono_assembly_open_from_bundle (MonoAssemblyLoadContext *alc, const char *filena * purpose assembly loading mechanism. */ MonoImage *image = NULL; + MONO_ENTER_GC_UNSAFE; gboolean is_satellite = culture && culture [0] != 0; if (is_satellite) @@ -1522,6 +1523,7 @@ mono_assembly_open_from_bundle (MonoAssemblyLoadContext *alc, const char *filena mono_image_addref (image); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Assembly Loader loaded assembly from bundle: '%s'.", filename); } + MONO_EXIT_GC_UNSAFE; return image; } @@ -2844,11 +2846,15 @@ mono_assembly_load_full (MonoAssemblyName *aname, const char *basedir, MonoImage MonoAssembly* mono_assembly_load (MonoAssemblyName *aname, const char *basedir, MonoImageOpenStatus *status) { + MonoAssembly *result = NULL; + MONO_ENTER_GC_UNSAFE; MonoAssemblyByNameRequest req; mono_assembly_request_prepare_byname (&req, mono_alc_get_default ()); req.requesting_assembly = NULL; req.basedir = basedir; - return mono_assembly_request_byname (aname, &req, status); + result = mono_assembly_request_byname (aname, &req, status); + MONO_EXIT_GC_UNSAFE; + return result; } /** diff --git a/src/mono/mono/metadata/gc.c b/src/mono/mono/metadata/gc.c index 7434ab68d3cbca..fc4526d72de36f 100644 --- a/src/mono/mono/metadata/gc.c +++ b/src/mono/mono/metadata/gc.c @@ -42,6 +42,7 @@ #include #include #include +#include #ifndef HOST_WIN32 #include #endif @@ -685,6 +686,21 @@ ves_icall_System_GCHandle_InternalSet (MonoGCHandle handle, MonoObjectHandle obj static MonoCoopSem finalizer_sem; static volatile gboolean finished; +#ifdef HOST_WASM + +static void +mono_wasm_gc_finalize_notify (void) +{ +#if 0 + /* use this if we are going to start the finalizer thread on wasm. */ + mono_coop_sem_post (&finalizer_sem); +#else + mono_threads_schedule_background_job (mono_runtime_do_background_work); +#endif +} + +#endif /* HOST_WASM */ + /* * mono_gc_finalize_notify: * @@ -705,7 +721,7 @@ mono_gc_finalize_notify (void) #if defined(HOST_WASI) // TODO: Schedule the background job on WASI. Threads aren't yet supported in this build. #elif defined(HOST_WASM) - mono_threads_schedule_background_job (mono_runtime_do_background_work); + mono_wasm_gc_finalize_notify (); #else mono_coop_sem_post (&finalizer_sem); #endif diff --git a/src/mono/mono/mini/mini-exceptions.c b/src/mono/mono/mini/mini-exceptions.c index 477b24f7f82a3b..f6ce3463d32ef8 100644 --- a/src/mono/mono/mini/mini-exceptions.c +++ b/src/mono/mono/mini/mini-exceptions.c @@ -3270,6 +3270,8 @@ mono_thread_state_init (MonoThreadUnwindState *ctx) #if defined(MONO_CROSS_COMPILE) ctx->valid = FALSE; //A cross compiler doesn't need to suspend. +#elif defined(HOST_WASM) + MONO_INIT_CONTEXT_FROM_FUNC (&(ctx->ctx), mono_thread_state_init); #elif defined(HOST_WASI) // TODO: For WASI, we need to review how thread state is initialized #elif MONO_ARCH_HAS_MONO_CONTEXT diff --git a/src/mono/mono/utils/CMakeLists.txt b/src/mono/mono/utils/CMakeLists.txt index 8ebc05f171d7a0..d0a01e77935507 100644 --- a/src/mono/mono/utils/CMakeLists.txt +++ b/src/mono/mono/utils/CMakeLists.txt @@ -135,6 +135,7 @@ set(utils_common_sources mono-threads-android.c mono-threads-haiku.c mono-threads-aix.c + mono-threads-wasm.h mono-threads-wasm.c mono-threads-sunos.c mono-threads.h diff --git a/src/mono/mono/utils/mono-threads-wasm.c b/src/mono/mono/utils/mono-threads-wasm.c index e7415532cbf095..8da132a23b772f 100644 --- a/src/mono/mono/utils/mono-threads-wasm.c +++ b/src/mono/mono/utils/mono-threads-wasm.c @@ -8,13 +8,19 @@ #include #include +#include #include #ifdef HOST_BROWSER +#include + #include #include +#ifndef DISABLE_THREADS +#include +#endif #define round_down(addr, val) ((void*)((addr) & ~((val) - 1))) @@ -110,7 +116,6 @@ mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2) return id1 == id2; } - MonoNativeThreadId mono_native_thread_id_get (void) { @@ -319,11 +324,22 @@ mono_memory_barrier_process_wide (void) G_EXTERN_C extern void schedule_background_exec (void); +/* jobs is not protected by a mutex, only access from a single thread! */ static GSList *jobs; void mono_threads_schedule_background_job (background_job_cb cb) { +#ifndef DISABLE_THREADS + if (!mono_threads_wasm_is_browser_thread ()) { + THREADS_DEBUG ("worker %p queued job %p\n", (gpointer)pthread_self(), (gpointer) cb); + mono_threads_wasm_async_run_in_main_thread_vi ((void (*)(gpointer))mono_threads_schedule_background_job, cb); + return; + } +#endif + + THREADS_DEBUG ("main thread queued job %p\n", (gpointer) cb); + if (!jobs) schedule_background_exec (); @@ -339,6 +355,9 @@ G_EXTERN_C EMSCRIPTEN_KEEPALIVE void mono_background_exec (void) { +#ifndef DISABLE_THREADS + g_assert (mono_threads_wasm_is_browser_thread ()); +#endif GSList *j = jobs, *cur; jobs = NULL; @@ -349,6 +368,40 @@ mono_background_exec (void) g_slist_free (j); } +gboolean +mono_threads_platform_is_main_thread (void) +{ +#ifdef DISABLE_THREADS + return TRUE; +#else + return emscripten_is_main_runtime_thread (); +#endif +} + +gboolean +mono_threads_wasm_is_browser_thread (void) +{ +#ifdef DISABLE_THREADS + return TRUE; +#else + return emscripten_is_main_browser_thread (); +#endif +} + +#ifndef DISABLE_THREADS +void +mono_threads_wasm_async_run_in_main_thread (void (*func) (void)) +{ + emscripten_async_run_in_main_runtime_thread (EM_FUNC_SIG_V, func); +} + +void +mono_threads_wasm_async_run_in_main_thread_vi (void (*func) (gpointer), gpointer user_data) +{ + emscripten_async_run_in_main_runtime_thread (EM_FUNC_SIG_VI, func, user_data); +} +#endif /* DISABLE_THREADS */ + #endif /* HOST_BROWSER */ #else diff --git a/src/mono/mono/utils/mono-threads-wasm.h b/src/mono/mono/utils/mono-threads-wasm.h new file mode 100644 index 00000000000000..ecad01a7ec6037 --- /dev/null +++ b/src/mono/mono/utils/mono-threads-wasm.h @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +/** + * \file + * Low-level threading for Webassembly + */ + +#ifndef __MONO_THREADS_WASM_H__ +#define __MONO_THREADS_WASM_H__ + +#include + +#ifdef HOST_WASM + +/* + * declared in mono-threads.h + * + * gboolean + * mono_threads_platform_is_main_thread (void); + */ + +gboolean +mono_threads_wasm_is_browser_thread (void); + +#ifndef DISABLE_THREADS +/** + * Runs the given function asynchronously on the main thread. + * See emscripten/threading.h emscripten_async_run_in_main_runtime_thread + */ +void +mono_threads_wasm_async_run_in_main_thread (void (*func) (void)); + +/* + * Variant that takes an argument. Add more variants as needed. + */ +void +mono_threads_wasm_async_run_in_main_thread_vi (void (*func)(gpointer), gpointer user_data); +#endif /* DISABLE_THREADS */ + +#endif /* HOST_WASM*/ + +#endif /* __MONO_THREADS_WASM_H__ */ diff --git a/src/mono/sample/wasm/browser-mt-eventpipe/Makefile b/src/mono/sample/wasm/browser-mt-eventpipe/Makefile new file mode 100644 index 00000000000000..8fddd8371b830e --- /dev/null +++ b/src/mono/sample/wasm/browser-mt-eventpipe/Makefile @@ -0,0 +1,11 @@ +TOP=../../../../.. + +include ../wasm.mk + +ifneq ($(AOT),) +override MSBUILD_ARGS+=/p:RunAOTCompilation=true +endif + +PROJECT_NAME=Wasm.Browser.ThreadsEP.Sample.csproj + +run: run-browser diff --git a/src/mono/sample/wasm/browser-mt-eventpipe/Program.cs b/src/mono/sample/wasm/browser-mt-eventpipe/Program.cs new file mode 100644 index 00000000000000..8683f673d92ef1 --- /dev/null +++ b/src/mono/sample/wasm/browser-mt-eventpipe/Program.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using System.Collections.Generic; +using System.Threading; +using System.Runtime.Versioning; + +namespace Sample +{ + public class Test + { + public static void Main(string[] args) + { + Console.WriteLine ("Hello, World!"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + [SupportedOSPlatform("browser")] // ask the analyzer to warn if we use APIs not supported on browser-wasm + public static int TestMeaning() + { + List myList = new List{ 1, 2, 3, 4 }; + Console.WriteLine(myList); + + Thread t = new Thread(new ThreadStart(ThreadFuncTest)); + t.Start(); + + for (int i = 0; i < 5; i++) + { + Console.WriteLine("Main Thread is doing stuff too... " + i.ToString()); + Thread.Sleep(100); + GC.Collect(); + } + + return 42; + } + + public static void ThreadFuncTest() + { + Console.WriteLine("Hello from another thread"); + + for (int i = 0; i < 5; i++) + { + Console.WriteLine("Sleeping from another thread: " + i.ToString()); + Thread.Sleep(100); + GC.Collect(); + } + } + } +} diff --git a/src/mono/sample/wasm/browser-mt-eventpipe/Wasm.Browser.ThreadsEP.Sample.csproj b/src/mono/sample/wasm/browser-mt-eventpipe/Wasm.Browser.ThreadsEP.Sample.csproj new file mode 100644 index 00000000000000..124d312b33d21c --- /dev/null +++ b/src/mono/sample/wasm/browser-mt-eventpipe/Wasm.Browser.ThreadsEP.Sample.csproj @@ -0,0 +1,43 @@ + + + true + main.js + true + embedded + 1 + false + true + true + $(ExecXHarnessCmd) wasm test-browser --app=. --browser=Chrome $(XHarnessBrowserPathArg) --html-file=index.html --output-directory=$(XHarnessOutput) -- $(MSBuildProjectName).dll + true + + + + + + + + + <_SampleProject>Wasm.Browser.CJS.Sample.csproj + + + + + true + + + + + + + + + + + + + diff --git a/src/mono/sample/wasm/browser-mt-eventpipe/index.html b/src/mono/sample/wasm/browser-mt-eventpipe/index.html new file mode 100644 index 00000000000000..e0a5f09c94108c --- /dev/null +++ b/src/mono/sample/wasm/browser-mt-eventpipe/index.html @@ -0,0 +1,20 @@ + + + + + + + Sample CJS + + + + + + + Answer to the Ultimate Question of Life, the Universe, and Everything is : + + + + + + \ No newline at end of file diff --git a/src/mono/sample/wasm/browser-mt-eventpipe/main.js b/src/mono/sample/wasm/browser-mt-eventpipe/main.js new file mode 100644 index 00000000000000..ba5a4075fe7c40 --- /dev/null +++ b/src/mono/sample/wasm/browser-mt-eventpipe/main.js @@ -0,0 +1,66 @@ +function wasm_exit(exit_code) { + /* Set result in a tests_done element, to be read by xharness in runonly CI test */ + const tests_done_elem = document.createElement("label"); + tests_done_elem.id = "tests_done"; + tests_done_elem.innerHTML = exit_code.toString(); + document.body.appendChild(tests_done_elem); + + console.log(`WASM EXIT ${exit_code}`); +} + +function Uint8ToString(u8a){ + var CHUNK_SZ = 0x8000; + var c = []; + for (var i=0; i < u8a.length; i+=CHUNK_SZ) { + c.push(String.fromCharCode.apply(null, u8a.subarray(i, i+CHUNK_SZ))); + } + return c.join(""); +} + +async function loadRuntime() { + globalThis.exports = {}; + await import("./dotnet.js"); + return globalThis.exports.createDotnetRuntime; +} + +async function main() { + const createDotnetRuntime = await loadRuntime(); + const { MONO, BINDING, Module, RuntimeBuildInfo } = await createDotnetRuntime(() => { + console.log('user code in createDotnetRuntime') + return { + disableDotnet6Compatibility: true, + configSrc: "./mono-config.json", + preInit: () => { console.log('user code Module.preInit') }, + preRun: () => { console.log('user code Module.preRun') }, + onRuntimeInitialized: () => { console.log('user code Module.onRuntimeInitialized') }, + postRun: () => { console.log('user code Module.postRun') }, + } + }); + globalThis.__Module = Module; + globalThis.MONO = MONO; + console.log('after createDotnetRuntime') + + try { + const testMeaning = BINDING.bind_static_method("[Wasm.Browser.ThreadsEP.Sample] Sample.Test:TestMeaning"); + const ret = testMeaning(); + document.getElementById("out").innerHTML = `${ret} as computed on dotnet ver ${RuntimeBuildInfo.ProductVersion}`; + + console.debug(`ret: ${ret}`); + + let exit_code = ret == 42 ? 0 : 1; + Module._mono_wasm_exit(exit_code); + + wasm_exit(exit_code); + } catch (err) { + console.log(`WASM ERROR ${err}`); + + var b = Module.FS.readFile('/trace.nettrace'); + var bits = btoa((Uint8ToString(b))); + + window.open("data:application/octet-stream;base64," + bits); + + wasm_exit(2); + } +} + +setTimeout(main, 10000); diff --git a/src/mono/sample/wasm/wasm.mk b/src/mono/sample/wasm/wasm.mk index 1d9d407e3dff6b..fbe782a3deb95a 100644 --- a/src/mono/sample/wasm/wasm.mk +++ b/src/mono/sample/wasm/wasm.mk @@ -10,6 +10,9 @@ CONFIG?=Release WASM_DEFAULT_BUILD_ARGS?=/p:TargetArchitecture=wasm /p:TargetOS=Browser /p:Configuration=$(CONFIG) +# we set specific headers to enable SharedArrayBuffer support in browsers for threading: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements +CORS_HEADERS?= -h "Cross-Origin-Opener-Policy:same-origin" -h "Cross-Origin-Embedder-Policy:require-corp" + # if we're in a container, don't try to open the browser ifneq ("$(wildcard /.dockerenv)", "") OPEN_BROWSER= @@ -22,10 +25,10 @@ endif all: publish build: - EMSDK_PATH=$(realpath $(TOP)/src/mono/wasm/emsdk) $(DOTNET) build $(DOTNET_Q_ARGS) $(WASM_DEFAULT_BUILD_ARGS) $(MSBUILD_ARGS) $(PROJECT_NAME) + $(DOTNET) build $(DOTNET_Q_ARGS) $(WASM_DEFAULT_BUILD_ARGS) $(MSBUILD_ARGS) $(PROJECT_NAME) publish: - EMSDK_PATH=$(realpath $(TOP)/src/mono/wasm/emsdk) $(DOTNET) publish $(DOTNET_Q_ARGS) $(WASM_DEFAULT_BUILD_ARGS) -p:WasmBuildOnlyAfterPublish=true $(MSBUILD_ARGS) $(PROJECT_NAME) + $(DOTNET) publish $(DOTNET_Q_ARGS) $(WASM_DEFAULT_BUILD_ARGS) -p:WasmBuildOnlyAfterPublish=true $(MSBUILD_ARGS) $(PROJECT_NAME) clean: rm -rf bin $(TOP)/artifacts/obj/mono/$(PROJECT_NAME:%.csproj=%) @@ -35,7 +38,7 @@ run-browser: echo "The tool dotnet-serve could not be found. Install with: $(DOTNET) tool install --global dotnet-serve"; \ exit 1; \ else \ - $(DOTNET) serve -d:bin/$(CONFIG)/AppBundle $(OPEN_BROWSER) -p:8000; \ + $(DOTNET) serve -d:bin/$(CONFIG)/AppBundle $(CORS_HEADERS) $(OPEN_BROWSER) -p:8000; \ fi run-console: diff --git a/src/mono/wasm/build/WasmApp.InTree.props b/src/mono/wasm/build/WasmApp.InTree.props index 7f655768c8e737..76c089b8dd4b87 100644 --- a/src/mono/wasm/build/WasmApp.InTree.props +++ b/src/mono/wasm/build/WasmApp.InTree.props @@ -15,7 +15,7 @@ <_MonoRuntimeComponentDontLink Include="libmono-component-debugger-stub-static.a" /> - <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a" /> + <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a" Condition="'$(FeatureWasmPerfTracing)' != 'true'"/> <_MonoRuntimeComponentDontLink Include="libmono-component-hot_reload-stub-static.a" /> diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index 501cb7e156808f..b92320d735befa 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -208,6 +208,7 @@ <_EmccCFlags Include="$(EmccCompileOptimizationFlag)" /> <_EmccCFlags Include="@(_EmccCommonFlags)" /> + <_EmccCFlags Include="-DDISABLE_PERFTRACING_LISTEN_PORTS=1" /> <_EmccCFlags Include="-DENABLE_AOT=1" Condition="'$(_WasmShouldAOT)' == 'true'" /> <_EmccCFlags Include="-DDRIVER_GEN=1" Condition="'$(_WasmShouldAOT)' == 'true'" /> <_EmccCFlags Include="-DINVARIANT_GLOBALIZATION=1" Condition="'$(InvariantGlobalization)' == 'true'" /> @@ -436,6 +437,7 @@ + diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index 070195319d6b53..cf8b18508cd7a4 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -260,6 +260,7 @@ icudt.dat <_HasDotnetWasm Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.wasm'">true + <_HasDotnetJsWorker Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.worker.js'">true <_HasDotnetJsSymbols Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.js.symbols'">true <_HasDotnetJs Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.js'">true @@ -268,6 +269,7 @@ + diff --git a/src/mono/wasm/runtime/CMakeLists.txt b/src/mono/wasm/runtime/CMakeLists.txt index dfd9e0d8c01dda..dac8d63e719d35 100644 --- a/src/mono/wasm/runtime/CMakeLists.txt +++ b/src/mono/wasm/runtime/CMakeLists.txt @@ -2,10 +2,13 @@ cmake_minimum_required(VERSION 3.14.5) project(mono-wasm-runtime C) +option(DISABLE_THREADS "defined if the build does NOT support multithreading" ON) +option(DISABLE_WASM_USER_THREADS "defined if the build does not allow user threads to be created in a multithreaded build" OFF) + set(CMAKE_EXECUTABLE_SUFFIX ".js") add_executable(dotnet corebindings.c driver.c pinvoke.c) -target_include_directories(dotnet PUBLIC ${MONO_INCLUDES} ${MONO_OBJ_INCLUDES}) +target_include_directories(dotnet PUBLIC ${MONO_INCLUDES} ${MONO_OBJ_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}/include/wasm) target_compile_options(dotnet PUBLIC @${NATIVE_BIN_DIR}/src/emcc-default.rsp @${NATIVE_BIN_DIR}/src/emcc-compile.rsp -DCORE_BINDINGS -DGEN_PINVOKE=1) set_target_properties(dotnet PROPERTIES COMPILE_FLAGS ${CONFIGURATION_EMCC_FLAGS}) @@ -33,3 +36,5 @@ set_target_properties(dotnet PROPERTIES if(CMAKE_BUILD_TYPE STREQUAL "Release") add_custom_command(TARGET dotnet POST_BUILD COMMAND ${EMSDK_PATH}/upstream/bin/wasm-opt --enable-exception-handling --strip-dwarf ${NATIVE_BIN_DIR}/dotnet.wasm -o ${NATIVE_BIN_DIR}/dotnet.wasm) endif() + +configure_file(wasm-config.h.in include/wasm/wasm-config.h) diff --git a/src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js b/src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js index 9326071c42e0a9..daa0782d477ad0 100644 --- a/src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js +++ b/src/mono/wasm/runtime/cjs/dotnet.cjs.extpost.js @@ -1,6 +1,7 @@ var require = require || undefined; // if loaded into global namespace and configured with global Module, we will self start in compatibility mode -let ENVIRONMENT_IS_GLOBAL = typeof globalThis.Module === "object" && globalThis.__dotnet_runtime === __dotnet_runtime; +const __isWorker = typeof globalThis.importScripts === "function"; +let ENVIRONMENT_IS_GLOBAL = !__isWorker && (typeof globalThis.Module === "object" && globalThis.__dotnet_runtime === __dotnet_runtime); if (ENVIRONMENT_IS_GLOBAL) { createDotnetRuntime(() => { return globalThis.Module; }).then((exports) => exports); } diff --git a/src/mono/wasm/runtime/corebindings.c b/src/mono/wasm/runtime/corebindings.c index 8cc2ff15a1ed4d..8d6d29cd947681 100644 --- a/src/mono/wasm/runtime/corebindings.c +++ b/src/mono/wasm/runtime/corebindings.c @@ -13,6 +13,7 @@ #include #include +#include "wasm-config.h" #include "gc-common.h" //JS funcs diff --git a/src/mono/wasm/runtime/dotnet.d.ts b/src/mono/wasm/runtime/dotnet.d.ts index 3e5083662d8601..0a4a8d48e8e7f6 100644 --- a/src/mono/wasm/runtime/dotnet.d.ts +++ b/src/mono/wasm/runtime/dotnet.d.ts @@ -382,6 +382,8 @@ declare const BINDING: { * @deprecated Renamed to conv_string_root */ conv_string_rooted: typeof conv_string_root; + mono_obj_array_new_ref: (size: number, result: MonoObjectRef) => void; + mono_obj_array_set_ref: (array: MonoObjectRef, idx: number, obj: MonoObjectRef) => void; js_string_to_mono_string_root: typeof js_string_to_mono_string_root; js_typed_array_to_array_root: typeof js_typed_array_to_array_root; js_to_mono_obj_root: typeof js_to_mono_obj_root; diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 2007d25bc22ae6..3a5977ee2c9657 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -28,6 +28,7 @@ #include #include +#include "wasm-config.h" #include "pinvoke.h" #include "gc-common.h" @@ -60,6 +61,8 @@ void mono_free (void*); int32_t mini_parse_debug_option (const char *option); char *mono_method_get_full_name (MonoMethod *method); +static void mono_wasm_init_finalizer_thread (void); + #define MARSHAL_TYPE_NULL 0 #define MARSHAL_TYPE_INT 1 #define MARSHAL_TYPE_FP64 2 @@ -464,6 +467,12 @@ mono_wasm_load_runtime (const char *unused, int debug_level) mono_wasm_link_icu_shim (); #endif + // We should enable this as part of the wasm build later +#ifndef DISABLE_THREADS + monoeg_g_setenv ("MONO_THREADS_SUSPEND", "coop", 0); + monoeg_g_setenv ("MONO_SLEEP_ABORT_LIMIT", "250", 0); +#endif + #ifdef DEBUG // monoeg_g_setenv ("MONO_LOG_LEVEL", "debug", 0); // monoeg_g_setenv ("MONO_LOG_MASK", "gc", 0); @@ -575,6 +584,10 @@ mono_wasm_load_runtime (const char *unused, int debug_level) mono_initialize_internals(); mono_thread_set_main (mono_thread_current ()); + + // TODO: we can probably delay starting the finalizer thread even longer - maybe from JS + // once we're done with loading and are about to begin running some managed code. + mono_wasm_init_finalizer_thread (); } EMSCRIPTEN_KEEPALIVE MonoAssembly* @@ -1203,6 +1216,7 @@ mono_wasm_exec_regression (int verbose_level, char *image) EMSCRIPTEN_KEEPALIVE int mono_wasm_exit (int exit_code) { + mono_jit_cleanup (root_domain); exit (exit_code); } @@ -1323,3 +1337,13 @@ mono_wasm_load_profiler_aot (const char *desc) } #endif + +static void +mono_wasm_init_finalizer_thread (void) +{ + // At this time we don't use a dedicated thread for finalization even if threading is enabled. + // Finalizers periodically run on the main thread +#if 0 + mono_gc_init_finalizer_thread (); +#endif +} diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index 37578887dded68..45124fc219aed2 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -170,6 +170,7 @@ let exportedAPI: DotnetPublicAPI; // this is executed early during load of emscripten runtime // it exports methods to global objects MONO, BINDING and Module in backward compatible way +// At runtime this will be referred to as 'createDotnetRuntime' // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types function initializeImportsAndExports( imports: { isESM: boolean, isGlobal: boolean, isNode: boolean, isShell: boolean, isWeb: boolean, locateFile: Function, quit_: Function, ExitStatus: ExitStatusError, requirePromise: Promise }, @@ -293,6 +294,14 @@ function initializeImportsAndExports( configure_emscripten_startup(module, exportedAPI); + // HACK: Emscripten expects the return value of this function to always be the Module object, + // but we changed ours to return a set of exported namespaces. In order for the emscripten + // generated worker code to keep working, we detect that we're running in a worker (via the + // presence of globalThis.importScripts) and emulate the old behavior. Note that this will + // impact anyone trying to load us in a web worker directly, not just emscripten! + if (typeof ((globalThis)["importScripts"]) === "function") + return exportedAPI.Module; + return exportedAPI; } diff --git a/src/mono/wasm/runtime/pinvoke.c b/src/mono/wasm/runtime/pinvoke.c index 3804005cb5adb4..eb422204826474 100644 --- a/src/mono/wasm/runtime/pinvoke.c +++ b/src/mono/wasm/runtime/pinvoke.c @@ -1,3 +1,4 @@ +#include "wasm-config.h" #include "pinvoke.h" #include diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index 49427b3539c07e..a8f3b7ce85b957 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -26,6 +26,29 @@ export const mono_wasm_runtime_is_initialized = new Promise((resolve, reject) => let ctx: DownloadAssetsContext | null = null; export function configure_emscripten_startup(module: DotnetModule, exportedAPI: DotnetPublicAPI): void { + // HACK: Emscripten expects us to provide it a fully qualified path where it can find + // our main script so that it can be loaded from inside of workers, because workers + // have their paths relative to the root instead of relative to our location + // In the browser we can create a hyperlink and set its href to a relative URL, + // and the browser will convert it into an absolute one for us + if ( + (typeof (globalThis.document) === "object") && + (typeof (globalThis.document.createElement) === "function") + ) { + // blazor injects a module preload link element for dotnet.[version].[sha].js + const blazorDotNetJS = Array.from (document.head.getElementsByTagName("link")).filter(elt => elt.rel !== undefined && elt.rel == "modulepreload" && elt.href !== undefined && elt.href.indexOf("dotnet") != -1 && elt.href.indexOf (".js") != -1); + if (blazorDotNetJS.length == 1) { + const hr = blazorDotNetJS[0].href; + console.log("determined url of main script to be " + hr); + (module)["mainScriptUrlOrBlob"] = hr; + } else { + const temp = globalThis.document.createElement("a"); + temp.href = "dotnet.js"; + console.log("determined url of main script to be " + temp.href); + (module)["mainScriptUrlOrBlob"] = temp.href; + } + } + // these could be overriden on DotnetModuleConfig if (!module.preInit) { module.preInit = []; @@ -715,4 +738,4 @@ export type DownloadAssetsContext = { resolved_promises: (MonoInitFetchResult | undefined)[] | null; loaded_files: { url?: string, file: string }[], loaded_assets: { [id: string]: [VoidPtr, number] }, -} \ No newline at end of file +} diff --git a/src/mono/wasm/runtime/wasm-config.h.in b/src/mono/wasm/runtime/wasm-config.h.in new file mode 100644 index 00000000000000..c5650ed200b45b --- /dev/null +++ b/src/mono/wasm/runtime/wasm-config.h.in @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// +#ifndef __MONO_WASM_CONFIG_H__ +#define __MONO_WASM_CONFIG_H__ + +/* Support for threads is disabled */ +#cmakedefine DISABLE_THREADS + +/* Support for starting user threads is disabled */ +#cmakedefine DISABLE_WASM_USER_THREADS + +#endif/*__MONO_WASM_CONFIG_H__*/ diff --git a/src/mono/wasm/threads.md b/src/mono/wasm/threads.md new file mode 100644 index 00000000000000..afda117cb74593 --- /dev/null +++ b/src/mono/wasm/threads.md @@ -0,0 +1,80 @@ +# Threaded runtime # + +## Building ## + +Build with `/p:WasmEnableThreads=true` to enable support for multi-threading. + +Build with `/p:WasmEnablePerfTracing=true` to enable support for EventPipe diagnostics - this enabled threading, but only for "internal" utility threads. User code is not allowed to start threads. + +Do not combine these options, just turn on one or the other. + +## Libraries feature defines ## + +We use the `FeatureWasmThreads` property in the libraries projects to conditionally define +`FEATURE_WASM_THREADS` which is used to affect how the libraries are built for the multi-threaded +runtime. + +We use the `FeatureWasmPerfTracing` property in the libraries projects to +conditionally define `FEATURE_WASM_PERFTRACING` which is used to affect how the +libraries are built for a runtime that is single-threaded for users, but +internally can use multithreading for EventPipe diagnostics. + +### Ref asssemblies ### + +For ref assemblies that have APIs that are related to threading, we use +`[UnsupportedOSPlatform("browser")]` under a `FEATURE_WASM_THREADS` define to mark APIs that are not +supported with the single-threaded runtime. Each such ref assembly (for example +`System.Threading.Thread`) is defined in two places: `src/libraries/System.Threading.Thread/ref` for +the single-threaded ref assemblies, and +`src/libraries/System.Threading.Thread.WebAssembly.Threading/ref/` for the multi-threaded ref +assemblies. By default users compile against the single-threaded ref assemblies, but by adding a +`PackageReference` to `Microsoft.NET.WebAssembly.Threading`, they get the multi-threaded ref +assemblies. + +### Implementation assemblies ### + +The implementation (in `System.Private.CoreLib`) we check +`System.Threading.Thread.IsThreadStartSupported` or call +`System.Threading.Thread.ThrowIfNoThreadStart()` to guard code paths that depends on +multi-threading. The property is a boolean constant that will allow the IL trimmer or the +JIT/interpreter/AOT to drop the multi-threaded implementation in the single-threaded CoreLib. + +The implementation should not use `[UnsupportedOSPlatform("browser")]` + +**TODO** For `FeatureWasmPerfTracing`, the implementation should check *some +runtime contant* and throw PNSE if diagnostics are not enabled. + +## Native runtime preprocessor defines ## + +In `src/mono/mono` and `src/mono/wasm` `DISABLE_THREADS` is defined for single-threaded builds (same +as mono's existing `-DENABLE_MINIMAL=threads` option). In multi-threaded builds, `DISABLE_THREADS` +is _not_ defined. + +For `WasmEnablePerfTracing`, `DISABLE_THREADS` is undefined (ie threading is enabled), but starting +user threads is not supported and `DISABLE_WASM_USER_THREADS` is defined (ie there is a +`-DENABLE_MINIMAL=wasm-user-threads` option) + +Additionally, `__EMSCRIPTEN_THREADS__` is defined by emscripten if threading is enabled. + +## Browser thread, main thread ## + +When the app starts, emscripten can optionally run `main` on a new worker instead of on the browser thread. + +Mono does _not_ use this at this time. + +## Running work on other threads ## + +Emscripten provides an API to queue up callbacks to run on the main thread, or on a particular +worker thread. See +[`emscripten/threading.h`](https://github.com/emscripten-core/emscripten/blob/main/system/include/emscripten/threading.h). + +Mono exposes these functions as `mono_threads_wasm_async_run_in_main_thread`, etc in +`mono/utils/mono-threads-wasm.h`. + +## Background tasks ## + +The runtime has a number of tasks that are scheduled with `mono_threads_schedule_background_job` +(pumping the threadpool task queue, running GC finalizers, etc). + +The background tasks will run on the main thread. Calling `mono_threads_schedule_background_job` on +a worker thread will use `async_run_in_main_thread` to queue up work for the main thread. diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index e63583af4aa8cb..c89caa7139db7d 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -6,7 +6,16 @@ browser-wasm $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'native', '$(NetCoreAppCurrent)-$(TargetOS)-$(Configuration)-$(TargetArchitecture)')) - $([MSBuild]::NormalizeDirectory('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm', 'native', 'lib')) + + + + true + true + + + + $([MSBuild]::NormalizeDirectory('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm', 'native', 'lib')) + $([MSBuild]::NormalizeDirectory('$(PkgMicrosoft_NETCore_Runtime_ICU_Transport)', 'runtimes', 'browser-wasm-threads', 'native', 'lib')) false false emcc @@ -129,6 +138,9 @@ <_EmccLinkFlags Include="-s NO_EXIT_RUNTIME=1" /> <_EmccLinkFlags Include="-s FORCE_FILESYSTEM=1" /> <_EmccLinkFlags Include="-s EXPORTED_RUNTIME_METHODS="['FS','print','ccall','cwrap','setValue','getValue','UTF8ToString','UTF8ArrayToString','FS_createPath','FS_createDataFile','removeRunDependency','addRunDependency', 'FS_readFile']"" /> + <_EmccCommonFlags Condition="'$(MonoWasmThreads)' == 'true'" Include="-s USE_PTHREADS=1" /> + <_EmccLinkFlags Condition="'$(MonoWasmThreads)' == 'true'" Include="-Wno-pthreads-mem-growth" /> + <_EmccLinkFlags Condition="'$(MonoWasmThreads)' == 'true'" Include="-s PTHREAD_POOL_SIZE=2" /> <_EmccLinkFlags Include="-s EXPORTED_FUNCTIONS=$(_DefaultExportedFunctions)" Condition="'$(_DefaultExportedFunctions)' != ''" /> <_EmccLinkFlags Include="--source-map-base http://example.com" /> <_EmccLinkFlags Include="-s STRICT_JS=1" /> @@ -178,6 +190,7 @@ $(CMakeConfigurationEmccFlags) -O2 + $(CMakeConfigurationLinkFlags) -Wno-pthreads-mem-growth $(CMakeConfigurationLinkFlags) --emit-symbol-map -DEMSDK_PATH="$(EMSDK_PATH.TrimEnd('\/'))" @@ -191,6 +204,8 @@ $(CMakeBuildRuntimeConfigureCmd) -DICU_LIB_DIR="$(ICULibDir.TrimEnd('\/'))" $(CMakeBuildRuntimeConfigureCmd) -DMONO_ARTIFACTS_DIR="$(MonoArtifactsPath.TrimEnd('\/'))" $(CMakeBuildRuntimeConfigureCmd) -DNATIVE_BIN_DIR="$(NativeBinDir.TrimEnd('\/'))" + $(CMakeBuildRuntimeConfigureCmd) -DDISABLE_THREADS=1 + $(CMakeBuildRuntimeConfigureCmd) -DDISABLE_WASM_USER_THREADS=1 $(CMakeBuildRuntimeConfigureCmd) $(CMakeConfigurationEmsdkPath) call "$(RepositoryEngineeringDir)native\init-vs-env.cmd" && call "$([MSBuild]::NormalizePath('$(EMSDK_PATH)', 'emsdk_env.bat'))" && $(CMakeBuildRuntimeConfigureCmd) @@ -259,6 +274,11 @@ DestinationFolder="$(MicrosoftNetCoreAppRuntimePackNativeDir)" SkipUnchangedFiles="true" /> + +