blob: 7afcea9586c8d925136e7f7580fa998a8f841899 [file] [log] [blame]
// Copyright 2018 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 "third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/logging.h"
#include "base/trace_event/traced_value.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
namespace blink {
namespace scheduler {
using base::sequence_manager::TaskQueue;
using QueueTraits = MainThreadTaskQueue::QueueTraits;
using QueueEnabledVoter = base::sequence_manager::TaskQueue::QueueEnabledVoter;
FrameTaskQueueController::FrameTaskQueueController(
MainThreadSchedulerImpl* main_thread_scheduler_impl,
FrameSchedulerImpl* frame_scheduler_impl,
Delegate* delegate)
: main_thread_scheduler_impl_(main_thread_scheduler_impl),
frame_scheduler_impl_(frame_scheduler_impl),
delegate_(delegate) {
DCHECK(frame_scheduler_impl_);
DCHECK(delegate_);
}
FrameTaskQueueController::~FrameTaskQueueController() = default;
scoped_refptr<MainThreadTaskQueue>
FrameTaskQueueController::LoadingTaskQueue() {
if (!loading_task_queue_)
CreateLoadingTaskQueue();
DCHECK(loading_task_queue_);
return loading_task_queue_;
}
scoped_refptr<MainThreadTaskQueue>
FrameTaskQueueController::LoadingControlTaskQueue() {
if (!loading_control_task_queue_)
CreateLoadingControlTaskQueue();
DCHECK(loading_control_task_queue_);
return loading_control_task_queue_;
}
scoped_refptr<MainThreadTaskQueue>
FrameTaskQueueController::InspectorTaskQueue() {
if (!inspector_task_queue_) {
inspector_task_queue_ = main_thread_scheduler_impl_->NewTaskQueue(
MainThreadTaskQueue::QueueCreationParams(
MainThreadTaskQueue::QueueType::kDefault)
.SetFrameScheduler(frame_scheduler_impl_));
TaskQueueCreated(inspector_task_queue_);
}
return inspector_task_queue_;
}
scoped_refptr<MainThreadTaskQueue>
FrameTaskQueueController::ExperimentalWebSchedulingTaskQueue(
WebSchedulingTaskQueueType task_queue_type) {
if (!web_scheduling_task_queues_[task_queue_type])
CreateWebSchedulingTaskQueue(task_queue_type);
DCHECK(web_scheduling_task_queues_[task_queue_type]);
return web_scheduling_task_queues_[task_queue_type];
}
scoped_refptr<MainThreadTaskQueue>
FrameTaskQueueController::NonLoadingTaskQueue(
MainThreadTaskQueue::QueueTraits queue_traits) {
if (!non_loading_task_queues_.Contains(queue_traits.Key()))
CreateNonLoadingTaskQueue(queue_traits);
auto it = non_loading_task_queues_.find(queue_traits.Key());
DCHECK(it != non_loading_task_queues_.end());
return it->value;
}
const std::vector<FrameTaskQueueController::TaskQueueAndEnabledVoterPair>&
FrameTaskQueueController::GetAllTaskQueuesAndVoters() const {
return all_task_queues_and_voters_;
}
void FrameTaskQueueController::CreateLoadingTaskQueue() {
DCHECK(!loading_task_queue_);
// |main_thread_scheduler_impl_| can be null in unit tests.
DCHECK(main_thread_scheduler_impl_);
loading_task_queue_ = main_thread_scheduler_impl_->NewLoadingTaskQueue(
MainThreadTaskQueue::QueueType::kFrameLoading, frame_scheduler_impl_);
TaskQueueCreated(loading_task_queue_);
}
void FrameTaskQueueController::CreateWebSchedulingTaskQueue(
WebSchedulingTaskQueueType task_queue_type) {
DCHECK(RuntimeEnabledFeatures::WorkerTaskQueueEnabled());
DCHECK(!web_scheduling_task_queues_[task_queue_type]);
// |main_thread_scheduler_impl_| can be null in unit tests.
DCHECK(main_thread_scheduler_impl_);
MainThreadTaskQueue::QueueType main_thread_queue_type =
MainThreadTaskQueue::QueueType::kDefault;
switch (task_queue_type) {
case kWebSchedulingUserVisiblePriority:
main_thread_queue_type =
MainThreadTaskQueue::QueueType::kWebSchedulingUserInteraction;
break;
case kWebSchedulingBestEffortPriority:
main_thread_queue_type =
MainThreadTaskQueue::QueueType::kWebSchedulingBestEffort;
break;
case kWebSchedulingPriorityCount:
NOTREACHED();
}
scoped_refptr<MainThreadTaskQueue> task_queue =
main_thread_scheduler_impl_->NewTaskQueue(
MainThreadTaskQueue::QueueCreationParams(main_thread_queue_type)
.SetCanBePaused(true)
.SetCanBeFrozen(true)
.SetCanBeDeferred(task_queue_type !=
kWebSchedulingUserVisiblePriority)
.SetCanBeThrottled(true)
.SetFrameScheduler(frame_scheduler_impl_));
TaskQueueCreated(task_queue);
web_scheduling_task_queues_[task_queue_type] = task_queue;
}
void FrameTaskQueueController::CreateLoadingControlTaskQueue() {
DCHECK(!loading_control_task_queue_);
// |main_thread_scheduler_impl_| can be null in unit tests.
DCHECK(main_thread_scheduler_impl_);
loading_control_task_queue_ =
main_thread_scheduler_impl_->NewLoadingTaskQueue(
MainThreadTaskQueue::QueueType::kFrameLoadingControl,
frame_scheduler_impl_);
TaskQueueCreated(loading_control_task_queue_);
}
scoped_refptr<MainThreadTaskQueue>
FrameTaskQueueController::NewResourceLoadingTaskQueue() {
scoped_refptr<MainThreadTaskQueue> task_queue =
main_thread_scheduler_impl_->NewLoadingTaskQueue(
MainThreadTaskQueue::QueueType::kFrameLoading, frame_scheduler_impl_);
TaskQueueCreated(task_queue);
resource_loading_task_queues_.insert(task_queue);
return task_queue;
}
void FrameTaskQueueController::CreateNonLoadingTaskQueue(
QueueTraits queue_traits) {
DCHECK(!non_loading_task_queues_.Contains(queue_traits.Key()));
// |main_thread_scheduler_impl_| can be null in unit tests.
DCHECK(main_thread_scheduler_impl_);
scoped_refptr<MainThreadTaskQueue> task_queue =
main_thread_scheduler_impl_->NewTaskQueue(
MainThreadTaskQueue::QueueCreationParams(
QueueTypeFromQueueTraits(queue_traits))
.SetQueueTraits(queue_traits)
// Freeze when keep active is currently only set for the
// throttleable queue.
// TODO(altimin): Figure out how to set this for new queues.
// Investigate which tasks must be kept alive, and if possible
// move them to an unfreezable queue and remove this override and
// the page scheduler KeepActive freezing override.
.SetFreezeWhenKeepActive(queue_traits.can_be_throttled)
.SetFrameScheduler(frame_scheduler_impl_));
TaskQueueCreated(task_queue);
non_loading_task_queues_.insert(queue_traits.Key(), task_queue);
}
void FrameTaskQueueController::TaskQueueCreated(
const scoped_refptr<MainThreadTaskQueue>& task_queue) {
DCHECK(task_queue);
std::unique_ptr<QueueEnabledVoter> voter;
// Only create a voter for queues that can be disabled.
if (task_queue->CanBePaused() || task_queue->CanBeFrozen())
voter = task_queue->CreateQueueEnabledVoter();
delegate_->OnTaskQueueCreated(task_queue.get(), voter.get());
all_task_queues_and_voters_.push_back(
TaskQueueAndEnabledVoterPair(task_queue.get(), voter.get()));
if (voter) {
DCHECK(task_queue_enabled_voters_.find(task_queue) ==
task_queue_enabled_voters_.end());
task_queue_enabled_voters_.insert(task_queue, std::move(voter));
}
}
base::sequence_manager::TaskQueue::QueueEnabledVoter*
FrameTaskQueueController::GetQueueEnabledVoter(
const scoped_refptr<MainThreadTaskQueue>& task_queue) {
auto it = task_queue_enabled_voters_.find(task_queue);
if (it == task_queue_enabled_voters_.end())
return nullptr;
return it->value.get();
}
bool FrameTaskQueueController::RemoveResourceLoadingTaskQueue(
const scoped_refptr<MainThreadTaskQueue>& task_queue) {
DCHECK(task_queue);
if (!resource_loading_task_queues_.Contains(task_queue))
return false;
resource_loading_task_queues_.erase(task_queue);
DCHECK(task_queue_enabled_voters_.Contains(task_queue));
task_queue_enabled_voters_.erase(task_queue);
bool found_task_queue = false;
for (auto it = all_task_queues_and_voters_.begin();
it != all_task_queues_and_voters_.end(); ++it) {
if (it->first == task_queue.get()) {
found_task_queue = true;
all_task_queues_and_voters_.erase(it);
break;
}
}
DCHECK(found_task_queue);
return true;
}
void FrameTaskQueueController::AsValueInto(
base::trace_event::TracedValue* state) const {
if (loading_task_queue_) {
state->SetString("loading_task_queue",
PointerToString(loading_task_queue_.get()));
}
if (loading_control_task_queue_) {
state->SetString("loading_control_task_queue",
PointerToString(loading_control_task_queue_.get()));
}
state->BeginArray("non_loading_task_queues");
for (const auto it : non_loading_task_queues_) {
state->AppendString(PointerToString(it.value.get()));
}
state->EndArray();
state->BeginArray("resource_loading_task_queues");
for (const auto& queue : resource_loading_task_queues_) {
state->AppendString(PointerToString(queue.get()));
}
state->EndArray();
}
// static
MainThreadTaskQueue::QueueType
FrameTaskQueueController::QueueTypeFromQueueTraits(QueueTraits queue_traits) {
if (queue_traits.can_be_throttled)
return MainThreadTaskQueue::QueueType::kFrameThrottleable;
if (queue_traits.can_be_deferred)
return MainThreadTaskQueue::QueueType::kFrameDeferrable;
if (queue_traits.can_be_paused)
return MainThreadTaskQueue::QueueType::kFramePausable;
return MainThreadTaskQueue::QueueType::kFrameUnpausable;
}
} // namespace scheduler
} // namespace blink