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
Fix AsyncValueTaskMethodBuilder.Start behavior with ExecutionContext
Browse files Browse the repository at this point in the history
  • Loading branch information
stephentoub committed Jul 21, 2016
1 parent 0458fc9 commit 309b2d2
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,7 @@ public static AsyncValueTaskMethodBuilder<TResult> Create() =>
/// <param name="stateMachine">The state machine instance, passed by reference.</param>
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
// We can't provide the same semantics as AsyncTaskMethodBuilder with regards to
// ExecutionContext as we don't have access to any of the relevant methods. We also can't
// call _methodBuilder.Start, as then we'll always end up creating a Task<T>. At the moment the
// only solution is to skip the ExecutionContext barrier that we'd want to put in place.
stateMachine.MoveNext();
_methodBuilder.Start(ref stateMachine); // will provide the right ExecutionContext semantics
}

/// <summary>Associates the builder with the specified state machine.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,40 @@ public void SetStateMachine_InvalidArgument_ThrowsException()
b.SetStateMachine(new DelegateStateMachine());
}

[Fact]
public void Start_ExecutionContextChangesInMoveNextDontFlowOut()
{
var al = new AsyncLocal<int> { Value = 0 };
int calls = 0;

var dsm = new DelegateStateMachine
{
MoveNextDelegate = () =>
{
al.Value++;
calls++;
}
};

dsm.MoveNext();
Assert.Equal(1, al.Value);
Assert.Equal(1, calls);

dsm.MoveNext();
Assert.Equal(2, al.Value);
Assert.Equal(2, calls);

AsyncValueTaskMethodBuilder<int> b = ValueTask<int>.CreateAsyncMethodBuilder();
b.Start(ref dsm);
Assert.Equal(2, al.Value); // change should not be visible
Assert.Equal(3, calls);

// Make sure we've not caused the Task to be allocated
b.SetResult(42);
ValueTask<int> vt = b.Task;
Assert.NotSame(vt.AsTask(), vt.AsTask());
}

private struct DelegateStateMachine : IAsyncStateMachine
{
internal Action MoveNextDelegate;
Expand Down

0 comments on commit 309b2d2

Please sign in to comment.