// Copyright 2013 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/one_shot_event.h" #include #include #include "base/functional/callback.h" #include "base/location.h" #include "base/task/single_thread_task_runner.h" #include "base/task/task_runner.h" #include "base/time/time.h" namespace base { struct OneShotEvent::TaskInfo { TaskInfo() {} TaskInfo(const Location& from_here, scoped_refptr runner, OnceClosure task, const TimeDelta& delay) : from_here(from_here), runner(std::move(runner)), task(std::move(task)), delay(delay) { CHECK(this->runner.get()); // Detect mistakes with a decent stack frame. } TaskInfo(TaskInfo&&) = default; TaskInfo& operator=(TaskInfo&&) = default; Location from_here; scoped_refptr runner; OnceClosure task; TimeDelta delay; }; OneShotEvent::OneShotEvent() : signaled_(false) { // It's acceptable to construct the OneShotEvent on one thread, but // immediately move it to another thread. thread_checker_.DetachFromThread(); } OneShotEvent::OneShotEvent(bool signaled) : signaled_(signaled) { thread_checker_.DetachFromThread(); } OneShotEvent::~OneShotEvent() {} void OneShotEvent::Post(const Location& from_here, OnceClosure task, scoped_refptr runner) const { PostImpl(from_here, std::move(task), std::move(runner), TimeDelta()); } void OneShotEvent::PostDelayed(const Location& from_here, OnceClosure task, const TimeDelta& delay) const { PostImpl(from_here, std::move(task), SingleThreadTaskRunner::GetCurrentDefault(), delay); } void OneShotEvent::Signal() { DCHECK(thread_checker_.CalledOnValidThread()); CHECK(!signaled_) << "Only call Signal once."; signaled_ = true; // After this point, a call to Post() from one of the queued tasks // could proceed immediately, but the fact that this object is // single-threaded prevents that from being relevant. // Move tasks to a temporary to ensure no new ones are added. std::vector moved_tasks; std::swap(moved_tasks, tasks_); // We could randomize tasks in debug mode in order to check that // the order doesn't matter... for (TaskInfo& task : moved_tasks) { if (task.delay.is_zero()) task.runner->PostTask(task.from_here, std::move(task.task)); else task.runner->PostDelayedTask(task.from_here, std::move(task.task), task.delay); } DCHECK(tasks_.empty()) << "No new tasks should be added during task running!"; } void OneShotEvent::PostImpl(const Location& from_here, OnceClosure task, scoped_refptr runner, const TimeDelta& delay) const { DCHECK(thread_checker_.CalledOnValidThread()); if (is_signaled()) { if (delay.is_zero()) runner->PostTask(from_here, std::move(task)); else runner->PostDelayedTask(from_here, std::move(task), delay); } else { tasks_.emplace_back(from_here, std::move(runner), std::move(task), delay); } } } // namespace base