C/C++ API Reference
Loading...
Searching...
No Matches
dispatcher.h
1// Copyright 2025 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#pragma once
15
16#include <atomic>
17#include <mutex>
18
19#include "pw_async2/context.h"
20#include "pw_async2/internal/lock.h"
21#include "pw_async2/task.h"
22#include "pw_async2/waker.h"
23#include "pw_containers/intrusive_list.h"
24#include "pw_sync/lock_annotations.h"
25
26namespace pw::async2 {
27namespace internal {
28
29template <typename T>
30using PendOutputOf = typename decltype(std::declval<T>().Pend(
31 std::declval<Context&>()))::value_type;
32
33} // namespace internal
34
36
54 public:
55 Dispatcher(Dispatcher&) = delete;
56 Dispatcher& operator=(Dispatcher&) = delete;
57
58 Dispatcher(Dispatcher&&) = delete;
59 Dispatcher& operator=(Dispatcher&&) = delete;
60
61 virtual ~Dispatcher() { Deregister(); }
62
72 void Post(Task& task) PW_LOCKS_EXCLUDED(internal::lock());
73
76 void LogRegisteredTasks() PW_LOCKS_EXCLUDED(internal::lock());
77
78 protected:
79 constexpr Dispatcher() = default;
80
89 bool PopAndRunAllReadyTasks() PW_LOCKS_EXCLUDED(internal::lock());
90
95 Task* PopTaskToRun() PW_LOCKS_EXCLUDED(internal::lock()) {
96 std::lock_guard lock(internal::lock());
97 return PopTaskToRunLocked();
98 }
99
112 Task* PopTaskToRun(bool& has_posted_tasks)
113 PW_LOCKS_EXCLUDED(internal::lock()) {
114 std::lock_guard lock(internal::lock());
115 Task* task = PopTaskToRunLocked();
116 has_posted_tasks = task != nullptr || !sleeping_.empty();
117 return task;
118 }
119
124 std::lock_guard lock(internal::lock());
125 set_wants_wake();
126 return PopTaskToRunLocked();
127 }
128
133 kActive = Task::kActive,
134
136 kDeregistered = Task::kDeregistered,
137
139 kCompleted = Task::kCompleted,
140 };
141
149 RunTaskResult RunTask(Task& task) PW_LOCKS_EXCLUDED(internal::lock());
150
151 private:
152 friend class Task;
153 friend class Waker;
154
155 // Allow DispatcherForTestFacade to wrap another dispatcher (call Do*).
156 template <typename>
157 friend class DispatcherForTestFacade;
158
173 virtual void DoWake() PW_LOCKS_EXCLUDED(internal::lock()) = 0;
174
175 void Wake() {
176 if (wanted_wake()) {
177 DoWake();
178 }
179 }
180
181 Task* PopTaskToRunLocked() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
182
183 // Removes references to this `Dispatcher` from all linked `Task`s and
184 // `Waker`s.
185 void Deregister() PW_LOCKS_EXCLUDED(internal::lock());
186
187 static void UnpostTaskList(IntrusiveList<Task>& list)
188 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
189
190 void RemoveWokenTaskLocked(Task& task)
191 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
192 woken_.remove(task);
193 }
194 void RemoveSleepingTaskLocked(Task& task)
195 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
196 sleeping_.remove(task);
197 }
198 void AddSleepingTaskLocked(Task& task)
199 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
200 sleeping_.push_front(task);
201 }
202
203 // For use by ``Waker``.
204 void WakeTask(Task& task) PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
205
206 void LogTaskWakers(const Task& task)
207 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
208
209 // Indicates that this Dispatcher should be woken when Wake() is called. This
210 // prevents unnecessary wakes when, for example, multiple wakers wake the same
211 // task or multiple tasks are posted before the dipsatcher runs.
212 //
213 // Must be called while the lock is held to prevent missed wakes.
214 void set_wants_wake() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
215 wants_wake_.store(true, std::memory_order_relaxed);
216 }
217
218 [[nodiscard]] bool wanted_wake() PW_NO_LOCK_SAFETY_ANALYSIS {
219 return wants_wake_.exchange(false, std::memory_order_relaxed);
220 }
221
222 IntrusiveList<Task> woken_ PW_GUARDED_BY(internal::lock());
223 IntrusiveList<Task> sleeping_ PW_GUARDED_BY(internal::lock());
224
225 // Latches wake requests to avoid duplicate DoWake calls.
226 std::atomic<bool> wants_wake_ PW_GUARDED_BY(internal::lock()) = false;
227};
228
230
231} // namespace pw::async2
Definition: dispatcher_for_test.h:53
Definition: dispatcher.h:53
Task * PopTaskToRun(bool &has_posted_tasks)
Definition: dispatcher.h:112
virtual void DoWake()=0
RunTaskResult
Definition: dispatcher.h:131
@ kDeregistered
The task was removed from the dispatcher by another thread.
Definition: dispatcher.h:136
@ kActive
The task is still posted to the dispatcher.
Definition: dispatcher.h:133
@ kCompleted
The task finished running.
Definition: dispatcher.h:139
Task * PopSingleTaskForThisWake()
Definition: dispatcher.h:123
void Post(Task &task)
RunTaskResult RunTask(Task &task)
Task * PopTaskToRun()
Definition: dispatcher.h:95
Definition: task.h:62
Definition: waker.h:160
Definition: intrusive_list.h:88
#define PW_GUARDED_BY(x)
Definition: lock_annotations.h:60
#define PW_NO_LOCK_SAFETY_ANALYSIS
Definition: lock_annotations.h:292
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:146
#define PW_LOCKS_EXCLUDED(...)
Definition: lock_annotations.h:176