Background and motivation
Introduce public feature flag, that could be used to decide if the application could
- create threads
- call blocking
.Wait() methods on synchronization objects.
On systems that are single-threaded, those APIs throw PNSE.
There are 3rd party libraries that need different implementation for single-threaded browser.
Because in that environment, they can't create background worker thread. They have to use async/timer instead.
Here is relevant example from OTEL.
Another example is Avalonia
API Proposal
namespace System.Runtime.CompilerServices;
public static class RuntimeFeature
{
// Existing APIs
public static bool IsDynamicCodeCompiled { get; }
public static bool IsDynamicCodeSupported { get; }
+ [System.Diagnostics.CodeAnalysis.FeatureSwitchDefinitionAttribute("System.Runtime.CompilerServices.RuntimeFeature.IsMultithreadingSupported")]
+ public static bool IsMultithreadingSupported { get; }
}
API Usage
We already have internal internal Thread.IsSingleThreaded which we use inside of System.Private.CoreLib
private bool SpinWait(int millisecondsTimeout)
{
if (IsCompleted) return true;
if (Thread.IsSingleThreaded)
{
return false;
}
...
We can get rid of conditional compilation and use this as a linker feature. For example in JavaScript interop code.
-#if FEATURE_WASM_MANAGED_THREADS
+if(!RuntimeFeature.IsSingleThreaded)
+{
lock (ctx)
{
// this means that CompleteTask is called before the ToManaged(out Task? value)
if (holder.Callback == null)
{
holder.CallbackReady = new ManualResetEventSlim(false);
}
}
+}
-#endif
Based on this we would also create PlatformDetection.IsSingleThreaded and PlatformDetection.IsNotSingleThreaded
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotSingleThreaded))]
{
var e = new ManualResetEvent(false);
ev1.Wait(); // this is unsupported API on browser and throws PNSE
}
Alternative Designs
RuntimeFeatures.IsThreadingSupported (existing similar API: RuntimeFeatures.IsDynamicCodeSupported).
RuntimeFeatures.IsSingleThreaded
Thread.IsThreadingSupported
Thread.IsSingleThreaded
Thread.IsThreadStartSupported
Risks
Background and motivation
Introduce public feature flag, that could be used to decide if the application could
.Wait()methods on synchronization objects.On systems that are single-threaded, those APIs throw PNSE.
There are 3rd party libraries that need different implementation for single-threaded browser.
Because in that environment, they can't create background worker thread. They have to use async/timer instead.
Here is relevant example from OTEL.
Another example is Avalonia
API Proposal
namespace System.Runtime.CompilerServices; public static class RuntimeFeature { // Existing APIs public static bool IsDynamicCodeCompiled { get; } public static bool IsDynamicCodeSupported { get; } + [System.Diagnostics.CodeAnalysis.FeatureSwitchDefinitionAttribute("System.Runtime.CompilerServices.RuntimeFeature.IsMultithreadingSupported")] + public static bool IsMultithreadingSupported { get; } }API Usage
We already have internal internal
Thread.IsSingleThreadedwhich we use inside ofSystem.Private.CoreLibWe can get rid of conditional compilation and use this as a linker feature. For example in JavaScript interop code.
Based on this we would also create
PlatformDetection.IsSingleThreadedandPlatformDetection.IsNotSingleThreadedAlternative Designs
RuntimeFeatures.IsThreadingSupported(existing similar API:RuntimeFeatures.IsDynamicCodeSupported).RuntimeFeatures.IsSingleThreadedThread.IsThreadingSupportedThread.IsSingleThreadedThread.IsThreadStartSupportedRisks