• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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