Skip to content

Commit

Permalink
Address PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
stephentoub committed Jun 3, 2023
1 parent e754990 commit 74a5fc9
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace System.Threading.Tasks
{
/// <summary>Options to control the behavior of an await on a <see cref="Task"/>.</summary>
/// <summary>Options to control behavior when awaiting.</summary>
[Flags]
public enum ConfigureAwaitOptions
{
Expand All @@ -21,11 +21,13 @@ public enum ConfigureAwaitOptions
/// <remarks>
/// If there is no such context/scheduler, or if this option is not specified, the thread on
/// which the continuation is invoked is unspecified and left up to the determination of the system.
/// <see cref="Task.ConfigureAwait(ConfigureAwaitOptions)"/> with a <see cref="ContinueOnCapturedContext"/> argument
/// behaves identically to using <see cref="Task.ConfigureAwait(bool)"/> with a <see langword="true"/> argument.
/// </remarks>
ContinueOnCapturedContext = 0x1,

/// <summary>
/// Avoids throwing an exception at the completion of an await on a <see cref="Task"/> that ends
/// Avoids throwing an exception at the completion of awaiting a <see cref="Task"/> that ends
/// in the <see cref="TaskStatus.Faulted"/> or <see cref="TaskStatus.Canceled"/> state.
/// </summary>
/// <remarks>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ public void ConfigureAwaitOptions_Invalid(ConfigureAwaitOptions options)
public void ConfigureAwaitOptions_SuppressThrowingUnsupportedOnGenericTask()
{
AssertExtensions.Throws<ArgumentOutOfRangeException>("options", () => Task.FromResult(true).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing));
AssertExtensions.Throws<ArgumentOutOfRangeException>("options", () => Task.FromResult(true).ConfigureAwait((ConfigureAwaitOptions)0x7));
AssertExtensions.Throws<ArgumentOutOfRangeException>("options", () => Task.FromResult(true).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing | ConfigureAwaitOptions.ForceYielding));
}

[Theory]
Expand All @@ -593,7 +593,7 @@ public void ConfigureAwaitOptions_ForceYielding_IsCompletedAlwaysFalse(Configure
}
}

[Fact]
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
public void ConfigureAwaitOptions_SuppressThrowing_NoExceptionsAreThrown()
{
Task t;
Expand All @@ -611,6 +611,58 @@ public void ConfigureAwaitOptions_SuppressThrowing_NoExceptionsAreThrown()
Assert.Throws<FormatException>(() => t.ConfigureAwait(ConfigureAwaitOptions.ContinueOnCapturedContext | ConfigureAwaitOptions.ForceYielding).GetAwaiter().GetResult());
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
[InlineData(false, ConfigureAwaitOptions.None)]
[InlineData(false, ConfigureAwaitOptions.ContinueOnCapturedContext)]
[InlineData(true, ConfigureAwaitOptions.None)]
[InlineData(true, ConfigureAwaitOptions.ContinueOnCapturedContext)]
public static void ConfigureAwaitOptions_ContinueOnCapturedContext_QueuesAccordingly(bool generic, ConfigureAwaitOptions options)
{
SynchronizationContext origCtx = SynchronizationContext.Current;
try
{
// Create a context that tracks operations, and set it as current
var validateCtx = new ValidateCorrectContextSynchronizationContext();
Assert.Equal(0, validateCtx.PostCount);
SynchronizationContext.SetSynchronizationContext(validateCtx);

// Create a not-completed task and get an awaiter for it
var mres = new ManualResetEventSlim();
var tcs = new TaskCompletionSource<object>();

// Hook up a callback
bool postedInContext = false;
Action callback = () =>
{
postedInContext = ValidateCorrectContextSynchronizationContext.t_isPostedInContext;
mres.Set();
};
if (generic)
{
tcs.Task.ConfigureAwait(options).GetAwaiter().OnCompleted(callback);
}
else
{
((Task)tcs.Task).ConfigureAwait(options).GetAwaiter().OnCompleted(callback);
}
Assert.False(mres.IsSet, "Callback should not yet have run.");

// Complete the task in another context and wait for the callback to run
Task.Run(() => tcs.SetResult(null));
mres.Wait();

// Validate the callback ran and in the correct context
bool shouldHavePosted = options == ConfigureAwaitOptions.ContinueOnCapturedContext;
Assert.Equal(shouldHavePosted ? 1 : 0, validateCtx.PostCount);
Assert.Equal(shouldHavePosted, postedInContext);
}
finally
{
// Reset back to the original context
SynchronizationContext.SetSynchronizationContext(origCtx);
}
}

private static int LineNumber([CallerLineNumber]int lineNumber = 0) => lineNumber;

private class ValidateCorrectContextSynchronizationContext : SynchronizationContext
Expand Down

0 comments on commit 74a5fc9

Please sign in to comment.