Esempio n. 1
0
        /// <summary>Runs a loop to process all queued work items, returning only when the task is completed.</summary>
        internal void CompleteOnCurrentThread()
        {
            Assumes.NotNull(this.wrappedTask);

            // "Push" this task onto the TLS field's virtual stack so that on hang reports we know which task to 'blame'.
            JoinableTask?priorCompletingTask = CompletingTask.Value;

            CompletingTask.Value = this;
            try
            {
                bool onMainThread    = false;
                var  additionalFlags = JoinableTaskFlags.CompletingSynchronously;
                if (this.JoinableTaskContext.IsOnMainThread)
                {
                    additionalFlags |= JoinableTaskFlags.SynchronouslyBlockingMainThread;
                    onMainThread     = true;
                }

                this.AddStateFlags(additionalFlags);

                if (!this.IsCompleteRequested)
                {
                    if (ThreadingEventSource.Instance.IsEnabled())
                    {
                        ThreadingEventSource.Instance.CompleteOnCurrentThreadStart(this.GetHashCode(), onMainThread);
                    }

                    using (this.JoinableTaskContext.NoMessagePumpSynchronizationContext.Apply())
                    {
                        lock (this.JoinableTaskContext.SyncContextLock)
                        {
                            JoinableTaskDependencyGraph.OnSynchronousTaskStartToBlockWaiting(this, out JoinableTask? pendingRequestTask, out this.pendingEventCount);

                            // Add the task to the depending tracking list of itself, so it will monitor the event queue.
                            this.pendingEventSource = pendingRequestTask?.WeakSelf;
                        }
                    }

                    if (onMainThread)
                    {
                        this.JoinableTaskContext.OnSynchronousJoinableTaskToCompleteOnMainThread(this);
                    }

                    try
                    {
                        // Don't use IsCompleted as the condition because that
                        // includes queues of posted work that don't have to complete for the
                        // JoinableTask to be ready to return from the JTF.Run method.
                        HashSet <IJoinableTaskDependent>?visited = null;
                        while (!this.IsCompleteRequested)
                        {
                            if (this.TryDequeueSelfOrDependencies(onMainThread, ref visited, out SingleExecuteProtector? work, out Task? tryAgainAfter))
                            {
                                work.TryExecute();
                            }
                            else if (tryAgainAfter != null)
                            {
                                ThreadingEventSource.Instance.WaitSynchronouslyStart();
                                this.owner.WaitSynchronously(tryAgainAfter);
                                ThreadingEventSource.Instance.WaitSynchronouslyStop();
                                Assumes.True(tryAgainAfter.IsCompleted);
                            }
                        }
                    }
                    finally
                    {
                        JoinableTaskDependencyGraph.OnSynchronousTaskEndToBlockWaiting(this);
                    }

                    if (ThreadingEventSource.Instance.IsEnabled())
                    {
                        ThreadingEventSource.Instance.CompleteOnCurrentThreadStop(this.GetHashCode());
                    }
                }
                else
                {
                    if (onMainThread)
                    {
                        this.JoinableTaskContext.OnSynchronousJoinableTaskToCompleteOnMainThread(this);
                    }
                }

                // Now that we're about to stop blocking a thread, transfer any work
                // that was queued but evidently not required to complete this task
                // back to the threadpool so it still gets done.
                if (this.threadPoolQueue?.Count > 0)
                {
                    while (this.threadPoolQueue.TryDequeue(out SingleExecuteProtector? executor))
                    {
                        ThreadPool.QueueUserWorkItem(SingleExecuteProtector.ExecuteOnceWaitCallback, executor);
                    }
                }

                Assumes.True(this.Task.IsCompleted);
                this.Task.GetAwaiter().GetResult(); // rethrow any exceptions
            }
            finally
            {
                CompletingTask.Value = priorCompletingTask;
            }
        }
Esempio n. 2
0
        /// <summary>Runs a loop to process all queued work items, returning only when the task is completed.</summary>
        internal void CompleteOnCurrentThread()
        {
            Assumes.NotNull(this.wrappedTask);

            // "Push" this task onto the TLS field's virtual stack so that on hang reports we know which task to 'blame'.
            JoinableTask priorCompletingTask = CompletingTask.Value;

            CompletingTask.Value = this;
            try
            {
                bool onMainThread    = false;
                var  additionalFlags = JoinableTaskFlags.CompletingSynchronously;
                if (this.JoinableTaskContext.IsOnMainThread)
                {
                    additionalFlags |= JoinableTaskFlags.SynchronouslyBlockingMainThread;
                    onMainThread     = true;
                }

                this.AddStateFlags(additionalFlags);

                if (!this.IsCompleteRequested)
                {
                    if (ThreadingEventSource.Instance.IsEnabled())
                    {
                        ThreadingEventSource.Instance.CompleteOnCurrentThreadStart(this.GetHashCode(), onMainThread);
                    }

                    using (this.JoinableTaskContext.NoMessagePumpSynchronizationContext.Apply())
                    {
                        lock (this.JoinableTaskContext.SyncContextLock)
                        {
                            JoinableTaskDependencyGraph.OnSynchronousTaskStartToBlockWaiting(this, out JoinableTask pendingRequestTask, out this.pendingEventCount);

                            // Add the task to the depending tracking list of itself, so it will monitor the event queue.
                            this.pendingEventSource = pendingRequestTask?.WeakSelf;
                        }
                    }

                    if (onMainThread)
                    {
                        this.JoinableTaskContext.OnSynchronousJoinableTaskToCompleteOnMainThread(this);
                    }

                    try
                    {
                        // Don't use IsCompleted as the condition because that
                        // includes queues of posted work that don't have to complete for the
                        // JoinableTask to be ready to return from the JTF.Run method.
                        HashSet <IJoinableTaskDependent> visited = null;
                        while (!this.IsCompleteRequested)
                        {
                            if (this.TryDequeueSelfOrDependencies(onMainThread, ref visited, out SingleExecuteProtector work, out Task tryAgainAfter))
                            {
                                work.TryExecute();
                            }
                            else if (tryAgainAfter != null)
                            {
                                ThreadingEventSource.Instance.WaitSynchronouslyStart();
                                this.owner.WaitSynchronously(tryAgainAfter);
                                ThreadingEventSource.Instance.WaitSynchronouslyStop();
                                Assumes.True(tryAgainAfter.IsCompleted);
                            }
                        }
                    }