Skip to content

Commit 8eff3b1

Browse files
committed
Remove a first chance exception for normal cancellation
This exception only occurs in integration test scenarios, but the internal performance test harness is not able to eliminate this false positive automatically.
1 parent 7f889ac commit 8eff3b1

File tree

1 file changed

+31
-14
lines changed

1 file changed

+31
-14
lines changed

src/Workspaces/Core/Portable/Shared/TestHooks/AsynchronousOperationListener.cs

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,33 +40,50 @@ public AsynchronousOperationListener(string featureName, bool enableDiagnosticTo
4040
TrackActiveTokens = Debugger.IsAttached || enableDiagnosticTokens;
4141
}
4242

43-
public async Task<bool> Delay(TimeSpan delay, CancellationToken cancellationToken)
43+
public Task<bool> Delay(TimeSpan delay, CancellationToken cancellationToken)
4444
{
45-
cancellationToken.ThrowIfCancellationRequested();
45+
if (cancellationToken.IsCancellationRequested)
46+
return Task.FromCanceled<bool>(cancellationToken);
4647

4748
var expeditedDelayCancellationToken = _expeditedDelayCancellationTokenSource.Token;
4849
if (expeditedDelayCancellationToken.IsCancellationRequested)
4950
{
5051
// The operation is already being expedited
51-
return false;
52+
return SpecializedTasks.False;
5253
}
5354

54-
using var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, expeditedDelayCancellationToken);
55+
var cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, expeditedDelayCancellationToken);
5556

5657
var delayTask = Task.Delay(delay, cancellationTokenSource.Token);
57-
await delayTask.NoThrowAwaitableInternal(false);
58-
59-
if (delayTask.Status != TaskStatus.RanToCompletion)
58+
if (delayTask.IsCompleted)
6059
{
61-
cancellationToken.ThrowIfCancellationRequested();
62-
63-
// The cancellation only occurred due to a request to expedite the operation.
64-
// Don't use try-catch to reduce the number of first chance exceptions.
65-
if (expeditedDelayCancellationToken.IsCancellationRequested)
66-
return false;
60+
cancellationTokenSource.Dispose();
61+
if (delayTask.Status == TaskStatus.RanToCompletion)
62+
return SpecializedTasks.True;
63+
else if (cancellationToken.IsCancellationRequested)
64+
return Task.FromCanceled<bool>(cancellationToken);
65+
else
66+
return SpecializedTasks.False;
6767
}
6868

69-
return true;
69+
return DelaySlow(delayTask, cancellationTokenSource, cancellationToken);
70+
71+
static Task<bool> DelaySlow(Task delayTask, CancellationTokenSource cancellationTokenSourceToDispose, CancellationToken cancellationToken)
72+
{
73+
return delayTask.ContinueWith(
74+
task =>
75+
{
76+
if (task.Status == TaskStatus.RanToCompletion)
77+
return SpecializedTasks.True;
78+
else if (cancellationToken.IsCancellationRequested)
79+
return Task.FromCanceled<bool>(cancellationToken);
80+
else
81+
return SpecializedTasks.False;
82+
},
83+
CancellationToken.None,
84+
TaskContinuationOptions.ExecuteSynchronously,
85+
TaskScheduler.Default).Unwrap();
86+
}
7087
}
7188

7289
public IAsyncToken BeginAsyncOperation(string name, object? tag = null, [CallerFilePath] string filePath = "", [CallerLineNumber] int lineNumber = 0)

0 commit comments

Comments
 (0)