Index: components/scheduler/child/task_queue_selector.cc |
diff --git a/components/scheduler/child/task_queue_selector.cc b/components/scheduler/child/task_queue_selector.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..d65cbf9ff2cf60267caac853ee383188805c6322 |
--- /dev/null |
+++ b/components/scheduler/child/task_queue_selector.cc |
@@ -0,0 +1,127 @@ |
+// Copyright 2014 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. |
+ |
+#include "components/scheduler/child/task_queue_selector.h" |
+ |
+#include "base/logging.h" |
+#include "base/trace_event/trace_event_argument.h" |
+#include "components/scheduler/child/task_queue_impl.h" |
+ |
+namespace scheduler { |
+namespace internal { |
+ |
+TaskQueueSelector::TaskQueueSelector() |
+ : task_queue_sets_(TaskQueue::QUEUE_PRIORITY_COUNT), |
+ starvation_count_(0), |
+ task_queue_selector_observer_(nullptr) {} |
+ |
+TaskQueueSelector::~TaskQueueSelector() {} |
+ |
+void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) { |
+ DCHECK(main_thread_checker_.CalledOnValidThread()); |
+ task_queue_sets_.AssignQueueToSet(queue, TaskQueue::NORMAL_PRIORITY); |
+} |
+ |
+void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl* queue) { |
+ DCHECK(main_thread_checker_.CalledOnValidThread()); |
+ task_queue_sets_.RemoveQueue(queue); |
+} |
+ |
+void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl* queue, |
+ TaskQueue::QueuePriority priority) { |
+ DCHECK(main_thread_checker_.CalledOnValidThread()); |
+ DCHECK_LT(priority, TaskQueue::QUEUE_PRIORITY_COUNT); |
+ TaskQueue::QueuePriority old_priority = |
+ static_cast<TaskQueue::QueuePriority>(queue->get_task_queue_set_index()); |
+ task_queue_sets_.AssignQueueToSet(queue, priority); |
+ if (task_queue_selector_observer_ && |
+ old_priority == TaskQueue::DISABLED_PRIORITY) { |
+ task_queue_selector_observer_->OnTaskQueueEnabled(queue); |
+ } |
+} |
+ |
+bool TaskQueueSelector::IsQueueEnabled( |
+ const internal::TaskQueueImpl* queue) const { |
+ DCHECK(main_thread_checker_.CalledOnValidThread()); |
+ return static_cast<TaskQueue::QueuePriority>( |
+ queue->get_task_queue_set_index()) != TaskQueue::DISABLED_PRIORITY; |
+} |
+ |
+TaskQueue::QueuePriority TaskQueueSelector::NextPriority( |
+ TaskQueue::QueuePriority priority) { |
+ DCHECK(priority < TaskQueue::QUEUE_PRIORITY_COUNT); |
+ return static_cast<TaskQueue::QueuePriority>(static_cast<int>(priority) + 1); |
+} |
+ |
+bool TaskQueueSelector::ChooseOldestWithPriority( |
+ TaskQueue::QueuePriority priority, |
+ internal::TaskQueueImpl** out_queue) const { |
+ return task_queue_sets_.GetOldestQueueInSet(priority, out_queue); |
+} |
+ |
+bool TaskQueueSelector::SelectQueueToService( |
+ internal::TaskQueueImpl** out_queue) { |
+ DCHECK(main_thread_checker_.CalledOnValidThread()); |
+ // Always service the control queue if it has any work. |
+ if (ChooseOldestWithPriority(TaskQueue::CONTROL_PRIORITY, out_queue)) { |
+ DidSelectQueueWithPriority(TaskQueue::CONTROL_PRIORITY); |
+ return true; |
+ } |
+ // Select from the normal priority queue if we are starving it. |
+ if (starvation_count_ >= kMaxStarvationTasks && |
+ ChooseOldestWithPriority(TaskQueue::NORMAL_PRIORITY, out_queue)) { |
+ DidSelectQueueWithPriority(TaskQueue::NORMAL_PRIORITY); |
+ return true; |
+ } |
+ // Otherwise choose in priority order. |
+ for (TaskQueue::QueuePriority priority = TaskQueue::HIGH_PRIORITY; |
+ priority < TaskQueue::DISABLED_PRIORITY; |
+ priority = NextPriority(priority)) { |
+ if (ChooseOldestWithPriority(priority, out_queue)) { |
+ DidSelectQueueWithPriority(priority); |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+void TaskQueueSelector::DidSelectQueueWithPriority( |
+ TaskQueue::QueuePriority priority) { |
+ switch (priority) { |
+ case TaskQueue::CONTROL_PRIORITY: |
+ break; |
+ case TaskQueue::HIGH_PRIORITY: |
+ starvation_count_++; |
+ break; |
+ case TaskQueue::NORMAL_PRIORITY: |
+ case TaskQueue::BEST_EFFORT_PRIORITY: |
+ starvation_count_ = 0; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+} |
+ |
+void TaskQueueSelector::AsValueInto( |
+ base::trace_event::TracedValue* state) const { |
+ DCHECK(main_thread_checker_.CalledOnValidThread()); |
+ state->SetInteger("starvation_count", starvation_count_); |
+} |
+ |
+void TaskQueueSelector::SetTaskQueueSelectorObserver(Observer* observer) { |
+ task_queue_selector_observer_ = observer; |
+} |
+ |
+bool TaskQueueSelector::EnabledWorkQueuesEmpty() const { |
+ for (TaskQueue::QueuePriority priority = TaskQueue::HIGH_PRIORITY; |
+ priority < TaskQueue::DISABLED_PRIORITY; |
+ priority = NextPriority(priority)) { |
+ if (!task_queue_sets_.IsSetEmpty(priority)) |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+} // namespace internal |
+} // namespace scheduler |