Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Add token to IValueTaskSource
Browse files Browse the repository at this point in the history
  • Loading branch information
stephentoub committed Mar 1, 2018
1 parent b52bb27 commit 34a565f
Show file tree
Hide file tree
Showing 21 changed files with 1,787 additions and 363 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,108 @@

namespace System.Runtime.CompilerServices
{
/// <summary>Represents a builder for asynchronous methods that return a <see cref="ValueTask"/>.</summary>
[StructLayout(LayoutKind.Auto)]
public struct AsyncValueTaskMethodBuilder
{
/// <summary>The <see cref="AsyncTaskMethodBuilder"/> to which most operations are delegated.</summary>
private AsyncTaskMethodBuilder _methodBuilder; // mutable struct; do not make it readonly
/// <summary>true if completed synchronously and successfully; otherwise, false.</summary>
private bool _haveResult;
/// <summary>true if the builder should be used for setting/getting the result; otherwise, false.</summary>
private bool _useBuilder;

/// <summary>Creates an instance of the <see cref="AsyncValueTaskMethodBuilder"/> struct.</summary>
/// <returns>The initialized instance.</returns>
public static AsyncValueTaskMethodBuilder Create() =>
#if CORERT
// corert's AsyncTaskMethodBuilder.Create() currently does additional debugger-related
// work, so we need to delegate to it.
new AsyncValueTaskMethodBuilder() { _methodBuilder = AsyncTaskMethodBuilder.Create() };
#else
// _methodBuilder should be initialized to AsyncTaskMethodBuilder.Create(), but on coreclr
// that Create() is a nop, so we can just return the default here.
default;
#endif

/// <summary>Begins running the builder with the associated state machine.</summary>
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
/// <param name="stateMachine">The state machine instance, passed by reference.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine =>
// will provide the right ExecutionContext semantics
#if netstandard
_methodBuilder.Start(ref stateMachine);
#else
AsyncMethodBuilderCore.Start(ref stateMachine);
#endif

/// <summary>Associates the builder with the specified state machine.</summary>
/// <param name="stateMachine">The state machine instance to associate with the builder.</param>
public void SetStateMachine(IAsyncStateMachine stateMachine) => _methodBuilder.SetStateMachine(stateMachine);

/// <summary>Marks the task as successfully completed.</summary>
public void SetResult()
{
if (_useBuilder)
{
_methodBuilder.SetResult();
}
else
{
_haveResult = true;
}
}

/// <summary>Marks the task as failed and binds the specified exception to the task.</summary>
/// <param name="exception">The exception to bind to the task.</param>
public void SetException(Exception exception) => _methodBuilder.SetException(exception);

/// <summary>Gets the task for this builder.</summary>
public ValueTask Task
{
get
{
if (_haveResult)
{
return default;
}
else
{
_useBuilder = true;
return new ValueTask(_methodBuilder.Task);
}
}
}

/// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
/// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
/// <param name="awaiter">the awaiter</param>
/// <param name="stateMachine">The state machine.</param>
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
_useBuilder = true;
_methodBuilder.AwaitOnCompleted(ref awaiter, ref stateMachine);
}

/// <summary>Schedules the state machine to proceed to the next action when the specified awaiter completes.</summary>
/// <typeparam name="TAwaiter">The type of the awaiter.</typeparam>
/// <typeparam name="TStateMachine">The type of the state machine.</typeparam>
/// <param name="awaiter">the awaiter</param>
/// <param name="stateMachine">The state machine.</param>
[SecuritySafeCritical]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
_useBuilder = true;
_methodBuilder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine);
}
}

/// <summary>Represents a builder for asynchronous methods that returns a <see cref="ValueTask{TResult}"/>.</summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
[StructLayout(LayoutKind.Auto)]
Expand All @@ -32,7 +134,7 @@ public static AsyncValueTaskMethodBuilder<TResult> Create() =>
#else
// _methodBuilder should be initialized to AsyncTaskMethodBuilder<TResult>.Create(), but on coreclr
// that Create() is a nop, so we can just return the default here.
default(AsyncValueTaskMethodBuilder<TResult>);
default;
#endif

/// <summary>Begins running the builder with the associated state machine.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,88 +5,212 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
#if !netstandard
using Internal.Runtime.CompilerServices;
#endif

namespace System.Runtime.CompilerServices
{
/// <summary>Provides an awaitable type that enables configured awaits on a <see cref="ValueTask"/>.</summary>
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredValueTaskAwaitable
{
/// <summary>The wrapped <see cref="Task"/>.</summary>
private readonly ValueTask _value;

/// <summary>Initializes the awaitable.</summary>
/// <param name="value">The wrapped <see cref="ValueTask"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ConfiguredValueTaskAwaitable(ValueTask value) => _value = value;

/// <summary>Returns an awaiter for this <see cref="ConfiguredValueTaskAwaitable"/> instance.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(_value);

/// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable"/>.</summary>
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion
#if CORECLR
, IValueTaskAwaiter
#endif
{
/// <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 ConfiguredValueTaskAwaiter(ValueTask value) => _value = value;

/// <summary>Gets whether the <see cref="ConfiguredValueTaskAwaitable"/> has completed.</summary>
public bool IsCompleted
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _value.IsCompleted;
}

/// <summary>Gets the result of the ValueTask.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[StackTraceHidden]
public void GetResult() => _value.ThrowIfCompletedUnsuccessfully();

/// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable"/>.</summary>
public void OnCompleted(Action continuation)
{
if (_value.ObjectIsTask)
{
_value.UnsafeTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
}
else if (_value._obj != null)
{
_value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
ValueTaskSourceOnCompletedFlags.FlowExecutionContext |
(_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None));
}
else
{
Task.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
}
}

/// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable"/>.</summary>
public void UnsafeOnCompleted(Action continuation)
{
if (_value.ObjectIsTask)
{
_value.UnsafeTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
}
else if (_value._obj != null)
{
_value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
}
else
{
Task.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
}
}

#if CORECLR
void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box)
{
if (_value.ObjectIsTask)
{
TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeTask, box, _value.ContinueOnCapturedContext);
}
else if (_value._obj != null)
{
_value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token,
_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
}
else
{
TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value.ContinueOnCapturedContext);
}
}
#endif
}
}

