diff options
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs')
-rw-r--r-- | src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs | 192 |
1 files changed, 170 insertions, 22 deletions
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 7bc8b5cc7..221a1a437 100644 --- a/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs +++ b/src/System.Private.CoreLib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs @@ -4,50 +4,198 @@ using System.Diagnostics; using System.Threading.Tasks; +using System.Threading.Tasks.Sources; namespace System.Runtime.CompilerServices { + /// <summary>Provides an awaiter for a <see cref="ValueTask"/>.</summary> + public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion +#if CORECLR + , IValueTaskAwaiter +#endif + { + /// <summary>Shim used to invoke an <see cref="Action"/> passed as the state argument to a <see cref="Action{Object}"/>.</summary> + internal static readonly Action<object> s_invokeActionDelegate = state => + { + if (!(state is Action action)) + { + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state); + return; + } + + action(); + }; + /// <summary>The value being awaited.</summary> + private readonly ValueTask _value; + + /// <summary>Initializes the awaiter.</summary> + /// <param name="value">The value to be awaited.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueTaskAwaiter(ValueTask value) => _value = value; + + /// <summary>Gets whether the <see cref="ValueTask"/> has completed.</summary> + public bool IsCompleted + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _value.IsCompleted; + } + + /// <summary>Gets the result of the ValueTask.</summary> + [StackTraceHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GetResult() => _value.ThrowIfCompletedUnsuccessfully(); + + /// <summary>Schedules the continuation action for this ValueTask.</summary> + public void OnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().GetAwaiter().OnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); + } + else + { + ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation); + } + } + + /// <summary>Schedules the continuation action for this ValueTask.</summary> + public void UnsafeOnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().GetAwaiter().UnsafeOnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + } + else + { + ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation); + } + } + +#if CORECLR + void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) + { + if (_value.ObjectIsTask) + { + TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeGetTask(), box, continueOnCapturedContext: true); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(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.Invoke(null); + }; +#endif + } + /// <summary>Provides an awaiter for a <see cref="ValueTask{TResult}"/>.</summary> - public struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion, IValueTaskAwaiter + public readonly struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion +#if CORECLR + , IValueTaskAwaiter +#endif { /// <summary>The value being awaited.</summary> - private ValueTask<TResult> _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies + private readonly ValueTask<TResult> _value; /// <summary>Initializes the awaiter.</summary> /// <param name="value">The value to be awaited.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ValueTaskAwaiter(ValueTask<TResult> value) => _value = value; /// <summary>Gets whether the <see cref="ValueTask{TResult}"/> has completed.</summary> - public bool IsCompleted => _value.IsCompleted; + public bool IsCompleted + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _value.IsCompleted; + } /// <summary>Gets the result of the ValueTask.</summary> [StackTraceHidden] - public TResult GetResult() => - _value._task == null ? - _value._result : - _value._task.GetAwaiter().GetResult(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TResult GetResult() => _value.Result; /// <summary>Schedules the continuation action for this ValueTask.</summary> - public void OnCompleted(Action continuation) => - _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().OnCompleted(continuation); + public void OnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().GetAwaiter().OnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); + } + else + { + ValueTask.CompletedTask.GetAwaiter().OnCompleted(continuation); + } + } /// <summary>Schedules the continuation action for this ValueTask.</summary> - public void UnsafeOnCompleted(Action continuation) => - _value.AsTask().ConfigureAwait(continueOnCapturedContext: true).GetAwaiter().UnsafeOnCompleted(continuation); - - /// <summary>Gets the task underlying <see cref="_value"/>.</summary> - internal Task<TResult> AsTask() => _value.AsTask(); + public void UnsafeOnCompleted(Action continuation) + { + if (_value.ObjectIsTask) + { + _value.UnsafeGetTask().GetAwaiter().UnsafeOnCompleted(continuation); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + } + else + { + ValueTask.CompletedTask.GetAwaiter().UnsafeOnCompleted(continuation); + } + } - /// <summary>Gets the task underlying the incomplete <see cref="_value"/>.</summary> - /// <remarks>This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task.</remarks> - Task IValueTaskAwaiter.GetTask() => _value.AsTaskExpectNonNull(); +#if CORECLR + void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box) + { + if (_value.ObjectIsTask) + { + TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeGetTask(), box, continueOnCapturedContext: true); + } + else if (_value._obj != null) + { + _value.UnsafeGetValueTaskSource().OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + } + else + { + TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, continueOnCapturedContext: true); + } + } +#endif } - /// <summary> - /// Internal interface used to enable extract the Task from arbitrary ValueTask awaiters. - /// </summary>> +#if CORECLR + /// <summary>Internal interface used to enable optimizations from <see cref="AsyncTaskMethodBuilder"/> on <see cref="ValueTask"/>.</summary>> internal interface IValueTaskAwaiter { - Task GetTask(); + /// <summary>Invoked to set <see cref="ITaskCompletionAction.Invoke"/> of the <paramref name="box"/> as the awaiter's continuation.</summary> + /// <param name="box">The box object.</param> + void AwaitUnsafeOnCompleted(IAsyncStateMachineBox box); } -} +#endif +}
\ No newline at end of file |