in src/Microsoft.VisualStudio.Threading/JoinableTask.cs [1096:1175]
private bool TryDequeueSelfOrDependencies(bool onMainThread, ref HashSet<IJoinableTaskDependent>? visited, [NotNullWhen(true)] out SingleExecuteProtector? work, out Task? tryAgainAfter)
{
using (this.JoinableTaskContext.NoMessagePumpSynchronizationContext.Apply())
{
lock (this.JoinableTaskContext.SyncContextLock)
{
if (this.IsFullyCompleted)
{
work = null;
tryAgainAfter = null;
return false;
}
if (this.pendingEventCount > 0)
{
this.pendingEventCount--;
if (this.pendingEventSource is object)
{
if (this.pendingEventSource.TryGetTarget(out JoinableTask? pendingSource) &&
(pendingSource == this ||
(!this.HasPotentialUnreachableDependents && JoinableTaskDependencyGraph.IsDependingSynchronousTask(pendingSource, this))))
{
ExecutionQueue? queue = onMainThread ? pendingSource.mainThreadQueue : pendingSource.threadPoolQueue;
if (queue is object && !queue.IsCompleted && queue.TryDequeue(out work))
{
if (queue.Count == 0)
{
this.pendingEventSource = null;
}
tryAgainAfter = null;
return true;
}
}
this.pendingEventSource = null;
}
if (visited is null)
{
visited = new HashSet<IJoinableTaskDependent>();
}
else
{
visited.Clear();
}
bool foundWork = TryDequeueSelfOrDependencies(this, onMainThread, visited, out work);
HashSet<IJoinableTaskDependent>? visitedNodes = visited;
if (this.HasPotentialUnreachableDependents)
{
// We walked the dependencies tree and use this information to update the PotentialUnreachableDependents list.
this.PotentialUnreachableDependents!.RemoveWhere(n => visitedNodes.Contains(n));
if (!foundWork && this.PotentialUnreachableDependents.Count > 0)
{
JoinableTaskDependencyGraph.RemoveUnreachableDependentItems(this, this.PotentialUnreachableDependents, visitedNodes);
this.PotentialUnreachableDependents.Clear();
}
}
if (foundWork)
{
Assumes.NotNull(work);
tryAgainAfter = null;
return true;
}
}
this.pendingEventCount = 0;
work = null;
tryAgainAfter = this.IsCompleteRequested ? null : this.QueueNeedProcessEvent;
return false;
}
}
}