diff options
author | Ben Adams <thundercat@illyriad.co.uk> | 2018-11-28 21:45:16 +0000 |
---|---|---|
committer | Stephen Toub <stoub@microsoft.com> | 2018-11-28 16:45:16 -0500 |
commit | e7ead79fedc52e17f2cf9befd5c0f5091d70f909 (patch) | |
tree | 432843200d1b9950c14f08e40d87932ea1b2a494 | |
parent | 204d2da615347cb540c5fd36989953536d77140a (diff) | |
download | coreclr-e7ead79fedc52e17f2cf9befd5c0f5091d70f909.tar.gz coreclr-e7ead79fedc52e17f2cf9befd5c0f5091d70f909.tar.bz2 coreclr-e7ead79fedc52e17f2cf9befd5c0f5091d70f909.zip |
Queue ValueTaskAwaiter IAsyncStateMachineBox directly to ThreadPool (#21159)
* Queue ValueTaskAwaiter IAsyncStateMachineBox directly to ThreadPool
* Invert the dependency
* Move to UnsafeQueueUserWorkItem
* MRVTSC queue null or Deafult EC to UnsafeQUWI
* Revert MRVTSC change
* Add comment and validation
* Use s_invokeAsyncStateMachineBox for AsTask
* nits
* nits 2
* Rever ValueTask
* nits
3 files changed, 36 insertions, 16 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs index 8f7b0c809c..b874af2cd1 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; +using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Sources; @@ -111,7 +112,7 @@ namespace System.Runtime.CompilerServices } else if (obj != null) { - Unsafe.As<IValueTaskSource>(obj).OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token, + Unsafe.As<IValueTaskSource>(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); } else @@ -222,7 +223,7 @@ namespace System.Runtime.CompilerServices } else if (obj != null) { - Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token, + Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); } else diff --git a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs index 02b5910b77..db14806c63 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Threading; using System.Threading.Tasks; using System.Threading.Tasks.Sources; @@ -101,25 +102,13 @@ namespace System.Runtime.CompilerServices } else if (obj != null) { - Unsafe.As<IValueTaskSource>(obj).OnCompleted(s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + Unsafe.As<IValueTaskSource>(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, continueOnCapturedContext: true); } } - - /// <summary>Shim used to invoke <see cref="ITaskCompletionAction.Invoke"/> of the supplied <see cref="IAsyncStateMachineBox"/>.</summary> - internal static readonly Action<object> s_invokeAsyncStateMachineBox = state => - { - if (!(state is IAsyncStateMachineBox box)) - { - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); - return; - } - - box.MoveNext(); - }; #endif } @@ -201,7 +190,7 @@ namespace System.Runtime.CompilerServices } else if (obj != null) { - Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + Unsafe.As<IValueTaskSource<TResult>>(obj).OnCompleted(ThreadPoolGlobals.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { diff --git a/src/System.Private.CoreLib/src/System/Threading/ThreadPool.cs b/src/System.Private.CoreLib/src/System/Threading/ThreadPool.cs index 5026003395..cf44d850a4 100644 --- a/src/System.Private.CoreLib/src/System/Threading/ThreadPool.cs +++ b/src/System.Private.CoreLib/src/System/Threading/ThreadPool.cs @@ -37,6 +37,18 @@ namespace System.Threading public static bool enableWorkerTracking; public static readonly ThreadPoolWorkQueue workQueue = new ThreadPoolWorkQueue(); + + /// <summary>Shim used to invoke <see cref="IAsyncStateMachineBox.MoveNext"/> of the supplied <see cref="IAsyncStateMachineBox"/>.</summary> + internal static readonly Action<object> s_invokeAsyncStateMachineBox = state => + { + if (!(state is IAsyncStateMachineBox box)) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); + return; + } + + box.MoveNext(); + }; } [StructLayout(LayoutKind.Sequential)] // enforce layout so that padding reduces false sharing @@ -1333,6 +1345,24 @@ namespace System.Threading ThrowHelper.ThrowArgumentNullException(ExceptionArgument.callBack); } + // If the callback is the runtime-provided invocation of an IAsyncStateMachineBox, + // then we can queue the Task state directly to the ThreadPool instead of + // wrapping it in a QueueUserWorkItemCallback. + // + // This occurs when user code queues its provided continuation to the ThreadPool; + // internally we call UnsafeQueueUserWorkItemInternal directly for Tasks. + if (ReferenceEquals(callBack, ThreadPoolGlobals.s_invokeAsyncStateMachineBox)) + { + if (!(state is IAsyncStateMachineBox)) + { + // The provided state must be the internal IAsyncStateMachineBox (Task) type + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); + } + + UnsafeQueueUserWorkItemInternal((object)state, preferLocal); + return true; + } + EnsureVMInitialized(); ThreadPoolGlobals.workQueue.Enqueue( |