// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_H_ #define BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_H_ #include #include "base/base_export.h" #include "base/macros.h" #include "base/pending_task.h" #include "base/task/sequence_manager/task_queue_selector_logic.h" #include "base/task/sequence_manager/work_queue_sets.h" namespace base { namespace sequence_manager { namespace internal { struct AssociatedThreadId; // TaskQueueSelector is used by the SchedulerHelper to enable prioritization // of particular task queues. class BASE_EXPORT TaskQueueSelector { public: explicit TaskQueueSelector( scoped_refptr associated_thread); ~TaskQueueSelector(); // Called to register a queue that can be selected. This function is called // on the main thread. void AddQueue(internal::TaskQueueImpl* queue); // The specified work will no longer be considered for selection. This // function is called on the main thread. void RemoveQueue(internal::TaskQueueImpl* queue); // Make |queue| eligible for selection. This function is called on the main // thread. Must only be called if |queue| is disabled. void EnableQueue(internal::TaskQueueImpl* queue); // Disable selection from |queue|. Must only be called if |queue| is enabled. void DisableQueue(internal::TaskQueueImpl* queue); // Called get or set the priority of |queue|. void SetQueuePriority(internal::TaskQueueImpl* queue, TaskQueue::QueuePriority priority); // Called to choose the work queue from which the next task should be taken // and run. Return true if |out_work_queue| indicates the queue to service or // false to avoid running any task. // // This function is called on the main thread. bool SelectWorkQueueToService(WorkQueue** out_work_queue); // Serialize the selector state for tracing. void AsValueInto(trace_event::TracedValue* state) const; class BASE_EXPORT Observer { public: virtual ~Observer() = default; // Called when |queue| transitions from disabled to enabled. virtual void OnTaskQueueEnabled(internal::TaskQueueImpl* queue) = 0; }; // Called once to set the Observer. This function is called // on the main thread. If |observer| is null, then no callbacks will occur. void SetTaskQueueSelectorObserver(Observer* observer); // Returns true if all the enabled work queues are empty. Returns false // otherwise. bool AllEnabledWorkQueuesAreEmpty() const; protected: class BASE_EXPORT PrioritizingSelector { public: PrioritizingSelector(TaskQueueSelector* task_queue_selector, const char* name); void ChangeSetIndex(internal::TaskQueueImpl* queue, TaskQueue::QueuePriority priority); void AddQueue(internal::TaskQueueImpl* queue, TaskQueue::QueuePriority priority); void RemoveQueue(internal::TaskQueueImpl* queue); bool SelectWorkQueueToService(TaskQueue::QueuePriority max_priority, WorkQueue** out_work_queue, bool* out_chose_delayed_over_immediate); WorkQueueSets* delayed_work_queue_sets() { return &delayed_work_queue_sets_; } WorkQueueSets* immediate_work_queue_sets() { return &immediate_work_queue_sets_; } const WorkQueueSets* delayed_work_queue_sets() const { return &delayed_work_queue_sets_; } const WorkQueueSets* immediate_work_queue_sets() const { return &immediate_work_queue_sets_; } bool ChooseOldestWithPriority(TaskQueue::QueuePriority priority, bool* out_chose_delayed_over_immediate, WorkQueue** out_work_queue) const; #if DCHECK_IS_ON() || !defined(NDEBUG) bool CheckContainsQueueForTest(const internal::TaskQueueImpl* queue) const; #endif private: bool ChooseOldestImmediateTaskWithPriority( TaskQueue::QueuePriority priority, WorkQueue** out_work_queue) const; bool ChooseOldestDelayedTaskWithPriority(TaskQueue::QueuePriority priority, WorkQueue** out_work_queue) const; // Return true if |out_queue| contains the queue with the oldest pending // task from the set of queues of |priority|, or false if all queues of that // priority are empty. In addition |out_chose_delayed_over_immediate| is set // to true iff we chose a delayed work queue in favour of an immediate work // queue. bool ChooseOldestImmediateOrDelayedTaskWithPriority( TaskQueue::QueuePriority priority, bool* out_chose_delayed_over_immediate, WorkQueue** out_work_queue) const; const TaskQueueSelector* task_queue_selector_; WorkQueueSets delayed_work_queue_sets_; WorkQueueSets immediate_work_queue_sets_; DISALLOW_COPY_AND_ASSIGN(PrioritizingSelector); }; // Return true if |out_queue| contains the queue with the oldest pending task // from the set of queues of |priority|, or false if all queues of that // priority are empty. In addition |out_chose_delayed_over_immediate| is set // to true iff we chose a delayed work queue in favour of an immediate work // queue. This method will force select an immediate task if those are being // starved by delayed tasks. void SetImmediateStarvationCountForTest(size_t immediate_starvation_count); PrioritizingSelector* prioritizing_selector_for_test() { return &prioritizing_selector_; } // Maximum score to accumulate before high priority tasks are run even in // the presence of highest priority tasks. static const size_t kMaxHighPriorityStarvationScore = 3; // Increment to be applied to the high priority starvation score when a task // should have only a small effect on the score. E.g. A number of highest // priority tasks must run before the high priority queue is considered // starved. static const size_t kSmallScoreIncrementForHighPriorityStarvation = 1; // Maximum score to accumulate before normal priority tasks are run even in // the presence of higher priority tasks i.e. highest and high priority tasks. static const size_t kMaxNormalPriorityStarvationScore = 5; // Increment to be applied to the normal priority starvation score when a task // should have a large effect on the score. E.g Only a few high priority // priority tasks must run before the normal priority queue is considered // starved. static const size_t kLargeScoreIncrementForNormalPriorityStarvation = 2; // Increment to be applied to the normal priority starvation score when a task // should have only a small effect on the score. E.g. A number of highest // priority tasks must run before the normal priority queue is considered // starved. static const size_t kSmallScoreIncrementForNormalPriorityStarvation = 1; // Maximum score to accumulate before low priority tasks are run even in the // presence of highest, high, or normal priority tasks. static const size_t kMaxLowPriorityStarvationScore = 25; // Increment to be applied to the low priority starvation score when a task // should have a large effect on the score. E.g. Only a few normal/high // priority tasks must run before the low priority queue is considered // starved. static const size_t kLargeScoreIncrementForLowPriorityStarvation = 5; // Increment to be applied to the low priority starvation score when a task // should have only a small effect on the score. E.g. A lot of highest // priority tasks must run before the low priority queue is considered // starved. static const size_t kSmallScoreIncrementForLowPriorityStarvation = 1; // Maximum number of delayed tasks tasks which can be run while there's a // waiting non-delayed task. static const size_t kMaxDelayedStarvationTasks = 3; private: // Returns the priority which is next after |priority|. static TaskQueue::QueuePriority NextPriority( TaskQueue::QueuePriority priority); bool SelectWorkQueueToServiceInternal(WorkQueue** out_work_queue); // Called whenever the selector chooses a task queue for execution with the // priority |priority|. void DidSelectQueueWithPriority(TaskQueue::QueuePriority priority, bool chose_delayed_over_immediate); // Returns true if there are pending tasks with priority |priority|. bool HasTasksWithPriority(TaskQueue::QueuePriority priority); scoped_refptr associated_thread_; PrioritizingSelector prioritizing_selector_; size_t immediate_starvation_count_; size_t high_priority_starvation_score_; size_t normal_priority_starvation_score_; size_t low_priority_starvation_score_; Observer* task_queue_selector_observer_; // Not owned. DISALLOW_COPY_AND_ASSIGN(TaskQueueSelector); }; } // namespace internal } // namespace sequence_manager } // namespace base #endif // BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_H_