| // 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 <algorithm> |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/task_runner.h" |
| #include "base/task_scheduler/task.h" |
| |
| namespace base { |
| namespace internal { |
| |
| DelayedTaskManager::DelayedTaskManager( |
| std::unique_ptr<const 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( |
| Task task, |
| PostTaskNowCallback post_task_now_callback) { |
| DCHECK(task.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); |
| |
| // 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( |
| Task task, |
| TimeDelta delay, |
| PostTaskNowCallback post_task_now_callback) { |
| DCHECK(task.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(std::move(post_task_now_callback), std::move(task)), |
| delay); |
| } |
| |
| } // namespace internal |
| } // namespace base |