diff options
author | Marek Safar <marek.safar@gmail.com> | 2019-02-05 04:43:10 +0100 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2019-02-04 19:43:10 -0800 |
commit | 382dbe4ba82f57a138484e0c5052c3b8606c1294 (patch) | |
tree | 4e220d0a0e3198678829836df034e8039e1697a2 /src/System.Private.CoreLib/src/System/Threading | |
parent | 7e20b6fa7b2253511b6f0a7d76c955360e040df6 (diff) | |
download | coreclr-382dbe4ba82f57a138484e0c5052c3b8606c1294.tar.gz coreclr-382dbe4ba82f57a138484e0c5052c3b8606c1294.tar.bz2 coreclr-382dbe4ba82f57a138484e0c5052c3b8606c1294.zip |
Move SynchronizationContext to shared partition (#22389)
* Move SynchronizationContext to shared partition
* Move WaitHelperNative to WaitHandle
Diffstat (limited to 'src/System.Private.CoreLib/src/System/Threading')
4 files changed, 94 insertions, 227 deletions
diff --git a/src/System.Private.CoreLib/src/System/Threading/SynchronizationContext.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Threading/SynchronizationContext.CoreCLR.cs new file mode 100644 index 0000000000..e26d9b7b70 --- /dev/null +++ b/src/System.Private.CoreLib/src/System/Threading/SynchronizationContext.CoreCLR.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Threading +{ + public partial class SynchronizationContext + { + private static int InvokeWaitMethodHelper(SynchronizationContext syncContext, IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) + { + return syncContext.Wait(waitHandles, waitAll, millisecondsTimeout); + } + } +} diff --git a/src/System.Private.CoreLib/src/System/Threading/SynchronizationContext.Uap.cs b/src/System.Private.CoreLib/src/System/Threading/SynchronizationContext.Uap.cs new file mode 100644 index 0000000000..69f6f95d25 --- /dev/null +++ b/src/System.Private.CoreLib/src/System/Threading/SynchronizationContext.Uap.cs @@ -0,0 +1,77 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Reflection; +using System.Diagnostics; + +namespace System.Threading +{ + public partial class SynchronizationContext + { + public static SynchronizationContext Current + { + get + { + SynchronizationContext context = Thread.CurrentThread.SynchronizationContext; + + if (context == null && ApplicationModel.IsUap) + context = GetWinRTContext(); + + return context; + } + } + + private static SynchronizationContext GetWinRTContext() + { + Debug.Assert(Environment.IsWinRTSupported); + Debug.Assert(ApplicationModel.IsUap); + + // + // We call into the VM to get the dispatcher. This is because: + // + // a) We cannot call the WinRT APIs directly from mscorlib, because we don't have the fancy projections here. + // b) We cannot call into System.Runtime.WindowsRuntime here, because we don't want to load that assembly + // into processes that don't need it (for performance reasons). + // + // So, we check the VM to see if the current thread has a dispatcher; if it does, we pass that along to + // System.Runtime.WindowsRuntime to get a corresponding SynchronizationContext. + // + object dispatcher = GetWinRTDispatcherForCurrentThread(); + if (dispatcher != null) + return GetWinRTSynchronizationContext(dispatcher); + + return null; + } + + private static Func<object, SynchronizationContext> s_createSynchronizationContextDelegate; + + private static SynchronizationContext GetWinRTSynchronizationContext(object dispatcher) + { + // + // Since we can't directly reference System.Runtime.WindowsRuntime from mscorlib, we have to get the factory via reflection. + // It would be better if we could just implement WinRTSynchronizationContextFactory in mscorlib, but we can't, because + // we can do very little with WinRT stuff in mscorlib. + // + Func<object, SynchronizationContext> createSynchronizationContextDelegate = s_createSynchronizationContextDelegate; + if (createSynchronizationContextDelegate == null) + { + Type factoryType = Type.GetType("System.Threading.WinRTSynchronizationContextFactory, System.Runtime.WindowsRuntime", throwOnError: true); + + // Create an instance delegate for the Create static method + MethodInfo createMethodInfo = factoryType.GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + createSynchronizationContextDelegate = (Func<object, SynchronizationContext>)Delegate.CreateDelegate(typeof(Func<object, SynchronizationContext>), createMethodInfo, /* throwOnBindFailure */ true); + + s_createSynchronizationContextDelegate = createSynchronizationContextDelegate; + } + + return s_createSynchronizationContextDelegate(dispatcher); + } + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Interface)] + private static extern object GetWinRTDispatcherForCurrentThread(); + } +} diff --git a/src/System.Private.CoreLib/src/System/Threading/SynchronizationContext.cs b/src/System.Private.CoreLib/src/System/Threading/SynchronizationContext.cs deleted file mode 100644 index a1336cb95e..0000000000 --- a/src/System.Private.CoreLib/src/System/Threading/SynchronizationContext.cs +++ /dev/null @@ -1,227 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -/*============================================================ -** -** -** -** Purpose: Capture synchronization semantics for asynchronous callbacks -** -** -===========================================================*/ - -namespace System.Threading -{ - using Microsoft.Win32.SafeHandles; - using System.Runtime.InteropServices; - using System.Runtime.CompilerServices; - using System.Runtime.ExceptionServices; - using System.Runtime; - using System.Runtime.Versioning; - using System.Runtime.ConstrainedExecution; - using System.Reflection; - using System.Security; - using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - - - [Flags] - internal enum SynchronizationContextProperties - { - None = 0, - RequireWaitNotification = 0x1 - }; - - public class SynchronizationContext - { - private SynchronizationContextProperties _props = SynchronizationContextProperties.None; - - public SynchronizationContext() - { - } - - - // helper delegate to statically bind to Wait method - private delegate int WaitDelegate(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout); - - private static Type s_cachedPreparedType1; - private static Type s_cachedPreparedType2; - private static Type s_cachedPreparedType3; - private static Type s_cachedPreparedType4; - private static Type s_cachedPreparedType5; - - // protected so that only the derived sync context class can enable these flags - [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "We never dereference s_cachedPreparedType*, so ordering is unimportant")] - protected void SetWaitNotificationRequired() - { - // - // Prepare the method so that it can be called in a reliable fashion when a wait is needed. - // This will obviously only make the Wait reliable if the Wait method is itself reliable. The only thing - // preparing the method here does is to ensure there is no failure point before the method execution begins. - // - // Preparing the method in this way is quite expensive, but only needs to be done once per type, per AppDomain. - // So we keep track of a few types we've already prepared in this AD. It is uncommon to have more than - // a few SynchronizationContext implementations, so we only cache the first five we encounter; this lets - // our cache be much faster than a more general cache might be. This is important, because this - // is a *very* hot code path for many WPF and WinForms apps. - // - Type type = this.GetType(); - if (s_cachedPreparedType1 != type && - s_cachedPreparedType2 != type && - s_cachedPreparedType3 != type && - s_cachedPreparedType4 != type && - s_cachedPreparedType5 != type) - { - RuntimeHelpers.PrepareDelegate(new WaitDelegate(this.Wait)); - - if (s_cachedPreparedType1 == null) s_cachedPreparedType1 = type; - else if (s_cachedPreparedType2 == null) s_cachedPreparedType2 = type; - else if (s_cachedPreparedType3 == null) s_cachedPreparedType3 = type; - else if (s_cachedPreparedType4 == null) s_cachedPreparedType4 = type; - else if (s_cachedPreparedType5 == null) s_cachedPreparedType5 = type; - } - - _props |= SynchronizationContextProperties.RequireWaitNotification; - } - - public bool IsWaitNotificationRequired() - { - return ((_props & SynchronizationContextProperties.RequireWaitNotification) != 0); - } - - - public virtual void Send(SendOrPostCallback d, object state) - { - d(state); - } - - public virtual void Post(SendOrPostCallback d, object state) - { - ThreadPool.QueueUserWorkItem(s => s.d(s.state), (d, state), preferLocal: false); - } - - - /// <summary> - /// Optional override for subclasses, for responding to notification that operation is starting. - /// </summary> - public virtual void OperationStarted() - { - } - - /// <summary> - /// Optional override for subclasses, for responding to notification that operation has completed. - /// </summary> - public virtual void OperationCompleted() - { - } - - // Method called when the CLR does a wait operation - [CLSCompliant(false)] - public virtual int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) - { - return WaitHelper(waitHandles, waitAll, millisecondsTimeout); - } - - // Method that can be called by Wait overrides - [CLSCompliant(false)] - protected static int WaitHelper(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) - { - if (waitHandles == null) - { - throw new ArgumentNullException(nameof(waitHandles)); - } - - return WaitHelperNative(waitHandles, waitAll, millisecondsTimeout); - } - - // Static helper to which the above method can delegate to in order to get the default - // COM behavior. - [MethodImplAttribute(MethodImplOptions.InternalCall)] - private static extern int WaitHelperNative(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout); - - public static void SetSynchronizationContext(SynchronizationContext syncContext) - { - Thread.CurrentThread.SynchronizationContext = syncContext; - } - - public static SynchronizationContext Current - { - get - { - SynchronizationContext context = Thread.CurrentThread.SynchronizationContext; - -#if FEATURE_APPX - if (context == null && ApplicationModel.IsUap) - context = GetWinRTContext(); -#endif - - return context; - } - } - -#if FEATURE_APPX - private static SynchronizationContext GetWinRTContext() - { - Debug.Assert(Environment.IsWinRTSupported); - Debug.Assert(ApplicationModel.IsUap); - - // - // We call into the VM to get the dispatcher. This is because: - // - // a) We cannot call the WinRT APIs directly from mscorlib, because we don't have the fancy projections here. - // b) We cannot call into System.Runtime.WindowsRuntime here, because we don't want to load that assembly - // into processes that don't need it (for performance reasons). - // - // So, we check the VM to see if the current thread has a dispatcher; if it does, we pass that along to - // System.Runtime.WindowsRuntime to get a corresponding SynchronizationContext. - // - object dispatcher = GetWinRTDispatcherForCurrentThread(); - if (dispatcher != null) - return GetWinRTSynchronizationContext(dispatcher); - - return null; - } - - private static Func<object, SynchronizationContext> s_createSynchronizationContextDelegate = null; - - private static SynchronizationContext GetWinRTSynchronizationContext(object dispatcher) - { - // - // Since we can't directly reference System.Runtime.WindowsRuntime from mscorlib, we have to get the factory via reflection. - // It would be better if we could just implement WinRTSynchronizationContextFactory in mscorlib, but we can't, because - // we can do very little with WinRT stuff in mscorlib. - // - Func<object, SynchronizationContext> createSynchronizationContextDelegate = s_createSynchronizationContextDelegate; - if (createSynchronizationContextDelegate == null) - { - Type factoryType = Type.GetType("System.Threading.WinRTSynchronizationContextFactory, System.Runtime.WindowsRuntime", throwOnError: true); - - // Create an instance delegate for the Create static method - MethodInfo createMethodInfo = factoryType.GetMethod("Create", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); - createSynchronizationContextDelegate = (Func<object, SynchronizationContext>)Delegate.CreateDelegate(typeof(Func<object, SynchronizationContext>), createMethodInfo, /* throwOnBindFailure */ true); - - s_createSynchronizationContextDelegate = createSynchronizationContextDelegate; - } - - return s_createSynchronizationContextDelegate(dispatcher); - } - - [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Interface)] - private static extern object GetWinRTDispatcherForCurrentThread(); -#endif //FEATURE_APPX - - - // helper to Clone this SynchronizationContext, - public virtual SynchronizationContext CreateCopy() - { - // the CLR dummy has an empty clone function - no member data - return new SynchronizationContext(); - } - - private static int InvokeWaitMethodHelper(SynchronizationContext syncContext, IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) - { - return syncContext.Wait(waitHandles, waitAll, millisecondsTimeout); - } - } -} diff --git a/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs b/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs index 6f3f9d220a..83c5269cbb 100644 --- a/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs +++ b/src/System.Private.CoreLib/src/System/Threading/WaitHandle.cs @@ -221,6 +221,9 @@ namespace System.Threading [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern int WaitMultiple(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext, bool WaitAll); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal static extern int WaitMultipleIgnoringSyncContext(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout); + public static bool WaitAll(WaitHandle[] waitHandles, int millisecondsTimeout, bool exitContext) { if (waitHandles == null) |