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" />
+
+