/// <summary>
        /// Get how many number of synchronous tasks in our tracking list.
        /// </summary>
        private int CountOfDependingSynchronousTasks()
        {
            int count = 0;
            DependentSynchronousTask existingTaskTracking = this.dependingSynchronousTaskTracking;

            while (existingTaskTracking != null)
            {
                count++;
                existingTaskTracking = existingTaskTracking.Next;
            }

            return(count);
        }
        /// <summary>
        /// Removes all synchronous tasks we applies to a dependent task, after the relationship is removed.
        /// </summary>
        /// <param name="child">The original dependent task</param>
        private void RemoveDependingSynchronousTaskFromChild(JoinableTask child)
        {
            Requires.NotNull(child, nameof(child));
            Assumes.True(Monitor.IsEntered(this.owner.Context.SyncContextLock));

            DependentSynchronousTask existingTaskTracking = this.dependingSynchronousTaskTracking;

            while (existingTaskTracking != null)
            {
                child.RemoveDependingSynchronousTask(existingTaskTracking.SynchronousTask);
                existingTaskTracking = existingTaskTracking.Next;
            }
        }
        /// <summary>
        /// Check whether a task is being tracked in our tracking list.
        /// </summary>
        private bool IsDependingSynchronousTask(JoinableTask syncTask)
        {
            DependentSynchronousTask existingTaskTracking = this.dependingSynchronousTaskTracking;

            while (existingTaskTracking != null)
            {
                if (existingTaskTracking.SynchronousTask == syncTask)
                {
                    return(true);
                }

                existingTaskTracking = existingTaskTracking.Next;
            }

            return(false);
        }
            /// <summary>
            /// Gets a value indicating whether the main thread is waiting for the task's completion
            /// This method is expected to be used with the JTF lock.
            /// </summary>
            internal bool HasMainThreadSynchronousTaskWaiting()
            {
                DependentSynchronousTask existingTaskTracking = this.dependingSynchronousTaskTracking;

                while (existingTaskTracking != null)
                {
                    if ((existingTaskTracking.SynchronousTask.State & JoinableTask.JoinableTaskFlags.SynchronouslyBlockingMainThread) == JoinableTask.JoinableTaskFlags.SynchronouslyBlockingMainThread)
                    {
                        return(true);
                    }

                    existingTaskTracking = existingTaskTracking.Next;
                }

                return(false);
            }
        /// <summary>
        /// Remove all synchronous tasks tracked by the this task.
        /// This is called when this task is completed
        /// </summary>
        private void CleanupDependingSynchronousTask()
        {
            if (this.dependingSynchronousTaskTracking != null)
            {
                DependentSynchronousTask existingTaskTracking = this.dependingSynchronousTaskTracking;
                this.dependingSynchronousTaskTracking = null;

                if (this.childOrJoinedJobs != null)
                {
                    var childrenTasks = this.childOrJoinedJobs.Select(item => item.Key).ToList();
                    while (existingTaskTracking != null)
                    {
                        RemoveDependingSynchronousTaskFrom(childrenTasks, existingTaskTracking.SynchronousTask, false);
                        existingTaskTracking = existingTaskTracking.Next;
                    }
                }
            }
        }
            /// <summary>
            /// Remove all synchronous tasks tracked by the this task.
            /// This is called when this task is completed.
            /// This method is expected to be used with the JTF lock.
            /// </summary>
            internal void OnTaskCompleted()
            {
                if (this.dependingSynchronousTaskTracking != null)
                {
                    DependentSynchronousTask existingTaskTracking = this.dependingSynchronousTaskTracking;
                    this.dependingSynchronousTaskTracking = null;

                    if (this.childDependentNodes != null)
                    {
                        var childrenTasks = new List <IJoinableTaskDependent>(this.childDependentNodes.Keys);
                        while (existingTaskTracking != null)
                        {
                            RemoveDependingSynchronousTaskFrom(childrenTasks, existingTaskTracking.SynchronousTask, false);
                            existingTaskTracking = existingTaskTracking.Next;
                        }
                    }
                }
            }
        /// <summary>
        /// Calculate the collection of events we need trigger after we enqueue a request.
        /// </summary>
        /// <param name="forMainThread">True if we want to find tasks to process the main thread queue. Otherwise tasks to process the background queue.</param>
        /// <returns>The collection of synchronous tasks we need notify.</returns>
        private List <JoinableTask> GetDependingSynchronousTasks(bool forMainThread)
        {
            Assumes.True(Monitor.IsEntered(this.owner.Context.SyncContextLock));

            var tasksNeedNotify = new List <JoinableTask>(this.CountOfDependingSynchronousTasks());
            DependentSynchronousTask existingTaskTracking = this.dependingSynchronousTaskTracking;

            while (existingTaskTracking != null)
            {
                var  syncTask = existingTaskTracking.SynchronousTask;
                bool syncTaskInOnMainThread = (syncTask.state & JoinableTaskFlags.SynchronouslyBlockingMainThread) == JoinableTaskFlags.SynchronouslyBlockingMainThread;
                if (forMainThread == syncTaskInOnMainThread)
                {
                    // Only synchronous tasks are in the list, so we don't need do further check for the CompletingSynchronously flag
                    tasksNeedNotify.Add(syncTask);
                }

                existingTaskTracking = existingTaskTracking.Next;
            }

            return(tasksNeedNotify);
        }
        /// <summary>
        /// Applies all synchronous tasks tracked by this task to a new child/dependent task.
        /// </summary>
        /// <param name="child">The new child task.</param>
        /// <returns>Pairs of synchronous tasks we need notify and the event source triggering it, plus the number of pending events.</returns>
        private List <PendingNotification> AddDependingSynchronousTaskToChild(JoinableTask child)
        {
            Requires.NotNull(child, nameof(child));
            Assumes.True(Monitor.IsEntered(this.owner.Context.SyncContextLock));

            var tasksNeedNotify = new List <PendingNotification>(this.CountOfDependingSynchronousTasks());
            DependentSynchronousTask existingTaskTracking = this.dependingSynchronousTaskTracking;

            while (existingTaskTracking != null)
            {
                int totalEventNumber    = 0;
                var eventTriggeringTask = child.AddDependingSynchronousTask(existingTaskTracking.SynchronousTask, ref totalEventNumber);
                if (eventTriggeringTask != null)
                {
                    tasksNeedNotify.Add(new PendingNotification(existingTaskTracking.SynchronousTask, eventTriggeringTask, totalEventNumber));
                }

                existingTaskTracking = existingTaskTracking.Next;
            }

            return(tasksNeedNotify);
        }
        /// <summary>
        /// Remove a synchronous task from the tracking list of this task.
        /// </summary>
        /// <param name="task">The synchronous task need be removed</param>
        /// <param name="reachableTasks">
        /// If it is not null, it will contain all task which can track the synchronous task. We will ignore reference count in that case.
        /// </param>
        /// <param name="remainingDependentTasks">This will retain the tasks which still tracks the synchronous task.</param>
        private void RemoveDependingSynchronousTask(JoinableTask task, HashSet <JoinableTask> reachableTasks, ref HashSet <JoinableTask> remainingDependentTasks)
        {
            Requires.NotNull(task, nameof(task));

            DependentSynchronousTask previousTaskTracking = null;
            DependentSynchronousTask currentTaskTracking  = this.dependingSynchronousTaskTracking;
            bool removed = false;

            while (currentTaskTracking != null)
            {
                if (currentTaskTracking.SynchronousTask == task)
                {
                    if (--currentTaskTracking.ReferenceCount > 0)
                    {
                        if (reachableTasks != null)
                        {
                            if (!reachableTasks.Contains(this))
                            {
                                currentTaskTracking.ReferenceCount = 0;
                            }
                        }
                    }

                    if (currentTaskTracking.ReferenceCount == 0)
                    {
                        removed = true;
                        if (previousTaskTracking != null)
                        {
                            previousTaskTracking.Next = currentTaskTracking.Next;
                        }
                        else
                        {
                            this.dependingSynchronousTaskTracking = currentTaskTracking.Next;
                        }
                    }

                    if (reachableTasks == null)
                    {
                        if (removed)
                        {
                            if (remainingDependentTasks != null)
                            {
                                remainingDependentTasks.Remove(this);
                            }
                        }
                        else
                        {
                            if (remainingDependentTasks == null)
                            {
                                remainingDependentTasks = new HashSet <JoinableTask>();
                            }

                            remainingDependentTasks.Add(this);
                        }
                    }

                    break;
                }

                previousTaskTracking = currentTaskTracking;
                currentTaskTracking  = currentTaskTracking.Next;
            }

            if (removed && this.childOrJoinedJobs != null)
            {
                foreach (var item in this.childOrJoinedJobs)
                {
                    item.Key.RemoveDependingSynchronousTask(task, reachableTasks, ref remainingDependentTasks);
                }
            }
        }
        /// <summary>
        /// Tracks a new synchronous task for this task.
        /// A synchronous task is a task blocking a thread and waits it to be completed.  We may want the blocking thread
        /// to process events from this task.
        /// </summary>
        /// <param name="task">The synchronous task</param>
        /// <param name="totalEventsPending">The total events need be processed</param>
        /// <returns>The task causes us to trigger the event of the synchronous task, so it can process new events.  Null means we don't need trigger any event</returns>
        private JoinableTask AddDependingSynchronousTask(JoinableTask task, ref int totalEventsPending)
        {
            Requires.NotNull(task, nameof(task));
            Assumes.True(Monitor.IsEntered(this.owner.Context.SyncContextLock));

            if (this.IsCompleted)
            {
                return(null);
            }

            if (this.IsCompleteRequested)
            {
                // A completed task might still have pending items in the queue.
                int pendingCount = this.GetPendingEventCountForTask(task);
                if (pendingCount > 0)
                {
                    totalEventsPending += pendingCount;
                    return(this);
                }

                return(null);
            }

            DependentSynchronousTask existingTaskTracking = this.dependingSynchronousTaskTracking;

            while (existingTaskTracking != null)
            {
                if (existingTaskTracking.SynchronousTask == task)
                {
                    existingTaskTracking.ReferenceCount++;
                    return(null);
                }

                existingTaskTracking = existingTaskTracking.Next;
            }

            int          pendingItemCount    = this.GetPendingEventCountForTask(task);
            JoinableTask eventTriggeringTask = null;

            if (pendingItemCount > 0)
            {
                totalEventsPending += pendingItemCount;
                eventTriggeringTask = this;
            }

            // For a new synchronous task, we need apply it to our child tasks.
            DependentSynchronousTask newTaskTracking = new DependentSynchronousTask(task)
            {
                Next = this.dependingSynchronousTaskTracking,
            };

            this.dependingSynchronousTaskTracking = newTaskTracking;

            if (this.childOrJoinedJobs != null)
            {
                foreach (var item in this.childOrJoinedJobs)
                {
                    var childTiggeringTask = item.Key.AddDependingSynchronousTask(task, ref totalEventsPending);
                    if (eventTriggeringTask == null)
                    {
                        eventTriggeringTask = childTiggeringTask;
                    }
                }
            }

            return(eventTriggeringTask);
        }