Home | History | Annotate | Download | only in sequence_manager
      1 // Copyright 2015 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_H_
      6 #define BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_H_
      7 
      8 #include <stddef.h>
      9 
     10 #include "base/base_export.h"
     11 #include "base/macros.h"
     12 #include "base/pending_task.h"
     13 #include "base/task/sequence_manager/task_queue_selector_logic.h"
     14 #include "base/task/sequence_manager/work_queue_sets.h"
     15 #include "base/threading/thread_checker.h"
     16 
     17 namespace base {
     18 namespace sequence_manager {
     19 namespace internal {
     20 
     21 // TaskQueueSelector is used by the SchedulerHelper to enable prioritization
     22 // of particular task queues.
     23 class BASE_EXPORT TaskQueueSelector {
     24  public:
     25   TaskQueueSelector();
     26   ~TaskQueueSelector();
     27 
     28   // Called to register a queue that can be selected. This function is called
     29   // on the main thread.
     30   void AddQueue(internal::TaskQueueImpl* queue);
     31 
     32   // The specified work will no longer be considered for selection. This
     33   // function is called on the main thread.
     34   void RemoveQueue(internal::TaskQueueImpl* queue);
     35 
     36   // Make |queue| eligible for selection. This function is called on the main
     37   // thread. Must only be called if |queue| is disabled.
     38   void EnableQueue(internal::TaskQueueImpl* queue);
     39 
     40   // Disable selection from |queue|. Must only be called if |queue| is enabled.
     41   void DisableQueue(internal::TaskQueueImpl* queue);
     42 
     43   // Called get or set the priority of |queue|.
     44   void SetQueuePriority(internal::TaskQueueImpl* queue,
     45                         TaskQueue::QueuePriority priority);
     46 
     47   // Called to choose the work queue from which the next task should be taken
     48   // and run. Return true if |out_work_queue| indicates the queue to service or
     49   // false to avoid running any task.
     50   //
     51   // This function is called on the main thread.
     52   bool SelectWorkQueueToService(WorkQueue** out_work_queue);
     53 
     54   // Serialize the selector state for tracing.
     55   void AsValueInto(trace_event::TracedValue* state) const;
     56 
     57   class BASE_EXPORT Observer {
     58    public:
     59     virtual ~Observer() = default;
     60 
     61     // Called when |queue| transitions from disabled to enabled.
     62     virtual void OnTaskQueueEnabled(internal::TaskQueueImpl* queue) = 0;
     63   };
     64 
     65   // Called once to set the Observer. This function is called
     66   // on the main thread. If |observer| is null, then no callbacks will occur.
     67   void SetTaskQueueSelectorObserver(Observer* observer);
     68 
     69   // Returns true if all the enabled work queues are empty. Returns false
     70   // otherwise.
     71   bool AllEnabledWorkQueuesAreEmpty() const;
     72 
     73  protected:
     74   class BASE_EXPORT PrioritizingSelector {
     75    public:
     76     PrioritizingSelector(TaskQueueSelector* task_queue_selector,
     77                          const char* name);
     78 
     79     void ChangeSetIndex(internal::TaskQueueImpl* queue,
     80                         TaskQueue::QueuePriority priority);
     81     void AddQueue(internal::TaskQueueImpl* queue,
     82                   TaskQueue::QueuePriority priority);
     83     void RemoveQueue(internal::TaskQueueImpl* queue);
     84 
     85     bool SelectWorkQueueToService(TaskQueue::QueuePriority max_priority,
     86                                   WorkQueue** out_work_queue,
     87                                   bool* out_chose_delayed_over_immediate);
     88 
     89     WorkQueueSets* delayed_work_queue_sets() {
     90       return &delayed_work_queue_sets_;
     91     }
     92     WorkQueueSets* immediate_work_queue_sets() {
     93       return &immediate_work_queue_sets_;
     94     }
     95 
     96     const WorkQueueSets* delayed_work_queue_sets() const {
     97       return &delayed_work_queue_sets_;
     98     }
     99     const WorkQueueSets* immediate_work_queue_sets() const {
    100       return &immediate_work_queue_sets_;
    101     }
    102 
    103     bool ChooseOldestWithPriority(TaskQueue::QueuePriority priority,
    104                                   bool* out_chose_delayed_over_immediate,
    105                                   WorkQueue** out_work_queue) const;
    106 
    107 #if DCHECK_IS_ON() || !defined(NDEBUG)
    108     bool CheckContainsQueueForTest(const internal::TaskQueueImpl* queue) const;
    109 #endif
    110 
    111    private:
    112     bool ChooseOldestImmediateTaskWithPriority(
    113         TaskQueue::QueuePriority priority,
    114         WorkQueue** out_work_queue) const;
    115 
    116     bool ChooseOldestDelayedTaskWithPriority(TaskQueue::QueuePriority priority,
    117                                              WorkQueue** out_work_queue) const;
    118 
    119     // Return true if |out_queue| contains the queue with the oldest pending
    120     // task from the set of queues of |priority|, or false if all queues of that
    121     // priority are empty. In addition |out_chose_delayed_over_immediate| is set
    122     // to true iff we chose a delayed work queue in favour of an immediate work
    123     // queue.
    124     bool ChooseOldestImmediateOrDelayedTaskWithPriority(
    125         TaskQueue::QueuePriority priority,
    126         bool* out_chose_delayed_over_immediate,
    127         WorkQueue** out_work_queue) const;
    128 
    129     const TaskQueueSelector* task_queue_selector_;
    130     WorkQueueSets delayed_work_queue_sets_;
    131     WorkQueueSets immediate_work_queue_sets_;
    132 
    133     DISALLOW_COPY_AND_ASSIGN(PrioritizingSelector);
    134   };
    135 
    136   // Return true if |out_queue| contains the queue with the oldest pending task
    137   // from the set of queues of |priority|, or false if all queues of that
    138   // priority are empty. In addition |out_chose_delayed_over_immediate| is set
    139   // to true iff we chose a delayed work queue in favour of an immediate work
    140   // queue.  This method will force select an immediate task if those are being
    141   // starved by delayed tasks.
    142   void SetImmediateStarvationCountForTest(size_t immediate_starvation_count);
    143 
    144   PrioritizingSelector* prioritizing_selector_for_test() {
    145     return &prioritizing_selector_;
    146   }
    147 
    148   // Maximum score to accumulate before high priority tasks are run even in
    149   // the presence of highest priority tasks.
    150   static const size_t kMaxHighPriorityStarvationScore = 3;
    151 
    152   // Increment to be applied to the high priority starvation score when a task
    153   // should have only a small effect on the score. E.g. A number of highest
    154   // priority tasks must run before the high priority queue is considered
    155   // starved.
    156   static const size_t kSmallScoreIncrementForHighPriorityStarvation = 1;
    157 
    158   // Maximum score to accumulate before normal priority tasks are run even in
    159   // the presence of higher priority tasks i.e. highest and high priority tasks.
    160   static const size_t kMaxNormalPriorityStarvationScore = 5;
    161 
    162   // Increment to be applied to the normal priority starvation score when a task
    163   // should have a large effect on the score. E.g Only a few high priority
    164   // priority tasks must run before the normal priority queue is considered
    165   // starved.
    166   static const size_t kLargeScoreIncrementForNormalPriorityStarvation = 2;
    167 
    168   // Increment to be applied to the normal priority starvation score when a task
    169   // should have only a small effect on the score. E.g. A number of highest
    170   // priority tasks must run before the normal priority queue is considered
    171   // starved.
    172   static const size_t kSmallScoreIncrementForNormalPriorityStarvation = 1;
    173 
    174   // Maximum score to accumulate before low priority tasks are run even in the
    175   // presence of highest, high, or normal priority tasks.
    176   static const size_t kMaxLowPriorityStarvationScore = 25;
    177 
    178   // Increment to be applied to the low priority starvation score when a task
    179   // should have a large effect on the score. E.g. Only a few normal/high
    180   // priority tasks must run before the low priority queue is considered
    181   // starved.
    182   static const size_t kLargeScoreIncrementForLowPriorityStarvation = 5;
    183 
    184   // Increment to be applied to the low priority starvation score when a task
    185   // should have only a small effect on the score. E.g. A lot of highest
    186   // priority tasks must run before the low priority queue is considered
    187   // starved.
    188   static const size_t kSmallScoreIncrementForLowPriorityStarvation = 1;
    189 
    190   // Maximum number of delayed tasks tasks which can be run while there's a
    191   // waiting non-delayed task.
    192   static const size_t kMaxDelayedStarvationTasks = 3;
    193 
    194  private:
    195   // Returns the priority which is next after |priority|.
    196   static TaskQueue::QueuePriority NextPriority(
    197       TaskQueue::QueuePriority priority);
    198 
    199   bool SelectWorkQueueToServiceInternal(WorkQueue** out_work_queue);
    200 
    201   // Called whenever the selector chooses a task queue for execution with the
    202   // priority |priority|.
    203   void DidSelectQueueWithPriority(TaskQueue::QueuePriority priority,
    204                                   bool chose_delayed_over_immediate);
    205 
    206   // Returns true if there are pending tasks with priority |priority|.
    207   bool HasTasksWithPriority(TaskQueue::QueuePriority priority);
    208 
    209   ThreadChecker main_thread_checker_;
    210 
    211   PrioritizingSelector prioritizing_selector_;
    212   size_t immediate_starvation_count_;
    213   size_t high_priority_starvation_score_;
    214   size_t normal_priority_starvation_score_;
    215   size_t low_priority_starvation_score_;
    216 
    217   Observer* task_queue_selector_observer_;  // Not owned.
    218   DISALLOW_COPY_AND_ASSIGN(TaskQueueSelector);
    219 };
    220 
    221 }  // namespace internal
    222 }  // namespace sequence_manager
    223 }  // namespace base
    224 
    225 #endif  // BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_H_
    226