in src/Microsoft.VisualStudio.Threading/CancellableJoinComputation.cs [55:133]
internal CancellableJoinComputation(Func<CancellationToken, Task> taskFactory, bool allowCancelled)
{
Requires.NotNull(taskFactory, nameof(taskFactory));
if (allowCancelled)
{
this.isCancellationAllowed = true;
this.combinedCancellationTokenSource = new CancellationTokenSource();
this.joinedWaitingList = new List<WaitingCancellationStatus>(capacity: 2);
}
this.InnerTask = taskFactory(this.combinedCancellationTokenSource?.Token ?? CancellationToken.None);
if (allowCancelled)
{
// Note: this continuation is chained asynchronously to prevent being inlined when we trigger the combined cancellation token.
this.InnerTask.ContinueWith(
(t, s) =>
{
var me = (CancellableJoinComputation)s!;
List<WaitingCancellationStatus> allWaitingTasks;
CancellationTokenSource? combinedCancellationTokenSource;
lock (me.syncObject)
{
Assumes.NotNull(me.joinedWaitingList);
allWaitingTasks = me.joinedWaitingList;
combinedCancellationTokenSource = me.combinedCancellationTokenSource;
me.joinedWaitingList = null;
me.combinedCancellationTokenSource = null;
}
combinedCancellationTokenSource?.Dispose();
if (t.IsCanceled)
{
for (int i = 0; i < allWaitingTasks.Count; i++)
{
WaitingCancellationStatus status = allWaitingTasks[i];
if (status.CancellationToken.IsCancellationRequested)
{
status.TrySetCanceled(status.CancellationToken);
}
else
{
status.TrySetCanceled();
}
status.Dispose();
}
}
else if (t.IsFaulted)
{
System.Collections.ObjectModel.ReadOnlyCollection<Exception> exceptions = t.Exception!.InnerExceptions;
for (int i = 0; i < allWaitingTasks.Count; i++)
{
WaitingCancellationStatus status = allWaitingTasks[i];
status.TrySetException(exceptions);
status.Dispose();
}
}
else
{
for (int i = 0; i < allWaitingTasks.Count; i++)
{
WaitingCancellationStatus status = allWaitingTasks[i];
status.TrySetResult(true);
status.Dispose();
}
}
},
this,
CancellationToken.None,
TaskContinuationOptions.RunContinuationsAsynchronously,
TaskScheduler.Default).Forget();
}
}