1 // Copyright 2014 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.
5 #include "components/scheduler/child/task_queue_selector.h"
7 #include "base/logging.h"
8 #include "base/trace_event/trace_event_argument.h"
9 #include "components/scheduler/child/task_queue_impl.h"
14 TaskQueueSelector::TaskQueueSelector()
15 : task_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT
),
17 task_queue_selector_observer_(nullptr) {}
19 TaskQueueSelector::~TaskQueueSelector() {}
21 void TaskQueueSelector::AddQueue(internal::TaskQueueImpl
* queue
) {
22 DCHECK(main_thread_checker_
.CalledOnValidThread());
23 task_queue_sets_
.AssignQueueToSet(queue
, TaskQueue::NORMAL_PRIORITY
);
26 void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl
* queue
) {
27 DCHECK(main_thread_checker_
.CalledOnValidThread());
28 task_queue_sets_
.RemoveQueue(queue
);
31 void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl
* queue
,
32 TaskQueue::QueuePriority priority
) {
33 DCHECK(main_thread_checker_
.CalledOnValidThread());
34 DCHECK_LT(priority
, TaskQueue::QUEUE_PRIORITY_COUNT
);
35 TaskQueue::QueuePriority old_priority
=
36 static_cast<TaskQueue::QueuePriority
>(queue
->get_task_queue_set_index());
37 task_queue_sets_
.AssignQueueToSet(queue
, priority
);
38 if (task_queue_selector_observer_
&&
39 old_priority
== TaskQueue::DISABLED_PRIORITY
) {
40 task_queue_selector_observer_
->OnTaskQueueEnabled(queue
);
44 bool TaskQueueSelector::IsQueueEnabled(
45 const internal::TaskQueueImpl
* queue
) const {
46 DCHECK(main_thread_checker_
.CalledOnValidThread());
47 return static_cast<TaskQueue::QueuePriority
>(
48 queue
->get_task_queue_set_index()) != TaskQueue::DISABLED_PRIORITY
;
51 TaskQueue::QueuePriority
TaskQueueSelector::NextPriority(
52 TaskQueue::QueuePriority priority
) {
53 DCHECK(priority
< TaskQueue::QUEUE_PRIORITY_COUNT
);
54 return static_cast<TaskQueue::QueuePriority
>(static_cast<int>(priority
) + 1);
57 bool TaskQueueSelector::ChooseOldestWithPriority(
58 TaskQueue::QueuePriority priority
,
59 internal::TaskQueueImpl
** out_queue
) const {
60 return task_queue_sets_
.GetOldestQueueInSet(priority
, out_queue
);
63 bool TaskQueueSelector::SelectQueueToService(
64 internal::TaskQueueImpl
** out_queue
) {
65 DCHECK(main_thread_checker_
.CalledOnValidThread());
66 // Always service the control queue if it has any work.
67 if (ChooseOldestWithPriority(TaskQueue::CONTROL_PRIORITY
, out_queue
)) {
68 DidSelectQueueWithPriority(TaskQueue::CONTROL_PRIORITY
);
71 // Select from the normal priority queue if we are starving it.
72 if (starvation_count_
>= kMaxStarvationTasks
&&
73 ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY
, out_queue
)) {
74 DidSelectQueueWithPriority(TaskQueue::NORMAL_PRIORITY
);
77 // Otherwise choose in priority order.
78 for (TaskQueue::QueuePriority priority
= TaskQueue::HIGH_PRIORITY
;
79 priority
< TaskQueue::DISABLED_PRIORITY
;
80 priority
= NextPriority(priority
)) {
81 if (ChooseOldestWithPriority(priority
, out_queue
)) {
82 DidSelectQueueWithPriority(priority
);
89 void TaskQueueSelector::DidSelectQueueWithPriority(
90 TaskQueue::QueuePriority priority
) {
92 case TaskQueue::CONTROL_PRIORITY
:
94 case TaskQueue::HIGH_PRIORITY
:
97 case TaskQueue::NORMAL_PRIORITY
:
98 case TaskQueue::BEST_EFFORT_PRIORITY
:
99 starvation_count_
= 0;
106 void TaskQueueSelector::AsValueInto(
107 base::trace_event::TracedValue
* state
) const {
108 DCHECK(main_thread_checker_
.CalledOnValidThread());
109 state
->SetInteger("starvation_count", starvation_count_
);
112 void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer
* observer
) {
113 task_queue_selector_observer_
= observer
;
116 bool TaskQueueSelector::EnabledWorkQueuesEmpty() const {
117 for (TaskQueue::QueuePriority priority
= TaskQueue::HIGH_PRIORITY
;
118 priority
< TaskQueue::DISABLED_PRIORITY
;
119 priority
= NextPriority(priority
)) {
120 if (!task_queue_sets_
.IsSetEmpty(priority
))
126 } // namespace internal
127 } // namespace scheduler