1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/one_shot_event.h"
6
7 #include <stddef.h>
8
9 #include <algorithm>
10 #include <utility>
11
12 #include "base/functional/callback.h"
13 #include "base/location.h"
14 #include "base/sequence_checker.h"
15 #include "base/task/task_runner.h"
16 #include "base/time/time.h"
17
18 namespace base {
19
20 struct OneShotEvent::TaskInfo {
21 TaskInfo() = default;
TaskInfobase::OneShotEvent::TaskInfo22 TaskInfo(const Location& from_here,
23 scoped_refptr<TaskRunner> runner,
24 OnceClosure task,
25 const TimeDelta& delay)
26 : from_here(from_here),
27 runner(std::move(runner)),
28 task(std::move(task)),
29 delay(delay) {
30 CHECK(this->runner); // Detect mistakes with a decent stack frame.
31 }
32 TaskInfo(TaskInfo&&) = default;
33 TaskInfo& operator=(TaskInfo&&) = default;
34
35 Location from_here;
36 scoped_refptr<TaskRunner> runner;
37 OnceClosure task;
38 TimeDelta delay;
39 };
40
OneShotEvent()41 OneShotEvent::OneShotEvent() {
42 // It's acceptable to construct the `OneShotEvent` on one sequence, but
43 // immediately move it to another sequence.
44 DETACH_FROM_SEQUENCE(sequence_checker_);
45 }
OneShotEvent(bool signaled)46 OneShotEvent::OneShotEvent(bool signaled) : signaled_(signaled) {
47 DETACH_FROM_SEQUENCE(sequence_checker_);
48 }
49 OneShotEvent::~OneShotEvent() = default;
50
Post(const Location & from_here,OnceClosure task,scoped_refptr<TaskRunner> runner) const51 void OneShotEvent::Post(const Location& from_here,
52 OnceClosure task,
53 scoped_refptr<TaskRunner> runner) const {
54 PostDelayed(from_here, std::move(task), TimeDelta(), std::move(runner));
55 }
56
PostDelayed(const Location & from_here,OnceClosure task,const TimeDelta & delay,scoped_refptr<TaskRunner> runner) const57 void OneShotEvent::PostDelayed(const Location& from_here,
58 OnceClosure task,
59 const TimeDelta& delay,
60 scoped_refptr<TaskRunner> runner) const {
61 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
62
63 if (is_signaled()) {
64 runner->PostDelayedTask(from_here, std::move(task), delay);
65 } else {
66 tasks_.emplace_back(from_here, std::move(runner), std::move(task), delay);
67 }
68 }
69
Signal()70 void OneShotEvent::Signal() {
71 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
72
73 CHECK(!signaled_) << "Only call Signal once.";
74
75 signaled_ = true;
76 // After this point, a call to `Post` from one of the queued tasks could
77 // proceed immediately, but the fact that this object is sequence-bound
78 // prevents that from being relevant.
79
80 // Move tasks to a temporary to ensure no new ones are added.
81 std::vector<TaskInfo> moved_tasks = std::exchange(tasks_, {});
82
83 // We could randomize tasks in debug mode in order to check that
84 // the order doesn't matter...
85 for (TaskInfo& task : moved_tasks) {
86 task.runner->PostDelayedTask(task.from_here, std::move(task.task),
87 task.delay);
88 }
89 DCHECK(tasks_.empty()) << "No new tasks should be added during task running!";
90 }
91
92 } // namespace base
93