| 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
|
| index 0bf7565a33957ae622b3f29b518df6d5e0be20b8..5cf1895fa44ead11336e3747465d5683d2d1ab0c 100644
|
| --- a/base/task_scheduler/delayed_task_manager.cc
|
| +++ b/base/task_scheduler/delayed_task_manager.cc
|
| @@ -4,7 +4,7 @@
|
|
|
| #include "base/task_scheduler/delayed_task_manager.h"
|
|
|
| -#include <utility>
|
| +#include <algorithm>
|
|
|
| #include "base/bind.h"
|
| #include "base/logging.h"
|
| @@ -14,30 +14,80 @@
|
| namespace base {
|
| namespace internal {
|
|
|
| -DelayedTaskManager::DelayedTaskManager(
|
| - scoped_refptr<TaskRunner> service_thread_task_runner)
|
| - : service_thread_task_runner_(std::move(service_thread_task_runner)) {
|
| - DCHECK(service_thread_task_runner_);
|
| +DelayedTaskManager::DelayedTaskManager(std::unique_ptr<TickClock> tick_clock)
|
| + : tick_clock_(std::move(tick_clock)) {
|
| + DCHECK(tick_clock_);
|
| }
|
|
|
| DelayedTaskManager::~DelayedTaskManager() = default;
|
|
|
| +void DelayedTaskManager::Start(
|
| + scoped_refptr<TaskRunner> service_thread_task_runner) {
|
| + DCHECK(service_thread_task_runner);
|
| +
|
| + decltype(tasks_added_before_start_) tasks_added_before_start;
|
| +
|
| + {
|
| + AutoSchedulerLock auto_lock(lock_);
|
| + DCHECK(!service_thread_task_runner_);
|
| + DCHECK(!started_.IsSet());
|
| + service_thread_task_runner_ = std::move(service_thread_task_runner);
|
| + tasks_added_before_start = std::move(tasks_added_before_start_);
|
| + // |service_thread_task_runner_| must not change after |started_| is set
|
| + // (cf. comment above |lock_| in header file).
|
| + started_.Set();
|
| + }
|
| +
|
| + const TimeTicks now = tick_clock_->NowTicks();
|
| + for (auto& task_and_callback : tasks_added_before_start) {
|
| + const TimeDelta delay =
|
| + std::max(TimeDelta(), task_and_callback.first->delayed_run_time - now);
|
| + AddDelayedTaskNow(std::move(task_and_callback.first), delay,
|
| + std::move(task_and_callback.second));
|
| + }
|
| +}
|
| +
|
| void DelayedTaskManager::AddDelayedTask(
|
| std::unique_ptr<Task> task,
|
| - const PostTaskNowCallback& post_task_now_callback) {
|
| + PostTaskNowCallback post_task_now_callback) {
|
| DCHECK(task);
|
|
|
| + const TimeDelta delay = task->delay;
|
| + DCHECK(!delay.is_zero());
|
| +
|
| // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
|
| // for details.
|
| CHECK(task->task);
|
|
|
| - const TimeDelta delay = task->delay;
|
| - DCHECK(!delay.is_zero());
|
| + // If |started_| is set, the DelayedTaskManager is in a stable state and
|
| + // AddDelayedTaskNow() can be called without synchronization. Otherwise, it is
|
| + // necessary to acquire |lock_| and recheck.
|
| + if (started_.IsSet()) {
|
| + AddDelayedTaskNow(std::move(task), delay,
|
| + std::move(post_task_now_callback));
|
| + } else {
|
| + AutoSchedulerLock auto_lock(lock_);
|
| + if (started_.IsSet()) {
|
| + AddDelayedTaskNow(std::move(task), delay,
|
| + std::move(post_task_now_callback));
|
| + } else {
|
| + tasks_added_before_start_.push_back(
|
| + {std::move(task), std::move(post_task_now_callback)});
|
| + }
|
| + }
|
| +}
|
|
|
| +void DelayedTaskManager::AddDelayedTaskNow(
|
| + std::unique_ptr<Task> task,
|
| + TimeDelta delay,
|
| + PostTaskNowCallback post_task_now_callback) {
|
| + DCHECK(task);
|
| + DCHECK(started_.IsSet());
|
| // TODO(fdoray): Use |task->delayed_run_time| on the service thread
|
| // MessageLoop rather than recomputing it from |delay|.
|
| service_thread_task_runner_->PostDelayedTask(
|
| - FROM_HERE, BindOnce(post_task_now_callback, Passed(std::move(task))),
|
| + FROM_HERE,
|
| + BindOnce(std::move(post_task_now_callback), Passed(std::move(task))),
|
| delay);
|
| }
|
|
|
|
|