/// <summary>Provides an awaitable type that enables configured awaits on a <see cref="ValueTask{TResult}"/>.</summary>
/// <typeparam name="TResult">The type of the result produced.</typeparam>
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredValueTaskAwaitable<TResult>
{
/// <summary>The wrapped <see cref="ValueTask{TResult}"/>.</summary>
private readonly ValueTask<TResult> _value;
/// <summary>true to attempt to marshal the continuation back to the original context captured; otherwise, false.</summary>
private readonly bool _continueOnCapturedContext;

/// <summary>Initializes the awaitable.</summary>
/// <param name="value">The wrapped <see cref="ValueTask{TResult}"/>.</param>
/// <param name="continueOnCapturedContext">
/// true to attempt to marshal the continuation back to the original synchronization context captured; otherwise, false.
/// </param>
internal ConfiguredValueTaskAwaitable(ValueTask<TResult> value, bool continueOnCapturedContext)
{
_value = value;
_continueOnCapturedContext = continueOnCapturedContext;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ConfiguredValueTaskAwaitable(ValueTask<TResult> value) => _value = value;

/// <summary>Returns an awaiter for this <see cref="ConfiguredValueTaskAwaitable{TResult}"/> instance.</summary>
public ConfiguredValueTaskAwaiter GetAwaiter() =>
new ConfiguredValueTaskAwaiter(_value, _continueOnCapturedContext);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ConfiguredValueTaskAwaiter GetAwaiter() => new ConfiguredValueTaskAwaiter(_value);

/// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
[StructLayout(LayoutKind.Auto)]
public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IConfiguredValueTaskAwaiter
public readonly struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion
#if CORECLR
, IValueTaskAwaiter
#endif
{
/// <summary>The value being awaited.</summary>
private readonly ValueTask<TResult> _value;
/// <summary>The value to pass to ConfigureAwait.</summary>
internal readonly bool _continueOnCapturedContext;

/// <summary>Initializes the awaiter.</summary>
/// <param name="value">The value to be awaited.</param>
/// <param name="continueOnCapturedContext">The value to pass to ConfigureAwait.</param>
internal ConfiguredValueTaskAwaiter(ValueTask<TResult> value, bool continueOnCapturedContext)
{
_value = value;
_continueOnCapturedContext = continueOnCapturedContext;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ConfiguredValueTaskAwaiter(ValueTask<TResult> value) => _value = value;

/// <summary>Gets whether the <see cref="ConfiguredValueTaskAwaitable{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>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[StackTraceHidden]
public TResult GetResult() =>
_value._task == null ?
_value._result :
_value._task.GetAwaiter().GetResult();
public TResult GetResult() => _value.Result;

/// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
public void OnCompleted(Action continuation) =>
_value.AsTask().ConfigureAwait(_continueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
public void OnCompleted(Action continuation)
{
if (_value.ObjectIsTask)
{
_value.UnsafeTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
}
else if (_value._obj != null)
{
_value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
ValueTaskSourceOnCompletedFlags.FlowExecutionContext |
(_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None));
}
else
{
Task.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().OnCompleted(continuation);
}
}

/// <summary>Schedules the continuation action for the <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
public void UnsafeOnCompleted(Action continuation) =>
_value.AsTask().ConfigureAwait(_continueOnCapturedContext).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.UnsafeTask.ConfigureAwait(_value.ContinueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation);
}
else if (_value._obj != null)
{
_value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
}
else
{
Task.CompletedTask.ConfigureAwait(_value.ContinueOnCapturedContext).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 IConfiguredValueTaskAwaiter.GetTask(out bool continueOnCapturedContext)
#if CORECLR
void IValueTaskAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox box)
{
continueOnCapturedContext = _continueOnCapturedContext;
return _value.AsTaskExpectNonNull();
if (_value.ObjectIsTask)
{
TaskAwaiter.UnsafeOnCompletedInternal(_value.UnsafeTask, box, _value.ContinueOnCapturedContext);
}
else if (_value._obj != null)
{
_value.UnsafeValueTaskSource.OnCompleted(ValueTaskAwaiter.s_invokeAsyncStateMachineBox, box, _value._token,
_value.ContinueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
}
else
{
TaskAwaiter.UnsafeOnCompletedInternal(Task.CompletedTask, box, _value.ContinueOnCapturedContext);
}
}
#endif
}
}

/// <summary>
/// Internal interface used to enable extract the Task from arbitrary configured ValueTask awaiters.
/// </summary>
internal interface IConfiguredValueTaskAwaiter
{
Task GetTask(out bool continueOnCapturedContext);
}
}
Loading

0 comments on commit 34a565f

Please sign in to comment.