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 {
26
28
30#define PW_ASYNC_TASK_NAME(name) PW_LOG_TOKEN_EXPR("pw_async2", name)
31
32class Dispatcher;
33
62class Task : public IntrusiveList<Task>::Item {
63 public:
72 explicit constexpr Task(log::Token name = kDefaultName) : name_(name) {}
73
74 Task(const Task&) = delete;
75 Task(Task&&) = delete;
76 Task& operator=(const Task&) = delete;
77 Task& operator=(Task&&) = delete;
78
88 virtual ~Task();
89
99 Poll<> Pend(Context& cx) { return DoPend(cx); }
100
109 bool IsRegistered() const;
110
125 void Deregister() PW_LOCKS_EXCLUDED(internal::lock());
126
131 void Join() PW_LOCKS_EXCLUDED(internal::lock());
132
133 private:
134 friend class Dispatcher;
135 friend class OwnedTask;
136 friend class Waker;
137
138 static constexpr log::Token kDefaultName =
139 PW_LOG_TOKEN("pw_async2", "(anonymous)");
140
141 struct OwnedTag {};
142
143 // Constructor for OwnedTask objects.
144 constexpr Task(log::Token name, OwnedTag)
145 : owned_by_dispatcher_(true), name_(name) {}
146
151 bool TryDeregister() PW_LOCKS_EXCLUDED(internal::lock());
152
170 virtual Poll<> DoPend(Context&) = 0;
171
172 // Sets this task to use the provided dispatcher.
173 void PostTo(Dispatcher& dispatcher)
174 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
175 PW_DASSERT(state_ == State::kUnposted);
176 PW_DASSERT(dispatcher_ == nullptr);
177 state_ = State::kWoken;
178 dispatcher_ = &dispatcher;
179 }
180
181 // Clears the task's dispatcher.
182 void Unpost() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
183 state_ = State::kUnposted;
184 dispatcher_ = nullptr;
185 RemoveAllWakersLocked();
186 }
187
188 void MarkRunning() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
189 state_ = State::kRunning;
190 }
191
192 // Result from `RunInDispatcher`. This is a superset of
193 // Dispatcher::RunTaskResult, which merges kCompletedNeedsDestroy into
194 // kCompleted.
195 enum RunResult {
196 // The task is still posted to the dispatcher.
197 kActive,
198
199 // The task was removed from the dispatcher by another thread.
200 kDeregistered,
201
202 // The task finished running.
203 kCompleted,
204
205 // The task finished running and must be deleted by the dispatcher.
206 kCompletedNeedsDestroy,
207 };
208
209 // Called by the dispatcher to run this task. The task has already been marked
210 // as running.
211 RunResult RunInDispatcher() PW_LOCKS_EXCLUDED(internal::lock());
212
213 // Called by the dispatcher to wake this task. Returns whether the task
214 // actually needed to be woken.
215 [[nodiscard]] bool Wake() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
216
217 // Unlinks all `Waker` objects associated with this `Task.`
218 void RemoveAllWakersLocked() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
219
220 // Adds a `Waker` to the linked list of `Waker` s tracked by this
221 // `Task`.
222 void AddWakerLocked(Waker&) PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
223
224 // Removes a `Waker` from the linked list of `Waker`s tracked by this `Task`.
225 //
226 // Precondition: the provided waker *must* be in the list of `Waker`s tracked
227 // by this `Task`.
228 void RemoveWakerLocked(Waker&) PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
229
230 Dispatcher& GetDispatcherWhileRunning() PW_NO_LOCK_SAFETY_ANALYSIS {
231 return *dispatcher_;
232 }
233
234 enum class State : unsigned char {
235 kUnposted,
236 kRunning,
237 kDeregisteredButRunning,
238 kWoken,
239 kSleeping,
240 };
241
242 // The current state of the task.
243 State state_ PW_GUARDED_BY(internal::lock()) = State::kUnposted;
244
245 bool owned_by_dispatcher_ PW_GUARDED_BY(internal::lock()) = false;
246
247 // A pointer to the dispatcher this task is associated with.
248 //
249 // This will be non-null when `state_` is anything other than `kUnposted`.
250 //
251 // This value must be cleared by the dispatcher upon destruction in order to
252 // prevent null access.
253 Dispatcher* dispatcher_ PW_GUARDED_BY(internal::lock()) = nullptr;
254
255 // Linked list of `Waker` s that may awaken this `Task`.
256 IntrusiveForwardList<Waker> wakers_ PW_GUARDED_BY(internal::lock());
257
258 // Optional user-facing name for the task. If set, it will be included in
259 // debug logs.
260 log::Token name_;
261};
262
264
265} // namespace pw::async2
Definition: context.h:54
Definition: dispatcher.h:53
Definition: owned_task.h:31
Definition: poll.h:60
Definition: task.h:62
virtual Poll DoPend(Context &)=0
Poll Pend(Context &cx)
Definition: task.h:99
bool IsRegistered() const
constexpr Task(log::Token name=kDefaultName)
Definition: task.h:72
Definition: waker.h:160
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