internal void Post()

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);
                        }
                    }
                }
            }
        }