diff options
author | Stephen Toub <stoub@microsoft.com> | 2019-01-27 14:15:08 -0500 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2019-01-27 11:15:08 -0800 |
commit | 5d5d680e64769f4807d2e114b74e1304a58822d5 (patch) | |
tree | 25a69e8865cebc902b7b48daa58eea5e416a6397 /src/System.Private.CoreLib/shared/System/Threading/Tasks | |
parent | 307ec0b724c01aec62d93cf2046f6b671c3eeced (diff) | |
download | coreclr-5d5d680e64769f4807d2e114b74e1304a58822d5.tar.gz coreclr-5d5d680e64769f4807d2e114b74e1304a58822d5.tar.bz2 coreclr-5d5d680e64769f4807d2e114b74e1304a58822d5.zip |
Remove several uses of VoidTaskResult (#22238)
* Remove defunct netstandard code from ValueTask
* Remove several uses of VoidTaskResult
Currently TrySetResult/Canceled/Exception live on `Task<T>`. There's no reason `TrySetCanceled` and `TrySetException` need to live there, as they only access state from the base `Task`, and so can be moved down. `TrySetResult` needs the `TResult`, however in a variety of cases `Task<T>` is used with a `VoidTaskResult`, and for such cases we can just have a parameterless `TrySetResult()` on the base class as well, which can be used any time there is no `TResult` or when `default(TResult)` is the desired result. This lets us switch several cases where we were using `Task<VoidTaskResult>` to just be `Task`, which saves 8 bytes on the task instance on 64-bit. It also avoids an Interlocked.Exchange as part of the TrySetResult call.
This primarily affects Task.Delay and the non-generic variants of Task.WhenAll, ValueTask.AsTask(), Task.FromCanceled, and Task.FromException.
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/Threading/Tasks')
5 files changed, 163 insertions, 219 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs index 9adcdd6df9..e207a7421f 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs @@ -147,7 +147,7 @@ namespace System.Threading.Tasks public Task Completion { // ValueLock not needed, but it's ok if it's held - get { return EnsureCompletionStateInitialized().Task; } + get { return EnsureCompletionStateInitialized(); } } /// <summary>Gets the lazily-initialized completion state.</summary> @@ -214,12 +214,12 @@ namespace System.Threading.Tasks ThreadPool.QueueUserWorkItem(state => { var localThis = (ConcurrentExclusiveSchedulerPair)state; - Debug.Assert(!localThis.m_completionState.Task.IsCompleted, "Completion should only happen once."); + Debug.Assert(!localThis.m_completionState.IsCompleted, "Completion should only happen once."); List<Exception> exceptions = localThis.m_completionState.m_exceptions; bool success = (exceptions != null && exceptions.Count > 0) ? localThis.m_completionState.TrySetException(exceptions) : - localThis.m_completionState.TrySetResult(default); + localThis.m_completionState.TrySetResult(); Debug.Assert(success, "Expected to complete completion task."); localThis.m_threadProcessingMode.Dispose(); @@ -479,7 +479,7 @@ namespace System.Threading.Tasks /// the Completion. /// </summary> [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] - private sealed class CompletionState : TaskCompletionSource<VoidTaskResult> + private sealed class CompletionState : Task { /// <summary>Whether the scheduler has had completion requested.</summary> /// <remarks>This variable is not volatile, so to gurantee safe reading reads, Volatile.Read is used in TryExecuteTaskInline.</remarks> @@ -741,7 +741,7 @@ namespace System.Threading.Tasks get { // If our completion task is done, so are we. - if (m_completionState != null && m_completionState.Task.IsCompleted) return ProcessingMode.Completed; + if (m_completionState != null && m_completionState.IsCompleted) return ProcessingMode.Completed; // Otherwise, summarize our current state. var mode = ProcessingMode.NotCurrentlyProcessing; diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs index 5cc0b6737b..06eb1186ae 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Future.cs @@ -386,6 +386,8 @@ namespace System.Threading.Tasks { Debug.Assert(m_action == null, "Task<T>.TrySetResult(): non-null m_action"); + bool returnValue = false; + // "Reserve" the completion for this task, while making sure that: (1) No prior reservation // has been made, (2) The result has not already been set, (3) An exception has not previously // been recorded, and (4) Cancellation has not been requested. @@ -411,10 +413,10 @@ namespace System.Threading.Tasks props.SetCompleted(); } FinishContinuations(); - return true; + returnValue = true; } - return false; + return returnValue; } // Transitions the promise task into a successfully completed state with the specified result. @@ -491,95 +493,6 @@ namespace System.Threading.Tasks return m_result; } - // Allow multiple exceptions to be assigned to a promise-style task. - // This is useful when a TaskCompletionSource<T> stands in as a proxy - // for a "real" task (as we do in Unwrap(), ContinueWhenAny() and ContinueWhenAll()) - // and the "real" task ends up with multiple exceptions, which is possible when - // a task has children. - // - // Called from TaskCompletionSource<T>.SetException(IEnumerable<Exception>). - internal bool TrySetException(object exceptionObject) - { - Debug.Assert(m_action == null, "Task<T>.TrySetException(): non-null m_action"); - - // TCS.{Try}SetException() should have checked for this - Debug.Assert(exceptionObject != null, "Expected non-null exceptionObject argument"); - - // Only accept these types. - Debug.Assert( - (exceptionObject is Exception) || (exceptionObject is IEnumerable<Exception>) || - (exceptionObject is ExceptionDispatchInfo) || (exceptionObject is IEnumerable<ExceptionDispatchInfo>), - "Expected exceptionObject to be either Exception, ExceptionDispatchInfo, or IEnumerable<> of one of those"); - - bool returnValue = false; - - // "Reserve" the completion for this task, while making sure that: (1) No prior reservation - // has been made, (2) The result has not already been set, (3) An exception has not previously - // been recorded, and (4) Cancellation has not been requested. - // - // If the reservation is successful, then add the exception(s) and finish completion processing. - // - // The lazy initialization may not be strictly necessary, but I'd like to keep it here - // anyway. Some downstream logic may depend upon an inflated m_contingentProperties. - EnsureContingentPropertiesInitialized(); - if (AtomicStateUpdate(TASK_STATE_COMPLETION_RESERVED, - TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) - { - AddException(exceptionObject); // handles singleton exception or exception collection - Finish(false); - returnValue = true; - } - - return returnValue; - } - - // internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder - // If the tokenToRecord is not None, it will be stored onto the task. - // This method is only valid for promise tasks. - internal bool TrySetCanceled(CancellationToken tokenToRecord) - { - return TrySetCanceled(tokenToRecord, null); - } - - // internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder - // If the tokenToRecord is not None, it will be stored onto the task. - // If the OperationCanceledException is not null, it will be stored into the task's exception holder. - // This method is only valid for promise tasks. - internal bool TrySetCanceled(CancellationToken tokenToRecord, object cancellationException) - { - Debug.Assert(m_action == null, "Task<T>.TrySetCanceled(): non-null m_action"); -#if DEBUG - var ceAsEdi = cancellationException as ExceptionDispatchInfo; - Debug.Assert( - cancellationException == null || - cancellationException is OperationCanceledException || - (ceAsEdi != null && ceAsEdi.SourceException is OperationCanceledException), - "Expected null or an OperationCanceledException"); -#endif - - bool returnValue = false; - - // "Reserve" the completion for this task, while making sure that: (1) No prior reservation - // has been made, (2) The result has not already been set, (3) An exception has not previously - // been recorded, and (4) Cancellation has not been requested. - // - // If the reservation is successful, then record the cancellation and finish completion processing. - // - // Note: I had to access static Task variables through Task<object> - // instead of Task, because I have a property named Task and that - // was confusing the compiler. - if (AtomicStateUpdate(Task<object>.TASK_STATE_COMPLETION_RESERVED, - Task<object>.TASK_STATE_COMPLETION_RESERVED | Task<object>.TASK_STATE_CANCELED | - Task<object>.TASK_STATE_FAULTED | Task<object>.TASK_STATE_RAN_TO_COMPLETION)) - { - RecordInternalCancellationRequest(tokenToRecord, cancellationException); - CancellationCleanupLogic(); // perform cancellation cleanup actions - returnValue = true; - } - - return returnValue; - } - /// <summary> /// Provides access to factory methods for creating <see cref="Task{TResult}"/> instances. /// </summary> diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs index 0d8cdcb535..55fab9a5de 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/FutureFactory.cs @@ -800,7 +800,7 @@ namespace System.Threading.Tasks Task.RemoveFromActiveTasks(promise); // Make sure we don't leave promise "dangling". - promise.TrySetResult(default); + promise.TrySetResult(); throw; } @@ -917,7 +917,7 @@ namespace System.Threading.Tasks Task.RemoveFromActiveTasks(promise); // Make sure we don't leave promise "dangling". - promise.TrySetResult(default); + promise.TrySetResult(); throw; } @@ -1042,7 +1042,7 @@ namespace System.Threading.Tasks Task.RemoveFromActiveTasks(promise); // Make sure we don't leave promise "dangling". - promise.TrySetResult(default); + promise.TrySetResult(); throw; } @@ -1175,7 +1175,7 @@ namespace System.Threading.Tasks Task.RemoveFromActiveTasks(promise); // Make sure we don't leave the promise "dangling". - promise.TrySetResult(default); + promise.TrySetResult(); throw; } diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs index 3f580c4bb0..2c19332555 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/Task.cs @@ -3192,6 +3192,113 @@ namespace System.Threading.Tasks m_stateFlags |= TASK_STATE_CANCELLATIONACKNOWLEDGED; } + /// <summary>Completes a promise task as RanToCompletion.</summary> + /// <remarks>If this is a Task{T}, default(T) is the implied result.</remarks> + /// <returns>true if the task was transitioned to ran to completion; false if it was already completed.</returns> + internal bool TrySetResult() + { + Debug.Assert(m_action == null, "Task<T>.TrySetResult(): non-null m_action"); + + if (AtomicStateUpdate( + TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION, + TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) + { + ContingentProperties props = m_contingentProperties; + if (props != null) + { + NotifyParentIfPotentiallyAttachedTask(); + props.SetCompleted(); + } + FinishContinuations(); + return true; + } + + return false; + } + + // Allow multiple exceptions to be assigned to a promise-style task. + // This is useful when a TaskCompletionSource<T> stands in as a proxy + // for a "real" task (as we do in Unwrap(), ContinueWhenAny() and ContinueWhenAll()) + // and the "real" task ends up with multiple exceptions, which is possible when + // a task has children. + // + // Called from TaskCompletionSource<T>.SetException(IEnumerable<Exception>). + internal bool TrySetException(object exceptionObject) + { + Debug.Assert(m_action == null, "Task<T>.TrySetException(): non-null m_action"); + + // TCS.{Try}SetException() should have checked for this + Debug.Assert(exceptionObject != null, "Expected non-null exceptionObject argument"); + + // Only accept these types. + Debug.Assert( + (exceptionObject is Exception) || (exceptionObject is IEnumerable<Exception>) || + (exceptionObject is ExceptionDispatchInfo) || (exceptionObject is IEnumerable<ExceptionDispatchInfo>), + "Expected exceptionObject to be either Exception, ExceptionDispatchInfo, or IEnumerable<> of one of those"); + + bool returnValue = false; + + // "Reserve" the completion for this task, while making sure that: (1) No prior reservation + // has been made, (2) The result has not already been set, (3) An exception has not previously + // been recorded, and (4) Cancellation has not been requested. + // + // If the reservation is successful, then add the exception(s) and finish completion processing. + // + // The lazy initialization may not be strictly necessary, but I'd like to keep it here + // anyway. Some downstream logic may depend upon an inflated m_contingentProperties. + EnsureContingentPropertiesInitialized(); + if (AtomicStateUpdate( + TASK_STATE_COMPLETION_RESERVED, + TASK_STATE_COMPLETION_RESERVED | TASK_STATE_RAN_TO_COMPLETION | TASK_STATE_FAULTED | TASK_STATE_CANCELED)) + { + AddException(exceptionObject); // handles singleton exception or exception collection + Finish(false); + returnValue = true; + } + + return returnValue; + } + + // internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder + // If the tokenToRecord is not None, it will be stored onto the task. + // This method is only valid for promise tasks. + internal bool TrySetCanceled(CancellationToken tokenToRecord) + { + return TrySetCanceled(tokenToRecord, null); + } + + // internal helper function breaks out logic used by TaskCompletionSource and AsyncMethodBuilder + // If the tokenToRecord is not None, it will be stored onto the task. + // If the OperationCanceledException is not null, it will be stored into the task's exception holder. + // This method is only valid for promise tasks. + internal bool TrySetCanceled(CancellationToken tokenToRecord, object cancellationException) + { + Debug.Assert(m_action == null, "Task<T>.TrySetCanceled(): non-null m_action"); + Debug.Assert( + cancellationException == null || + cancellationException is OperationCanceledException || + (cancellationException as ExceptionDispatchInfo)?.SourceException is OperationCanceledException, + "Expected null or an OperationCanceledException"); + + bool returnValue = false; + + // "Reserve" the completion for this task, while making sure that: (1) No prior reservation + // has been made, (2) The result has not already been set, (3) An exception has not previously + // been recorded, and (4) Cancellation has not been requested. + // + // If the reservation is successful, then record the cancellation and finish completion processing. + if (AtomicStateUpdate( + TASK_STATE_COMPLETION_RESERVED, + TASK_STATE_COMPLETION_RESERVED | TASK_STATE_CANCELED | TASK_STATE_FAULTED | TASK_STATE_RAN_TO_COMPLETION)) + { + RecordInternalCancellationRequest(tokenToRecord, cancellationException); + CancellationCleanupLogic(); // perform cancellation cleanup actions + returnValue = true; + } + + return returnValue; + } + // // Continuation passing functionality (aka ContinueWith) @@ -5054,7 +5161,12 @@ namespace System.Threading.Tasks /// <returns>The faulted task.</returns> public static Task FromException(Exception exception) { - return FromException<VoidTaskResult>(exception); + if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); + + var task = new Task(); + bool succeeded = task.TrySetException(exception); + Debug.Assert(succeeded, "This should always succeed on a new task."); + return task; } /// <summary>Creates a <see cref="Task{TResult}"/> that's completed exceptionally with the specified exception.</summary> @@ -5092,13 +5204,26 @@ namespace System.Threading.Tasks return new Task<TResult>(true, default, TaskCreationOptions.None, cancellationToken); } + /// <summary>Creates a <see cref="Task"/> that's completed due to cancellation with the specified exception.</summary> + /// <param name="exception">The exception with which to complete the task.</param> + /// <returns>The canceled task.</returns> + internal static Task FromCanceled(OperationCanceledException exception) + { + Debug.Assert(exception != null); + + var task = new Task(); + bool succeeded = task.TrySetCanceled(exception.CancellationToken, exception); + Debug.Assert(succeeded, "This should always succeed on a new task."); + return task; + } + /// <summary>Creates a <see cref="Task{TResult}"/> that's completed due to cancellation with the specified exception.</summary> /// <typeparam name="TResult">The type of the result returned by the task.</typeparam> /// <param name="exception">The exception with which to complete the task.</param> /// <returns>The canceled task.</returns> - internal static Task<TResult> FromCancellation<TResult>(OperationCanceledException exception) + internal static Task<TResult> FromCanceled<TResult>(OperationCanceledException exception) { - if (exception == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.exception); + Debug.Assert(exception != null); var task = new Task<TResult>(); bool succeeded = task.TrySetCanceled(exception.CancellationToken, exception); @@ -5389,10 +5514,9 @@ namespace System.Threading.Tasks } /// <summary>Task that also stores the completion closure and logic for Task.Delay implementation.</summary> - private sealed class DelayPromise : Task<VoidTaskResult> + private sealed class DelayPromise : Task { internal DelayPromise(CancellationToken token) - : base() { this.Token = token; if (AsyncCausalityTracer.LoggingOn) @@ -5423,7 +5547,7 @@ namespace System.Threading.Tasks if (s_asyncDebuggingEnabled) RemoveFromActiveTasks(this); - setSucceeded = TrySetResult(default); + setSucceeded = TrySetResult(); } // If we set the value, also clean up. @@ -5555,10 +5679,10 @@ namespace System.Threading.Tasks new WhenAllPromise(tasks); } - // A Task<VoidTaskResult> that gets completed when all of its constituent tasks complete. + // A Task that gets completed when all of its constituent tasks complete. // Completion logic will analyze the antecedents in order to choose completion status. // This type allows us to replace this logic: - // Task<VoidTaskResult> promise = new Task<VoidTaskResult>(...); + // Task promise = new Task(...); // Action<Task> completionAction = delegate { <completion logic>}; // TaskFactory.CommonCWAllLogic(tasksCopy).AddCompletionAction(completionAction); // return promise; @@ -5567,7 +5691,7 @@ namespace System.Threading.Tasks // which saves a couple of allocations and enables debugger notification specialization. // // Used in InternalWhenAll(Task[]) - private sealed class WhenAllPromise : Task<VoidTaskResult>, ITaskCompletionAction + private sealed class WhenAllPromise : Task, ITaskCompletionAction { /// <summary> /// Stores all of the constituent tasks. Tasks clear themselves out of this @@ -5577,8 +5701,7 @@ namespace System.Threading.Tasks /// <summary>The number of tasks remaining to complete.</summary> private int m_count; - internal WhenAllPromise(Task[] tasks) : - base() + internal WhenAllPromise(Task[] tasks) { Debug.Assert(tasks != null, "Expected a non-null task array"); Debug.Assert(tasks.Length > 0, "Expected a non-zero length task array"); @@ -5656,7 +5779,7 @@ namespace System.Threading.Tasks if (s_asyncDebuggingEnabled) RemoveFromActiveTasks(this); - TrySetResult(default); + TrySetResult(); } } Debug.Assert(m_count >= 0, "Count should never go below 0"); diff --git a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs index 4d6a759605..256d4d71a2 100644 --- a/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs +++ b/src/System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs @@ -7,10 +7,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading.Tasks.Sources; - -#if !netstandard using Internal.Runtime.CompilerServices; -#endif namespace System.Threading.Tasks { @@ -60,19 +57,10 @@ namespace System.Threading.Tasks public readonly struct ValueTask : IEquatable<ValueTask> { /// <summary>A task canceled using `new CancellationToken(true)`.</summary> - private static readonly Task s_canceledTask = -#if netstandard - Task.Delay(Timeout.Infinite, new CancellationToken(canceled: true)); -#else - Task.FromCanceled(new CancellationToken(canceled: true)); -#endif + private static readonly Task s_canceledTask = Task.FromCanceled(new CancellationToken(canceled: true)); + /// <summary>A successfully completed task.</summary> - internal static Task CompletedTask -#if netstandard - { get; } = Task.Delay(0); -#else - => Task.CompletedTask; -#endif + internal static Task CompletedTask => Task.CompletedTask; /// <summary>null if representing a successful synchronous completion, otherwise a <see cref="Task"/> or a <see cref="IValueTaskSource"/>.</summary> internal readonly object _obj; @@ -190,45 +178,27 @@ namespace System.Threading.Tasks { if (status == ValueTaskSourceStatus.Canceled) { -#if !netstandard if (exc is OperationCanceledException oce) { - var task = new Task<VoidTaskResult>(); + var task = new Task(); task.TrySetCanceled(oce.CancellationToken, oce); return task; } -#endif + return s_canceledTask; } else { -#if netstandard - var tcs = new TaskCompletionSource<bool>(); - tcs.TrySetException(exc); - return tcs.Task; -#else return Task.FromException(exc); -#endif } } } - var m = new ValueTaskSourceAsTask(t, _token); - return -#if netstandard - m.Task; -#else - m; -#endif + return new ValueTaskSourceAsTask(t, _token); } /// <summary>Type used to create a <see cref="Task"/> to represent a <see cref="IValueTaskSource"/>.</summary> - private sealed class ValueTaskSourceAsTask : -#if netstandard - TaskCompletionSource<bool> -#else - Task<VoidTaskResult> -#endif + private sealed class ValueTaskSourceAsTask : Task { private static readonly Action<object> s_completionAction = state => { @@ -247,15 +217,12 @@ namespace System.Threading.Tasks try { source.GetResult(vtst._token); - vtst.TrySetResult(default); + vtst.TrySetResult(); } catch (Exception exc) { if (status == ValueTaskSourceStatus.Canceled) { -#if netstandard - vtst.TrySetCanceled(); -#else if (exc is OperationCanceledException oce) { vtst.TrySetCanceled(oce.CancellationToken, oce); @@ -264,7 +231,6 @@ namespace System.Threading.Tasks { vtst.TrySetCanceled(new CancellationToken(true)); } -#endif } else { @@ -325,12 +291,7 @@ namespace System.Threading.Tasks if (obj is Task t) { - return -#if netstandard - t.Status == TaskStatus.RanToCompletion; -#else - t.IsCompletedSuccessfully; -#endif + return t.IsCompletedSuccessfully; } return Unsafe.As<IValueTaskSource>(obj).GetStatus(_token) == ValueTaskSourceStatus.Succeeded; @@ -398,11 +359,7 @@ namespace System.Threading.Tasks { if (obj is Task t) { -#if netstandard - t.GetAwaiter().GetResult(); -#else TaskAwaiter.ValidateEnd(t); -#endif } else { @@ -569,12 +526,7 @@ namespace System.Threading.Tasks if (obj == null) { - return -#if netstandard - Task.FromResult(_result); -#else - AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result); -#endif + return AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result); } if (obj is Task<TResult> t) @@ -602,12 +554,7 @@ namespace System.Threading.Tasks { // Get the result of the operation and return a task for it. // If any exception occurred, propagate it - return -#if netstandard - Task.FromResult(t.GetResult(_token)); -#else - AsyncTaskMethodBuilder<TResult>.GetTaskForResult(t.GetResult(_token)); -#endif + return AsyncTaskMethodBuilder<TResult>.GetTaskForResult(t.GetResult(_token)); // If status is Faulted or Canceled, GetResult should throw. But // we can't guarantee every implementation will do the "right thing". @@ -618,59 +565,33 @@ namespace System.Threading.Tasks { if (status == ValueTaskSourceStatus.Canceled) { -#if !netstandard if (exc is OperationCanceledException oce) { var task = new Task<TResult>(); task.TrySetCanceled(oce.CancellationToken, oce); return task; } -#endif Task<TResult> canceledTask = s_canceledTask; if (canceledTask == null) { -#if netstandard - var tcs = new TaskCompletionSource<TResult>(); - tcs.TrySetCanceled(); - canceledTask = tcs.Task; -#else - canceledTask = Task.FromCanceled<TResult>(new CancellationToken(true)); -#endif // Benign race condition to initialize cached task, as identity doesn't matter. - s_canceledTask = canceledTask; + s_canceledTask = Task.FromCanceled<TResult>(new CancellationToken(true)); } return canceledTask; } else { -#if netstandard - var tcs = new TaskCompletionSource<TResult>(); - tcs.TrySetException(exc); - return tcs.Task; -#else return Task.FromException<TResult>(exc); -#endif } } } - var m = new ValueTaskSourceAsTask(t, _token); - return -#if netstandard - m.Task; -#else - m; -#endif + return new ValueTaskSourceAsTask(t, _token); } /// <summary>Type used to create a <see cref="Task{TResult}"/> to represent a <see cref="IValueTaskSource{TResult}"/>.</summary> - private sealed class ValueTaskSourceAsTask : -#if netstandard - TaskCompletionSource<TResult> -#else - Task<TResult> -#endif + private sealed class ValueTaskSourceAsTask : Task<TResult> { private static readonly Action<object> s_completionAction = state => { @@ -694,9 +615,6 @@ namespace System.Threading.Tasks { if (status == ValueTaskSourceStatus.Canceled) { -#if netstandard - vtst.TrySetCanceled(); -#else if (exc is OperationCanceledException oce) { vtst.TrySetCanceled(oce.CancellationToken, oce); @@ -705,7 +623,6 @@ namespace System.Threading.Tasks { vtst.TrySetCanceled(new CancellationToken(true)); } -#endif } else { @@ -766,12 +683,7 @@ namespace System.Threading.Tasks if (obj is Task<TResult> t) { - return -#if netstandard - t.Status == TaskStatus.RanToCompletion; -#else - t.IsCompletedSuccessfully; -#endif + return t.IsCompletedSuccessfully; } return Unsafe.As<IValueTaskSource<TResult>>(obj).GetStatus(_token) == ValueTaskSourceStatus.Succeeded; @@ -843,12 +755,8 @@ namespace System.Threading.Tasks if (obj is Task<TResult> t) { -#if netstandard - return t.GetAwaiter().GetResult(); -#else TaskAwaiter.ValidateEnd(t); return t.ResultOnSuccess; -#endif } return Unsafe.As<IValueTaskSource<TResult>>(obj).GetResult(_token); |