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); |
} |