Skip to content

Commit

Permalink
Suppress ExecutionContext flow in more awaiters
Browse files Browse the repository at this point in the history
  • Loading branch information
AArnott committed Sep 30, 2020
1 parent babb79a commit 44d9db7
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 5 deletions.
5 changes: 3 additions & 2 deletions src/Microsoft.VisualStudio.Threading/AsyncReaderWriterLock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2525,9 +2525,10 @@ private void OnCompleted(Action continuation, bool flowExecutionContext)
}

bool restoreFlow = !flowExecutionContext && !ExecutionContext.IsFlowSuppressed();
AsyncFlowControl flowControl = default;
if (restoreFlow)
{
ExecutionContext.SuppressFlow();
flowControl = ExecutionContext.SuppressFlow();
}

try
Expand All @@ -2549,7 +2550,7 @@ private void OnCompleted(Action continuation, bool flowExecutionContext)
{
if (restoreFlow)
{
ExecutionContext.RestoreFlow();
flowControl.Dispose();
}
}
}
Expand Down
59 changes: 56 additions & 3 deletions src/Microsoft.VisualStudio.Threading/AwaitExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,21 @@ public void UnsafeOnCompleted(Action continuation)
}
else
{
// There is no API for scheduling a Task without capturing the ExecutionContext.
#if NETFRAMEWORK // Only bother suppressing flow on .NET Framework where the perf would improve from doing so.
if (ExecutionContext.IsFlowSuppressed())
{
Task.Factory.StartNew(continuation, CancellationToken.None, TaskCreationOptions.None, this.scheduler);
}
else
{
using (ExecutionContext.SuppressFlow())
{
Task.Factory.StartNew(continuation, CancellationToken.None, TaskCreationOptions.None, this.scheduler);
}
}
#else
Task.Factory.StartNew(continuation, CancellationToken.None, TaskCreationOptions.None, this.scheduler);
#endif
}
}

Expand Down Expand Up @@ -567,7 +580,7 @@ public ExecuteContinuationSynchronouslyAwaitable(Task antecedent)
/// A Task awaiter that has affinity to executing callbacks synchronously on the completing callstack.
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "Awaitables are not compared.")]
public readonly struct ExecuteContinuationSynchronouslyAwaiter : INotifyCompletion
public readonly struct ExecuteContinuationSynchronouslyAwaiter : ICriticalNotifyCompletion
{
/// <summary>
/// The task whose completion will execute the continuation.
Expand Down Expand Up @@ -609,6 +622,26 @@ public void OnCompleted(Action continuation)
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}

/// <inheritdoc cref="OnCompleted(Action)"/>
public void UnsafeOnCompleted(Action continuation)
{
#if NETFRAMEWORK // Only bother suppressing flow on .NET Framework where the perf would improve from doing so.
if (ExecutionContext.IsFlowSuppressed())
{
this.OnCompleted(continuation);
}
else
{
using (ExecutionContext.SuppressFlow())
{
this.OnCompleted(continuation);
}
}
#else
this.OnCompleted(continuation);
#endif
}
}

/// <summary>
Expand Down Expand Up @@ -645,7 +678,7 @@ public ExecuteContinuationSynchronouslyAwaitable(Task<T> antecedent)
/// </summary>
/// <typeparam name="T">The type of value returned by the awaited <see cref="Task"/>.</typeparam>
[SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes", Justification = "Awaitables are not compared.")]
public readonly struct ExecuteContinuationSynchronouslyAwaiter<T> : INotifyCompletion
public readonly struct ExecuteContinuationSynchronouslyAwaiter<T> : ICriticalNotifyCompletion
{
/// <summary>
/// The task whose completion will execute the continuation.
Expand Down Expand Up @@ -687,6 +720,26 @@ public void OnCompleted(Action continuation)
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}

/// <inheritdoc cref="OnCompleted(Action)"/>
public void UnsafeOnCompleted(Action continuation)
{
#if NETFRAMEWORK // Only bother suppressing flow on .NET Framework where the perf would improve from doing so.
if (ExecutionContext.IsFlowSuppressed())
{
this.OnCompleted(continuation);
}
else
{
using (ExecutionContext.SuppressFlow())
{
this.OnCompleted(continuation);
}
}
#else
this.OnCompleted(continuation);
#endif
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.GetRe
Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.IsCompleted.get -> bool
Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.OnCompleted(System.Action! continuation) -> void
Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.UnsafeOnCompleted(System.Action! continuation) -> void
Microsoft.VisualStudio.Threading.AwaitExtensions.ExecuteContinuationSynchronouslyAwaiter.UnsafeOnCompleted(System.Action! continuation) -> void
Microsoft.VisualStudio.Threading.AwaitExtensions.ExecuteContinuationSynchronouslyAwaiter<T>.UnsafeOnCompleted(System.Action! continuation) -> void
static Microsoft.VisualStudio.Threading.AwaitExtensions.ConfigureAwaitForAggregateException(this System.Threading.Tasks.Task! task, bool continueOnCapturedContext = true) -> Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaitable
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.GetRe
Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.IsCompleted.get -> bool
Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.OnCompleted(System.Action! continuation) -> void
Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.UnsafeOnCompleted(System.Action! continuation) -> void
Microsoft.VisualStudio.Threading.AwaitExtensions.ExecuteContinuationSynchronouslyAwaiter.UnsafeOnCompleted(System.Action! continuation) -> void
Microsoft.VisualStudio.Threading.AwaitExtensions.ExecuteContinuationSynchronouslyAwaiter<T>.UnsafeOnCompleted(System.Action! continuation) -> void
static Microsoft.VisualStudio.Threading.AwaitExtensions.ConfigureAwaitForAggregateException(this System.Threading.Tasks.Task! task, bool continueOnCapturedContext = true) -> Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaitable
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.GetRe
Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.IsCompleted.get -> bool
Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.OnCompleted(System.Action! continuation) -> void
Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaiter.UnsafeOnCompleted(System.Action! continuation) -> void
Microsoft.VisualStudio.Threading.AwaitExtensions.ExecuteContinuationSynchronouslyAwaiter.UnsafeOnCompleted(System.Action! continuation) -> void
Microsoft.VisualStudio.Threading.AwaitExtensions.ExecuteContinuationSynchronouslyAwaiter<T>.UnsafeOnCompleted(System.Action! continuation) -> void
static Microsoft.VisualStudio.Threading.AwaitExtensions.ConfigureAwaitForAggregateException(this System.Threading.Tasks.Task! task, bool continueOnCapturedContext = true) -> Microsoft.VisualStudio.Threading.AwaitExtensions.AggregateExceptionAwaitable

0 comments on commit 44d9db7

Please sign in to comment.