C/C++ API Reference
Loading...
Searching...
No Matches
task.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 "pw_assert/assert.h"
17#include "pw_async2/context.h"
18#include "pw_async2/internal/lock.h"
19#include "pw_async2/poll.h"
20#include "pw_containers/intrusive_forward_list.h"
21#include "pw_containers/intrusive_list.h"
22#include "pw_log/tokenized_args.h"
23#include "pw_sync/lock_annotations.h"
24
25namespace pw::async2 {
26namespace internal {
27
28class OwnedTask;
29
30} // namespace internal
31
33
35#define PW_ASYNC_TASK_NAME(name) PW_LOG_TOKEN_EXPR("pw_async2", name)
36
37class Dispatcher;
38
67class Task : public IntrusiveList<Task>::Item {
68 public:
77 explicit constexpr Task(log::Token name = kDefaultName) : name_(name) {}
78
79 Task(const Task&) = delete;
80 Task(Task&&) = delete;
81 Task& operator=(const Task&) = delete;
82 Task& operator=(Task&&) = delete;
83
93 virtual ~Task();
94
104 Poll<> Pend(Context& cx) { return DoPend(cx); }
105
114 bool IsRegistered() const;
115
130 void Deregister() PW_LOCKS_EXCLUDED(internal::lock());
131
136 void Join() PW_LOCKS_EXCLUDED(internal::lock());
137
138 private:
139 friend class Dispatcher;
140 friend internal::OwnedTask;
141 friend class Waker;
142
143 static constexpr log::Token kDefaultName =
144 PW_LOG_TOKEN("pw_async2", "(anonymous)");
145
146 struct OwnedTag {};
147
148 // Constructor for OwnedTask objects.
149 constexpr Task(log::Token name, OwnedTag)
150 : owned_by_dispatcher_(true), name_(name) {}
151
156 bool TryDeregister() PW_LOCKS_EXCLUDED(internal::lock());
157
175 virtual Poll<> DoPend(Context&) = 0;
176
177 // Sets this task to use the provided dispatcher.
178 void PostTo(Dispatcher& dispatcher)
179 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
180 PW_DASSERT(state_ == State::kUnposted);
181 PW_DASSERT(dispatcher_ == nullptr);
182 state_ = State::kWoken;
183 dispatcher_ = &dispatcher;
184 }
185
186 // Clears the task's dispatcher.
187 void Unpost() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
188 state_ = State::kUnposted;
189 dispatcher_ = nullptr;
190 RemoveAllWakersLocked();
191 }
192
193 void MarkRunning() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
194 state_ = State::kRunning;
195 }
196
197 // Result from `RunInDispatcher`. This is a superset of
198 // Dispatcher::RunTaskResult, which merges kCompletedNeedsDestroy into
199 // kCompleted.
200 enum RunResult {
201 // The task is still posted to the dispatcher.
202 kActive,
203
204 // The task was removed from the dispatcher by another thread.
205 kDeregistered,
206
207 // The task finished running.
208 kCompleted,
209
210 // The task finished running and must be deleted by the dispatcher.
211 kCompletedNeedsDestroy,
212 };
213
214 // Called by the dispatcher to run this task. The task has already been marked
215 // as running.
216 RunResult RunInDispatcher() PW_LOCKS_EXCLUDED(internal::lock());
217
218 // Called by the dispatcher to wake this task. Returns whether the task
219 // actually needed to be woken.
220 [[nodiscard]] bool Wake() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
221
222 // Unlinks all `Waker` objects associated with this `Task.`
223 void RemoveAllWakersLocked() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
224
225 // Adds a `Waker` to the linked list of `Waker` s tracked by this
226 // `Task`.
227 void AddWakerLocked(Waker&) PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
228
229 // Removes a `Waker` from the linked list of `Waker`s tracked by this `Task`.
230 //
231 // Precondition: the provided waker *must* be in the list of `Waker`s tracked
232 // by this `Task`.
233 void RemoveWakerLocked(Waker&) PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
234
235 Dispatcher& GetDispatcherWhileRunning() PW_NO_LOCK_SAFETY_ANALYSIS {
236 return *dispatcher_;
237 }
238
239 enum class State : unsigned char {
240 kUnposted,
241 kRunning,
242 kDeregisteredButRunning,
243 kWoken,
244 kSleeping,
245 };
246
247 // The current state of the task.
248 State state_ PW_GUARDED_BY(internal::lock()) = State::kUnposted;
249
250 bool owned_by_dispatcher_ PW_GUARDED_BY(internal::lock()) = false;
251
252 // A pointer to the dispatcher this task is associated with.
253 //
254 // This will be non-null when `state_` is anything other than `kUnposted`.
255 //
256 // This value must be cleared by the dispatcher upon destruction in order to
257 // prevent null access.
258 Dispatcher* dispatcher_ PW_GUARDED_BY(internal::lock()) = nullptr;
259
260 // Linked list of `Waker` s that may awaken this `Task`.
261 IntrusiveForwardList<Waker> wakers_ PW_GUARDED_BY(internal::lock());
262
263 // Optional user-facing name for the task. If set, it will be included in
264 // debug logs.
265 log::Token name_;
266};
267
269
270} // namespace pw::async2
Definition: context.h:46
Definition: dispatcher.h:46
Definition: poll.h:138
Definition: task.h:67
virtual Poll DoPend(Context &)=0
Poll Pend(Context &cx)
Definition: task.h:104
bool IsRegistered() const
constexpr Task(log::Token name=kDefaultName)
Definition: task.h:77
Definition: waker.h:158
Definition: intrusive_list.h:88
#define PW_LOG_TOKEN(...)
Definition: tokenized_args.h:63
#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