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_allocator/internal/control_block.h"
17#include "pw_allocator/shared_ptr.h"
18#include "pw_assert/assert.h"
19#include "pw_async2/context.h"
20#include "pw_async2/internal/lock.h"
21#include "pw_async2/poll.h"
22#include "pw_containers/intrusive_forward_list.h"
23#include "pw_containers/intrusive_list.h"
24#include "pw_log/tokenized_args.h"
25#include "pw_sync/lock_annotations.h"
26
27namespace pw::async2 {
28
30
32#define PW_ASYNC_TASK_NAME(name) PW_LOG_TOKEN_EXPR("pw_async2", name)
33
34class Dispatcher;
35
38enum class RunTaskResult {
40 kActive,
41
44
47};
48
78class Task : public IntrusiveList<Task>::Item {
79 public:
88 explicit constexpr Task(log::Token name = kDefaultName) : name_(name) {}
89
90 Task(const Task&) = delete;
91 Task(Task&&) = delete;
92 Task& operator=(const Task&) = delete;
93 Task& operator=(Task&&) = delete;
94
104 virtual ~Task();
105
115 Poll<> Pend(Context& cx) { return DoPend(cx); }
116
125 bool IsRegistered() const;
126
141 void Deregister() PW_LOCKS_EXCLUDED(internal::lock());
142
147 void Join() PW_LOCKS_EXCLUDED(internal::lock());
148
149 private:
150 friend class Dispatcher;
151 friend class Waker;
152
153 static constexpr log::Token kDefaultName =
154 PW_LOG_TOKEN("pw_async2", "(anonymous)");
155
160 bool TryDeregister() PW_LOCKS_EXCLUDED(internal::lock());
161
179 virtual Poll<> DoPend(Context&) = 0;
180
181 // Sets this task to use the provided dispatcher.
182 void PostTo(Dispatcher& dispatcher)
183 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
184 PW_DASSERT(state_ == State::kUnposted);
185 PW_DASSERT(dispatcher_ == nullptr);
186 state_ = State::kWoken;
187 dispatcher_ = &dispatcher;
188 }
189
190 // Removes the task from the dispatcher. Returns the ControlBlock* if the
191 // dispatcher has a shared reference to this task.
192 allocator::internal::ControlBlock* Unpost()
193 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
194
195 // Unposts and releases the dispatcher's shared reference to the task, if any.
196 // Unconditionally releases the lock since it cannot be held while a task
197 // destructor is called.
198 void UnpostAndReleaseRef() PW_UNLOCK_FUNCTION(internal::lock());
199
200 // Unposts and releases the dispatcher's shared reference to the task, if any.
201 // If the dispatcher has a shared reference to the task, the lock is
202 // released to destroy the task, then reacquired. This should ONLY be called
203 // from the Dispatcher's destructor, since no tasks should be posted or run
204 // while the Dispatcher is being destroyed.
205 void UnpostAndReleaseRefFromDispatcherDestructor()
206 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
207
208 void MarkRunning() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
209 state_ = State::kRunning;
210 }
211
212 // Called by the dispatcher to run this task. The task has already been marked
213 // as running.
214 RunTaskResult RunInDispatcher() PW_LOCKS_EXCLUDED(internal::lock());
215
216 // Called by a waker to wake this task.
217 void Wake() PW_UNLOCK_FUNCTION(internal::lock());
218
219 // Unlinks all `Waker` objects associated with this `Task.`
220 void RemoveAllWakersLocked() PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
221
222 // Adds a `Waker` to the linked list of `Waker`s tracked by this `Task`.
223 void AddWakerLocked(Waker& waker)
224 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
225 wakers_.push_front(waker);
226 }
227
228 // Removes a `Waker` from the linked list of `Waker`s tracked by this `Task`.
229 //
230 // Precondition: the provided waker *must* be in the list of `Waker`s tracked
231 // by this `Task`.
232 void RemoveWakerLocked(Waker& waker)
233 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock()) {
234 wakers_.remove(waker);
235 }
236
237 Dispatcher& GetDispatcherWhileRunning() PW_NO_LOCK_SAFETY_ANALYSIS {
238 return *dispatcher_;
239 }
240
241 void ReleaseSharedRef(allocator::internal::ControlBlock* control_block)
242 PW_LOCKS_EXCLUDED(internal::lock()) {
243 // Create a SharedPtr to decrement the ref count and possibly delete this.
244 SharedPtr<Task> temp(this, control_block);
245 }
246
247 // Sets the control block for an allocated BEFORE the task is posted. Since
248 // the task hasn't been posted yet, it's not necessary to hold the lock.
249 void SetControlBlockBeforePosted(
250 allocator::internal::ControlBlock& control_block)
252 control_block_ = &control_block;
253 }
254
255 enum class State : unsigned char {
256 kUnposted,
257 kSleeping,
258 kRunning,
259 kDeregisteredButRunning,
260 kWokenWhileRunning,
261 kWoken,
262 };
263
264 // The current state of the task.
265 State state_ PW_GUARDED_BY(internal::lock()) = State::kUnposted;
266
267 // A pointer to the dispatcher this task is associated with.
268 //
269 // This will be non-null when `state_` is anything other than `kUnposted`.
270 //
271 // This value must be cleared by the dispatcher upon destruction in order to
272 // prevent null access.
273 Dispatcher* dispatcher_ PW_GUARDED_BY(internal::lock()) = nullptr;
274
275 // The memory block that contains this task, if it was dynamically allocated.
276 allocator::internal::ControlBlock* control_block_
277 PW_GUARDED_BY(internal::lock()) = nullptr;
278
279 // Linked list of `Waker` s that may awaken this `Task`.
280 IntrusiveForwardList<Waker> wakers_ PW_GUARDED_BY(internal::lock());
281
282 // Optional user-facing name for the task. If set, it will be included in
283 // debug logs.
284 log::Token name_;
285};
286
288
289} // namespace pw::async2
Definition: context.h:46
Definition: dispatcher.h:75
Definition: poll.h:138
Definition: task.h:78
virtual Poll DoPend(Context &)=0
Poll Pend(Context &cx)
Definition: task.h:115
bool IsRegistered() const
constexpr Task(log::Token name=kDefaultName)
Definition: task.h:88
Definition: waker.h:149
Definition: intrusive_list.h:88
RunTaskResult
Definition: task.h:38
@ kDeregistered
The task was removed from the dispatcher by another thread.
@ kCompleted
The task finished running.
@ kActive
The task is still posted to the dispatcher.
#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:296
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:147
#define PW_UNLOCK_FUNCTION(...)
Definition: lock_annotations.h:249
#define PW_LOCKS_EXCLUDED(...)
Definition: lock_annotations.h:178