| Index: content/renderer/scheduler/renderer_scheduler_selector.cc
|
| diff --git a/content/renderer/scheduler/renderer_scheduler_selector.cc b/content/renderer/scheduler/renderer_scheduler_selector.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..eda54c1a8783744ec8b32489731d9a09cda2cf4e
|
| --- /dev/null
|
| +++ b/content/renderer/scheduler/renderer_scheduler_selector.cc
|
| @@ -0,0 +1,116 @@
|
| +// 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 "content/renderer/scheduler/renderer_scheduler_selector.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/pending_task.h"
|
| +
|
| +namespace content {
|
| +
|
| +RendererSchedulerSelector::RendererSchedulerSelector()
|
| + : normal_queue_starvation_count_(0) {
|
| +}
|
| +
|
| +RendererSchedulerSelector::~RendererSchedulerSelector() {
|
| +}
|
| +
|
| +void RendererSchedulerSelector::RegisterWorkQueues(
|
| + const std::vector<const base::TaskQueue*>& work_queues) {
|
| + main_thread_checker_.CalledOnValidThread();
|
| + work_queues_ = work_queues;
|
| + // By default, all work queues are set to normal priority.
|
| + for (size_t i = 0; i < work_queues.size(); i++) {
|
| + queue_priorities_[kNormalPriority].insert(i);
|
| + }
|
| + queue_priorities_[kControlPriority].clear();
|
| + queue_priorities_[kHighPriority].clear();
|
| + queue_priorities_[kBestEffortPriority].clear();
|
| +}
|
| +
|
| +void RendererSchedulerSelector::SetQueuePriority(size_t queue_index,
|
| + QueuePriority priority) {
|
| + main_thread_checker_.CalledOnValidThread();
|
| + DCHECK_LT(queue_index, work_queues_.size());
|
| + DCHECK_LT(priority, kQueuePriorityCount);
|
| + DisableQueue(queue_index);
|
| + queue_priorities_[priority].insert(queue_index);
|
| +}
|
| +
|
| +void RendererSchedulerSelector::EnableQueue(size_t queue_index,
|
| + QueuePriority priority) {
|
| + SetQueuePriority(queue_index, priority);
|
| +}
|
| +
|
| +void RendererSchedulerSelector::DisableQueue(size_t queue_index) {
|
| + main_thread_checker_.CalledOnValidThread();
|
| + DCHECK_LT(queue_index, work_queues_.size());
|
| + static const QueuePriority kPriorities[] = {
|
| + kControlPriority, kHighPriority, kNormalPriority, kBestEffortPriority};
|
| + for (QueuePriority priority : kPriorities) {
|
| + queue_priorities_[priority].erase(queue_index);
|
| + }
|
| +}
|
| +
|
| +bool RendererSchedulerSelector::IsOlder(const base::TaskQueue* queueA,
|
| + const base::TaskQueue* queueB) const {
|
| + return queueB->front() < queueA->front();
|
| +}
|
| +
|
| +bool RendererSchedulerSelector::ChooseOldestWithPriority(
|
| + QueuePriority priority,
|
| + size_t* out_queue_index) const {
|
| + bool found_non_empty_queue = false;
|
| + size_t chosen_queue = 0;
|
| + for (int queue_index : queue_priorities_[priority]) {
|
| + if (work_queues_[queue_index]->empty()) {
|
| + continue;
|
| + }
|
| + // Note: the comparison between |chosen_queue| and |queue_index| is correct
|
| + // due to the fact that the PendingTask operator inverts comparison for
|
| + // priority queue.
|
| + if (!found_non_empty_queue ||
|
| + IsOlder(work_queues_[queue_index], work_queues_[chosen_queue])) {
|
| + found_non_empty_queue = true;
|
| + chosen_queue = queue_index;
|
| + }
|
| + }
|
| +
|
| + if (found_non_empty_queue) {
|
| + *out_queue_index = chosen_queue;
|
| + }
|
| + return found_non_empty_queue;
|
| +}
|
| +
|
| +bool RendererSchedulerSelector::SelectWorkQueueToService(
|
| + size_t* out_queue_index) {
|
| + main_thread_checker_.CalledOnValidThread();
|
| + DCHECK(work_queues_.size());
|
| + // Always service the control queue if it has any work.
|
| + if (ChooseOldestWithPriority(kControlPriority, out_queue_index)) {
|
| + return true;
|
| + }
|
| + // Select from the normal priority queue if we are starving it.
|
| + if (normal_queue_starvation_count_ >= kMaxStarvationTasks &&
|
| + ChooseOldestWithPriority(kNormalPriority, out_queue_index)) {
|
| + normal_queue_starvation_count_ = 0;
|
| + return true;
|
| + }
|
| + // Otherwise choose in priority order.
|
| + static const QueuePriority kPriorities[] = {
|
| + kHighPriority, kNormalPriority, kBestEffortPriority};
|
| + for (QueuePriority priority : kPriorities) {
|
| + if (ChooseOldestWithPriority(priority, out_queue_index)) {
|
| + if (priority == kHighPriority) {
|
| + normal_queue_starvation_count_++;
|
| + } else {
|
| + normal_queue_starvation_count_ = 0;
|
| + }
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +} // namespace content
|
|
|