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