| Index: base/task_scheduler/delayed_task_manager.cc
|
| diff --git a/base/task_scheduler/delayed_task_manager.cc b/base/task_scheduler/delayed_task_manager.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..91fc23782b3a294142a6a8e0acef99faf2f21ea1
|
| --- /dev/null
|
| +++ b/base/task_scheduler/delayed_task_manager.cc
|
| @@ -0,0 +1,144 @@
|
| +// Copyright 2016 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 "base/task_scheduler/delayed_task_manager.h"
|
| +
|
| +#include <utility>
|
| +#include <vector>
|
| +
|
| +#include "base/logging.h"
|
| +
|
| +namespace base {
|
| +namespace internal {
|
| +
|
| +struct DelayedTaskManager::DelayedTask {
|
| + DelayedTask() = default;
|
| + DelayedTask(std::unique_ptr<Task> task,
|
| + const PostTaskCallback& post_task_callback,
|
| + size_t index);
|
| + DelayedTask(DelayedTask&& other);
|
| + DelayedTask& operator=(DelayedTask&& other);
|
| +
|
| + ~DelayedTask() = default;
|
| +
|
| + std::unique_ptr<Task> task;
|
| + PostTaskCallback post_task_callback;
|
| +
|
| + // Ensures that tasks that have the same |delayed_run_time| are sorted
|
| + // according to the order in which they were created.
|
| + size_t index;
|
| +};
|
| +
|
| +DelayedTaskManager::DelayedTaskManager(const Closure& delayed_run_time_changed)
|
| + : delayed_run_time_changed_(delayed_run_time_changed) {
|
| + DCHECK(!delayed_run_time_changed_.is_null());
|
| +}
|
| +
|
| +DelayedTaskManager::~DelayedTaskManager() = default;
|
| +
|
| +void DelayedTaskManager::AddDelayedTask(
|
| + std::unique_ptr<Task> task,
|
| + const PostTaskCallback& post_task_callback) {
|
| + DCHECK(task);
|
| + DCHECK(!post_task_callback.is_null());
|
| +
|
| + const TimeTicks new_task_delayed_run_time = task->delayed_run_time;
|
| + TimeTicks previous_delayed_run_time;
|
| +
|
| + {
|
| + AutoSchedulerLock auto_lock(lock_);
|
| +
|
| + if (!delayed_tasks_.empty())
|
| + previous_delayed_run_time = delayed_tasks_.top().task->delayed_run_time;
|
| +
|
| + delayed_tasks_.emplace(std::move(task), post_task_callback,
|
| + next_delayed_task_index_++);
|
| + }
|
| +
|
| + if (previous_delayed_run_time.is_null() ||
|
| + new_task_delayed_run_time < previous_delayed_run_time) {
|
| + delayed_run_time_changed_.Run();
|
| + }
|
| +}
|
| +
|
| +void DelayedTaskManager::PostReadyTasks() {
|
| + const TimeTicks now = Now();
|
| +
|
| + // Move delayed tasks that are ready for execution into |ready_tasks|. Don't
|
| + // post them right away to avoid imposing an unecessary lock dependency on
|
| + // callbacks.
|
| + std::vector<DelayedTask> ready_tasks;
|
| +
|
| + {
|
| + AutoSchedulerLock auto_lock(lock_);
|
| + while (!delayed_tasks_.empty() &&
|
| + delayed_tasks_.top().task->delayed_run_time <= now) {
|
| + // The const_cast for std::move is almost okay since we're immediately
|
| + // moving it to |ready_tasks|. See DelayedTaskComparator::operator() for
|
| + // why it's almost.
|
| + ready_tasks.emplace_back(
|
| + std::move(const_cast<DelayedTask&>(delayed_tasks_.top())));
|
| + delayed_tasks_.pop();
|
| + }
|
| + }
|
| +
|
| + // Post delayed tasks that are ready for execution.
|
| + for (auto& delayed_task : ready_tasks)
|
| + delayed_task.post_task_callback.Run(std::move(delayed_task.task));
|
| +}
|
| +
|
| +TimeTicks DelayedTaskManager::GetNextDelayedRunTime() const {
|
| + AutoSchedulerLock auto_lock(lock_);
|
| +
|
| + if (delayed_tasks_.empty())
|
| + return TimeTicks();
|
| +
|
| + return delayed_tasks_.top().task->delayed_run_time;
|
| +}
|
| +
|
| +TimeTicks DelayedTaskManager::Now() {
|
| + return TimeTicks::Now();
|
| +}
|
| +
|
| +DelayedTaskManager::DelayedTask::DelayedTask(
|
| + std::unique_ptr<Task> task,
|
| + const PostTaskCallback& post_task_callback,
|
| + size_t index)
|
| + : task(std::move(task)),
|
| + post_task_callback(post_task_callback),
|
| + index(index) {}
|
| +
|
| +DelayedTaskManager::DelayedTask::DelayedTask(DelayedTask&& other)
|
| + : task(std::move(other.task)),
|
| + post_task_callback(other.post_task_callback),
|
| + index(other.index) {}
|
| +
|
| +DelayedTaskManager::DelayedTask& DelayedTaskManager::DelayedTask::operator=(
|
| + DelayedTask&& other) {
|
| + task = std::move(other.task);
|
| + post_task_callback = other.post_task_callback;
|
| + index = other.index;
|
| + return *this;
|
| +}
|
| +
|
| +bool DelayedTaskManager::DelayedTaskComparator::operator()(
|
| + const DelayedTask& left,
|
| + const DelayedTask& right) const {
|
| + // Due to STL consistency checks in Windows and const_cast'ing right before
|
| + // popping the DelayedTask, we might actually have null tasks.
|
| + // To keep the order of the data structure the same, we consider null tasks
|
| + // to be the smallest possible |delayed_run_time|.
|
| + if (!left.task)
|
| + return false;
|
| + if (!right.task)
|
| + return true;
|
| + if (left.task->delayed_run_time > right.task->delayed_run_time)
|
| + return true;
|
| + if (left.task->delayed_run_time < right.task->delayed_run_time)
|
| + return false;
|
| + return left.index > right.index;
|
| +}
|
| +
|
| +} // namespace internal
|
| +} // namespace base
|
|
|