C/C++ API Reference
Loading...
Searching...
No Matches
waker.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/internal/config.h"
18#include "pw_async2/internal/lock.h"
19#include "pw_containers/intrusive_forward_list.h"
20#include "pw_log/tokenized_args.h"
21#include "pw_sync/lock_annotations.h"
22
23namespace pw::async2 {
24
25class Task;
26class Waker;
27
28namespace internal {
29
30template <typename Callable>
31[[nodiscard]] constexpr auto InvokeWithNodiscard(Callable&& callable) {
32 return callable();
33}
34
35[[nodiscard]] bool CloneWaker(Waker& waker_in,
36 Waker& waker_out,
37 log::Token wait_reason = log::kDefaultToken)
38 PW_LOCKS_EXCLUDED(internal::lock());
39
40} // namespace internal
41
43
58#define PW_ASYNC_STORE_WAKER(context, waker_or_queue_out, wait_reason_string) \
59 do { \
60 bool waker_or_queue_had_space = PW_ASYNC_TRY_STORE_WAKER( \
61 context, waker_or_queue_out, wait_reason_string); \
62 PW_ASSERT(waker_or_queue_had_space); \
63 } while (0)
64
79#define PW_ASYNC_TRY_STORE_WAKER( \
80 context, waker_or_queue_out, wait_reason_string) \
81 _PW_ASYNC_TRY_GET_WAKER(::pw::async2::internal::StoreWaker, \
82 context, \
83 waker_or_queue_out, \
84 wait_reason_string)
85
100#define PW_ASYNC_CLONE_WAKER(waker_in, waker_or_queue_out, wait_reason_string) \
101 do { \
102 bool waker_or_queue_had_space = PW_ASYNC_TRY_CLONE_WAKER( \
103 waker_in, waker_or_queue_out, wait_reason_string); \
104 PW_ASSERT(waker_or_queue_had_space); \
105 } while (0)
106
121#define PW_ASYNC_TRY_CLONE_WAKER( \
122 waker_in, waker_or_queue_out, wait_reason_string) \
123 _PW_ASYNC_TRY_GET_WAKER(::pw::async2::internal::CloneWaker, \
124 waker_in, \
125 waker_or_queue_out, \
126 wait_reason_string)
127
129
130// Base implementation of the TRY_{STORE,CLONE}_WAKER macros.
131#define _PW_ASYNC_TRY_GET_WAKER( \
132 func, source, waker_or_queue_out, wait_reason_string) \
133 ::pw::async2::internal::InvokeWithNodiscard( \
134 [&]() PW_NO_LOCK_SAFETY_ANALYSIS { \
135 [[maybe_unused]] constexpr const char* \
136 pw_async2_wait_reason_must_be_string = wait_reason_string; \
137 constexpr ::pw::log::Token pw_async2_wait_reason = \
138 PW_LOG_TOKEN("pw_async2", wait_reason_string); \
139 return func(source, waker_or_queue_out, pw_async2_wait_reason); \
140 })
141
143
158class Waker : public pw::IntrusiveForwardList<Waker>::Item {
159 friend class Task;
160 friend class Dispatcher;
161
162 public:
163 constexpr Waker() = default;
164 Waker(Waker&& other) noexcept PW_LOCKS_EXCLUDED(internal::lock());
165
169 Waker& operator=(Waker&& other) noexcept PW_LOCKS_EXCLUDED(internal::lock());
170
171 ~Waker() noexcept { RemoveFromTaskWakerList(); }
172
179 void Wake() PW_LOCKS_EXCLUDED(internal::lock());
180
189 [[nodiscard]] bool IsEmpty() const PW_LOCKS_EXCLUDED(internal::lock());
190
197 void Clear() PW_LOCKS_EXCLUDED(internal::lock()) {
198 RemoveFromTaskWakerList();
199 }
200
201 private:
202 friend bool internal::CloneWaker(Waker& waker_in,
203 Waker& waker_out,
204 log::Token wait_reason);
205
206 Waker(Task& task) PW_LOCKS_EXCLUDED(internal::lock()) : task_(&task) {
207 InsertIntoTaskWakerList();
208 }
209
218 void InternalCloneIntoLocked(Waker& waker_out, log::Token wait_reason) &
219 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
220
221 void InsertIntoTaskWakerList();
222 void InsertIntoTaskWakerListLocked()
223 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
224 void RemoveFromTaskWakerList();
225 void RemoveFromTaskWakerListLocked()
226 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::lock());
227
228 // The ``Task`` to poll when awoken.
229 Task* task_ PW_GUARDED_BY(internal::lock()) = nullptr;
230
231#if PW_ASYNC2_DEBUG_WAIT_REASON
232 log::Token wait_reason_ = log::kDefaultToken;
233#endif // PW_ASYNC2_DEBUG_WAIT_REASON
234};
235
237
238} // namespace pw::async2
Definition: intrusive_forward_list.h:99
Definition: dispatcher.h:46
Definition: task.h:67
Definition: waker.h:158
Waker & operator=(Waker &&other) noexcept
void Clear()
Definition: waker.h:197
bool IsEmpty() const
#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