Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suppress ExecutionContext flow in more awaiters #689

Merged
merged 1 commit into from
Oct 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}
AArnott marked this conversation as resolved.
Show resolved Hide resolved
#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