/proc/self/cwd/pw_async_basic/fake_dispatcher.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2023 The Pigweed Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
4 | | // use this file except in compliance with the License. You may obtain a copy of |
5 | | // the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
11 | | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
12 | | // License for the specific language governing permissions and limitations under |
13 | | // the License. |
14 | | |
15 | | #include "pw_async/fake_dispatcher.h" |
16 | | |
17 | | #include "pw_async/task.h" |
18 | | #include "pw_log/log.h" |
19 | | |
20 | | using namespace std::chrono_literals; |
21 | | |
22 | | namespace pw::async::test::backend { |
23 | | |
24 | | NativeFakeDispatcher::NativeFakeDispatcher(Dispatcher& dispatcher) |
25 | 15.1k | : dispatcher_(dispatcher) {} |
26 | | |
27 | 15.1k | NativeFakeDispatcher::~NativeFakeDispatcher() { |
28 | 15.1k | RequestStop(); |
29 | 15.1k | DrainTaskQueue(); |
30 | 15.1k | } |
31 | | |
32 | 6.96M | bool NativeFakeDispatcher::RunUntilIdle() { |
33 | 6.96M | bool tasks_ran = ExecuteDueTasks(); |
34 | 6.96M | if (stop_requested_) { |
35 | 0 | tasks_ran |= DrainTaskQueue(); |
36 | 0 | } |
37 | 6.96M | return tasks_ran; |
38 | 6.96M | } |
39 | | |
40 | 4.03M | bool NativeFakeDispatcher::RunUntil(chrono::SystemClock::time_point end_time) { |
41 | 4.03M | bool tasks_ran = false; |
42 | 8.79M | while (!task_queue_.empty() && task_queue_.front().due_time() <= end_time && |
43 | 8.79M | !stop_requested_) { |
44 | 4.75M | now_ = task_queue_.front().due_time(); |
45 | 4.75M | tasks_ran |= ExecuteDueTasks(); |
46 | 4.75M | } |
47 | | |
48 | 4.03M | if (stop_requested_) { |
49 | 0 | tasks_ran |= DrainTaskQueue(); |
50 | 0 | return tasks_ran; |
51 | 0 | } |
52 | | |
53 | 4.03M | if (now_ < end_time) { |
54 | 600k | now_ = end_time; |
55 | 600k | } |
56 | 4.03M | return tasks_ran; |
57 | 4.03M | } |
58 | | |
59 | 4.03M | bool NativeFakeDispatcher::RunFor(chrono::SystemClock::duration duration) { |
60 | 4.03M | return RunUntil(now() + duration); |
61 | 4.03M | } |
62 | | |
63 | 11.7M | bool NativeFakeDispatcher::ExecuteDueTasks() { |
64 | 11.7M | bool task_ran = false; |
65 | 17.4M | while (!task_queue_.empty() && task_queue_.front().due_time() <= now() && |
66 | 17.4M | !stop_requested_) { |
67 | 5.73M | ::pw::async::backend::NativeTask& task = task_queue_.front(); |
68 | 5.73M | task_queue_.pop_front(); |
69 | | |
70 | 5.73M | Context ctx{&dispatcher_, &task.task_}; |
71 | 5.73M | task(ctx, OkStatus()); |
72 | | |
73 | 5.73M | task_ran = true; |
74 | 5.73M | } |
75 | 11.7M | return task_ran; |
76 | 11.7M | } |
77 | | |
78 | 15.1k | void NativeFakeDispatcher::RequestStop() { |
79 | 15.1k | PW_LOG_DEBUG("stop requested"); |
80 | 15.1k | stop_requested_ = true; |
81 | 15.1k | } |
82 | | |
83 | 15.1k | bool NativeFakeDispatcher::DrainTaskQueue() { |
84 | 15.1k | bool task_ran = false; |
85 | 15.1k | while (!task_queue_.empty()) { |
86 | 0 | ::pw::async::backend::NativeTask& task = task_queue_.front(); |
87 | 0 | task_queue_.pop_front(); |
88 | |
|
89 | 0 | PW_LOG_DEBUG("running cancelled task"); |
90 | 0 | Context ctx{&dispatcher_, &task.task_}; |
91 | 0 | task(ctx, Status::Cancelled()); |
92 | |
|
93 | 0 | task_ran = true; |
94 | 0 | } |
95 | 15.1k | return task_ran; |
96 | 15.1k | } |
97 | | |
98 | 0 | void NativeFakeDispatcher::Post(Task& task) { PostAt(task, now()); } |
99 | | |
100 | | void NativeFakeDispatcher::PostAfter(Task& task, |
101 | 6.54M | chrono::SystemClock::duration delay) { |
102 | 6.54M | PostAt(task, now() + delay); |
103 | 6.54M | } |
104 | | |
105 | | void NativeFakeDispatcher::PostAt(Task& task, |
106 | 7.08M | chrono::SystemClock::time_point time) { |
107 | 7.08M | PW_LOG_DEBUG("posting task"); |
108 | 7.08M | PostTaskInternal(task.native_type(), time); |
109 | 7.08M | } |
110 | | |
111 | 6.66M | bool NativeFakeDispatcher::Cancel(Task& task) { |
112 | 6.66M | return task_queue_.remove(task.native_type()); |
113 | 6.66M | } |
114 | | |
115 | | void NativeFakeDispatcher::PostTaskInternal( |
116 | | ::pw::async::backend::NativeTask& task, |
117 | 7.08M | chrono::SystemClock::time_point time_due) { |
118 | 7.08M | if (!task.unlisted()) { |
119 | 0 | if (task.due_time() <= time_due) { |
120 | | // No need to repost a task that was already queued to run. |
121 | 0 | return; |
122 | 0 | } |
123 | | // The task needs its time updated, so we have to move it to |
124 | | // a different part of the list. |
125 | 0 | task.unlist(); |
126 | 0 | } |
127 | 7.08M | task.set_due_time(time_due); |
128 | 7.08M | auto it_front = task_queue_.begin(); |
129 | 7.08M | auto it_behind = task_queue_.before_begin(); |
130 | 346M | while (it_front != task_queue_.end() && time_due >= it_front->due_time()) { |
131 | 339M | ++it_front; |
132 | 339M | ++it_behind; |
133 | 339M | } |
134 | 7.08M | task_queue_.insert_after(it_behind, task); |
135 | 7.08M | } |
136 | | |
137 | | } // namespace pw::async::test::backend |