| Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 5 | #include "base/one_shot_event.h" |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 6 | |
| avi | 2d124c0 | 2015-12-23 06:36:42 | [diff] [blame] | 7 | #include <stddef.h> |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 8 | |
| 9 | #include <algorithm> |
| Karandeep Bhatia | 57a637c | 2020-04-20 23:07:12 | [diff] [blame] | 10 | #include <utility> |
| avi | 2d124c0 | 2015-12-23 06:36:42 | [diff] [blame] | 11 | |
| Avi Drissman | 63e1f99 | 2023-01-13 18:54:43 | [diff] [blame] | 12 | #include "base/functional/callback.h" |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 13 | #include "base/location.h" |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 14 | #include "base/sequence_checker.h" |
| Patrick Monette | 643cdf6 | 2021-10-15 19:13:42 | [diff] [blame] | 15 | #include "base/task/task_runner.h" |
| [email protected] | e5f8fffe | 2014-04-02 00:30:44 | [diff] [blame] | 16 | #include "base/time/time.h" |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 17 | |
| Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 18 | namespace base { |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 19 | |
| 20 | struct OneShotEvent::TaskInfo { |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 21 | TaskInfo() = default; |
| Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 22 | TaskInfo(const Location& from_here, |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 23 | scoped_refptr<TaskRunner> runner, |
| Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 24 | OnceClosure task, |
| 25 | const TimeDelta& delay) |
| Mikel Astiz | e05037e | 2019-03-29 20:44:24 | [diff] [blame] | 26 | : from_here(from_here), |
| Karandeep Bhatia | 57a637c | 2020-04-20 23:07:12 | [diff] [blame] | 27 | runner(std::move(runner)), |
| Mikel Astiz | e05037e | 2019-03-29 20:44:24 | [diff] [blame] | 28 | task(std::move(task)), |
| 29 | delay(delay) { |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 30 | CHECK(this->runner); // Detect mistakes with a decent stack frame. |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 31 | } |
| Mikel Astiz | e05037e | 2019-03-29 20:44:24 | [diff] [blame] | 32 | TaskInfo(TaskInfo&&) = default; |
| Karandeep Bhatia | 57a637c | 2020-04-20 23:07:12 | [diff] [blame] | 33 | TaskInfo& operator=(TaskInfo&&) = default; |
| Mikel Astiz | e05037e | 2019-03-29 20:44:24 | [diff] [blame] | 34 | |
| Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 35 | Location from_here; |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 36 | scoped_refptr<TaskRunner> runner; |
| Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 37 | OnceClosure task; |
| 38 | TimeDelta delay; |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 39 | }; |
| 40 | |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 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_); |
| [email protected] | 89c44672e | 2013-05-23 04:32:09 | [diff] [blame] | 45 | } |
| [email protected] | ebf16b2 | 2013-12-19 09:46:01 | [diff] [blame] | 46 | OneShotEvent::OneShotEvent(bool signaled) : signaled_(signaled) { |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 47 | DETACH_FROM_SEQUENCE(sequence_checker_); |
| [email protected] | ebf16b2 | 2013-12-19 09:46:01 | [diff] [blame] | 48 | } |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 49 | OneShotEvent::~OneShotEvent() = default; |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 50 | |
| Karandeep Bhatia | 57a637c | 2020-04-20 23:07:12 | [diff] [blame] | 51 | void OneShotEvent::Post(const Location& from_here, |
| 52 | OnceClosure task, |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 53 | scoped_refptr<TaskRunner> runner) const { |
| 54 | PostDelayed(from_here, std::move(task), TimeDelta(), std::move(runner)); |
| [email protected] | e5f8fffe | 2014-04-02 00:30:44 | [diff] [blame] | 55 | } |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 56 | |
| Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 57 | void OneShotEvent::PostDelayed(const Location& from_here, |
| 58 | OnceClosure task, |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 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 | } |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | void OneShotEvent::Signal() { |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 71 | DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 72 | |
| 73 | CHECK(!signaled_) << "Only call Signal once."; |
| 74 | |
| 75 | signaled_ = true; |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 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. |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 79 | |
| Istiaque Ahmed | e2ea864 | 2018-06-18 22:00:12 | [diff] [blame] | 80 | // Move tasks to a temporary to ensure no new ones are added. |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 81 | std::vector<TaskInfo> moved_tasks = std::exchange(tasks_, {}); |
| Istiaque Ahmed | e2ea864 | 2018-06-18 22:00:12 | [diff] [blame] | 82 | |
| 83 | // We could randomize tasks in debug mode in order to check that |
| [email protected] | 4a10006a | 2013-05-17 23:18:35 | [diff] [blame] | 84 | // the order doesn't matter... |
| Mikel Astiz | e05037e | 2019-03-29 20:44:24 | [diff] [blame] | 85 | for (TaskInfo& task : moved_tasks) { |
| Luke Klimek | 965c89d4 | 2024-06-14 12:44:47 | [diff] [blame] | 86 | task.runner->PostDelayedTask(task.from_here, std::move(task.task), |
| 87 | task.delay); |
| [email protected] | e5f8fffe | 2014-04-02 00:30:44 | [diff] [blame] | 88 | } |
| Istiaque Ahmed | e2ea864 | 2018-06-18 22:00:12 | [diff] [blame] | 89 | DCHECK(tasks_.empty()) << "No new tasks should be added during task running!"; |
| [email protected] | e5f8fffe | 2014-04-02 00:30:44 | [diff] [blame] | 90 | } |
| 91 | |
| Christopher Lam | ebb9020 | 2019-04-04 03:42:36 | [diff] [blame] | 92 | } // namespace base |