| // 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 "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" |
| #include "starboard/types.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<AssociatedThreadId> 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<AssociatedThreadId> 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_ |