in src/Microsoft.VisualStudio.Threading/JoinableTask.cs [637:776]
internal void Post(SendOrPostCallback d, object? state, bool mainThreadAffinitized)
{
using (this.JoinableTaskContext.NoMessagePumpSynchronizationContext.Apply())
{
SingleExecuteProtector? wrapper = null;
List<AsyncManualResetEvent>? eventsNeedNotify = null; // initialized if we should pulse it at the end of the method
bool postToFactory = false;
bool isCompleteRequested;
bool synchronouslyBlockingMainThread;
lock (this.JoinableTaskContext.SyncContextLock)
{
isCompleteRequested = this.IsCompleteRequested;
synchronouslyBlockingMainThread = this.SynchronouslyBlockingMainThread;
}
if (isCompleteRequested)
{
// This job has already been marked for completion.
// We need to forward the work to the fallback mechanisms.
postToFactory = true;
}
else
{
bool mainThreadQueueUpdated = false;
bool backgroundThreadQueueUpdated = false;
wrapper = SingleExecuteProtector.Create(this, d, state);
if (ThreadingEventSource.Instance.IsEnabled())
{
ThreadingEventSource.Instance.PostExecutionStart(wrapper.GetHashCode(), mainThreadAffinitized);
}
if (mainThreadAffinitized && !synchronouslyBlockingMainThread)
{
wrapper.RaiseTransitioningEvents();
}
lock (this.JoinableTaskContext.SyncContextLock)
{
if (mainThreadAffinitized)
{
if (this.mainThreadQueue is null)
{
this.mainThreadQueue = new ExecutionQueue(this);
}
// Try to post the message here, but we'll also post to the underlying sync context
// so if this fails (because the operation has completed) we'll still get the work
// done eventually.
this.mainThreadQueue.TryEnqueue(wrapper);
mainThreadQueueUpdated = true;
}
else
{
if (this.SynchronouslyBlockingThreadPool)
{
if (this.threadPoolQueue is null)
{
this.threadPoolQueue = new ExecutionQueue(this);
}
backgroundThreadQueueUpdated = this.threadPoolQueue.TryEnqueue(wrapper);
if (!backgroundThreadQueueUpdated)
{
ThreadPool.QueueUserWorkItem(SingleExecuteProtector.ExecuteOnceWaitCallback, wrapper);
}
}
else
{
ThreadPool.QueueUserWorkItem(SingleExecuteProtector.ExecuteOnceWaitCallback, wrapper);
}
}
if (mainThreadQueueUpdated || backgroundThreadQueueUpdated)
{
IReadOnlyCollection<JoinableTask>? tasksNeedNotify = JoinableTaskDependencyGraph.GetDependingSynchronousTasks(this, mainThreadQueueUpdated);
if (tasksNeedNotify.Count > 0)
{
eventsNeedNotify = new List<AsyncManualResetEvent>(tasksNeedNotify.Count);
foreach (JoinableTask? taskToNotify in tasksNeedNotify)
{
if (mainThreadQueueUpdated && taskToNotify != this && taskToNotify.pendingEventCount == 0 && taskToNotify.HasPotentialUnreachableDependents)
{
// It is not essential to clean up potential unreachable dependent items before triggering the UI thread,
// because dependencies may change, and invalidate this work. However, we try to do this work in the background thread to make it less likely
// doing the expensive work on the UI thread.
if (JoinableTaskDependencyGraph.CleanUpPotentialUnreachableDependentItems(taskToNotify, out HashSet<IJoinableTaskDependent>? reachableNodes) &&
!reachableNodes.Contains(this))
{
continue;
}
}
if (taskToNotify.pendingEventSource is null || taskToNotify == this)
{
taskToNotify.pendingEventSource = this.WeakSelf;
}
taskToNotify.pendingEventCount++;
if (taskToNotify.queueNeedProcessEvent is object)
{
eventsNeedNotify.Add(taskToNotify.queueNeedProcessEvent);
}
}
}
}
}
}
// Notify tasks which can process the event queue.
if (eventsNeedNotify is object)
{
foreach (AsyncManualResetEvent? queueEvent in eventsNeedNotify)
{
queueEvent.PulseAll();
}
}
// We deferred this till after we release our lock earlier in this method since we're calling outside code.
if (postToFactory)
{
Assumes.Null(wrapper); // we avoid using a wrapper in this case because this job transferring ownership to the factory.
this.Factory.Post(d, state, mainThreadAffinitized);
}
else if (mainThreadAffinitized)
{
Assumes.NotNull(wrapper); // this should have been initialized in the above logic.
this.owner.PostToUnderlyingSynchronizationContextOrThreadPool(wrapper);
foreach (JoinableTaskFactory? nestingFactory in this.nestingFactories)
{
if (nestingFactory != this.owner)
{
nestingFactory.PostToUnderlyingSynchronizationContextOrThreadPool(wrapper);
}
}
}
}
}