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 {
27
29
47 public:
48 Dispatcher(Dispatcher&) = delete;
49 Dispatcher& operator=(Dispatcher&) = delete;
50
51 Dispatcher(Dispatcher&&) = delete;
52 Dispatcher& operator=(Dispatcher&&) = delete;
53
54 virtual ~Dispatcher() { Deregister(); }
55
65 void Post(Task& task) PW_LOCKS_EXCLUDED(internal::lock());
66
69 void LogRegisteredTasks() PW_LOCKS_EXCLUDED(internal::lock());
70
71 protected:
72 constexpr Dispatcher() = default;
73
82 bool PopAndRunAllReadyTasks() PW_LOCKS_EXCLUDED(internal::lock());
83
88 Task* PopTaskToRun() PW_LOCKS_EXCLUDED(internal::lock()) {
89 std::lock_guard lock(internal::lock());
90 return PopTaskToRunLocked();
91 }
92
105 Task* PopTaskToRun(bool& has_posted_tasks)
106 PW_LOCKS_EXCLUDED(internal::lock()) {
107 std::lock_guard lock(internal::lock());
108 Task* task = PopTaskToRunLocked();
109 has_posted_tasks = task != nullptr || !sleeping_.empty();
110 return task;
111 }
112
117 std::lock_guard lock(internal::lock());
118 SetWantsWake();
119 return PopTaskToRunLocked();
120 }
121
126 kActive = Task::kActive,
127
129 kDeregistered = Task::kDeregistered,
130
132 kCompleted = Task::kCompleted,
133 };
134
142 RunTaskResult RunTask(Task& task) PW_LOCKS_EXCLUDED(internal::lock());
143
144 private:
145 friend class Task;
146 friend class Waker;
147
148 // Allow DispatcherForTestFacade to wrap another dispatcher (call Do*).
149 template <typename>
150 friend class DispatcherForTestFacade;
151
166 virtual void DoWake() PW_LOCKS_EXCLUDED(internal::lock()) = 0;
167
168 void Wake() {
169 if (wants_wake_.exchange(false, std::memory_order_relaxed)) {
170 DoWake();
171 }
172 }
173
174 Task* PopTaskToRunLocked() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
175
176 // Removes references to this `Dispatcher` from all linked `Task`s and
177 // `Waker`s.
178 void Deregister() PW_LOCKS_EXCLUDED(internal::lock());
179
180 static void UnpostTaskList(IntrusiveList<Task>& list)
181 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
182
183 void RemoveWokenTaskLocked(Task& task)
184 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
185 woken_.remove(task);
186 }
187 void RemoveSleepingTaskLocked(Task& task)
188 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
189 sleeping_.remove(task);
190 }
191 void AddSleepingTaskLocked(Task& task)
192 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
193 sleeping_.push_front(task);
194 }
195
196 // For use by ``Waker``.
197 void WakeTask(Task& task) PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
198
199 void LogTaskWakers(const Task& task)
200 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
201
202 // Indicates that this Dispatcher should be woken when Wake() is called. This
203 // prevents unnecessary wakes when, for example, multiple wakers wake the same
204 // task or multiple tasks are posted before the dipsatcher runs.
205 //
206 // Must be called while the lock is held to prevent missed wakes.
207 void SetWantsWake() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
208 wants_wake_.store(true, std::memory_order_relaxed);
209 }
210
211 IntrusiveList<Task> woken_ PW_GUARDED_BY(internal::lock());
212 IntrusiveList<Task> sleeping_ PW_GUARDED_BY(internal::lock());
213
214 // Latches wake requests to avoid duplicate DoWake calls.
215 std::atomic<bool> wants_wake_ = false;
216};
217
219
220} // namespace pw::async2
Definition: dispatcher_for_test.h:36
Definition: dispatcher.h:46
Task * PopTaskToRun(bool &has_posted_tasks)
Definition: dispatcher.h:105
virtual void DoWake()=0
RunTaskResult
Definition: dispatcher.h:124
@ kDeregistered
The task was removed from the dispatcher by another thread.
Definition: dispatcher.h:129
@ kActive
The task is still posted to the dispatcher.
Definition: dispatcher.h:126
@ kCompleted
The task finished running.
Definition: dispatcher.h:132
Task * PopSingleTaskForThisWake()
Definition: dispatcher.h:116
void Post(Task &task)
RunTaskResult RunTask(Task &task)
Task * PopTaskToRun()
Definition: dispatcher.h:88
Definition: task.h:67
Definition: waker.h:158
Definition: intrusive_list.h:88
#define PW_GUARDED_BY(x)
Definition: lock_annotations.h:60
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:146
#define PW_LOCKS_EXCLUDED(...)
Definition: lock_annotations.h:176