Pigweed
C/C++ API Reference
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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/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
30class WakerQueueBase;
31
32template <typename Callable>
33[[nodiscard]] constexpr auto InvokeWithNodiscard(Callable&& callable) {
34 return callable();
35}
36
37[[nodiscard]] bool CloneWaker(Waker& waker_in,
38 Waker& waker_out,
39 log::Token wait_reason = log::kDefaultToken)
40 PW_LOCKS_EXCLUDED(impl::dispatcher_lock());
41
42} // namespace internal
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
128// Base implementation of the TRY_{STORE,CLONE}_WAKER macros.
129#define _PW_ASYNC_TRY_GET_WAKER( \
130 func, source, waker_or_queue_out, wait_reason_string) \
131 ::pw::async2::internal::InvokeWithNodiscard( \
132 [&]() PW_NO_LOCK_SAFETY_ANALYSIS { \
133 [[maybe_unused]] constexpr const char* \
134 pw_async2_wait_reason_must_be_string = wait_reason_string; \
135 constexpr ::pw::log::Token pw_async2_wait_reason = \
136 PW_LOG_TOKEN("pw_async2", wait_reason_string); \
137 return func(source, waker_or_queue_out, pw_async2_wait_reason); \
138 })
139
154class Waker : public pw::IntrusiveForwardList<Waker>::Item {
155 friend class Task;
156 friend class NativeDispatcherBase;
157 friend class internal::WakerQueueBase;
158
159 public:
160 constexpr Waker() = default;
161 Waker(Waker&& other) noexcept PW_LOCKS_EXCLUDED(impl::dispatcher_lock());
162
166 Waker& operator=(Waker&& other) noexcept
167 PW_LOCKS_EXCLUDED(impl::dispatcher_lock());
168
169 ~Waker() noexcept { RemoveFromTaskWakerList(); }
170
180 void Wake() && PW_LOCKS_EXCLUDED(impl::dispatcher_lock());
181
190 [[nodiscard]] bool IsEmpty() const PW_LOCKS_EXCLUDED(impl::dispatcher_lock());
191
198 void Clear() PW_LOCKS_EXCLUDED(impl::dispatcher_lock()) {
199 RemoveFromTaskWakerList();
200 }
201
202 private:
203 friend bool internal::CloneWaker(Waker& waker_in,
204 Waker& waker_out,
205 log::Token wait_reason);
206
207 Waker(Task& task) PW_LOCKS_EXCLUDED(impl::dispatcher_lock()) : task_(&task) {
208 InsertIntoTaskWakerList();
209 }
210
219 void InternalCloneIntoLocked(Waker& waker_out, log::Token wait_reason) &
220 PW_EXCLUSIVE_LOCKS_REQUIRED(impl::dispatcher_lock());
221
222 void InsertIntoTaskWakerList();
223 void InsertIntoTaskWakerListLocked()
224 PW_EXCLUSIVE_LOCKS_REQUIRED(impl::dispatcher_lock());
225 void RemoveFromTaskWakerList();
226 void RemoveFromTaskWakerListLocked()
227 PW_EXCLUSIVE_LOCKS_REQUIRED(impl::dispatcher_lock());
228
229 // The ``Task`` to poll when awoken.
230 Task* task_ PW_GUARDED_BY(impl::dispatcher_lock()) = nullptr;
231
232#if PW_ASYNC2_DEBUG_WAIT_REASON
233 log::Token wait_reason_ = log::kDefaultToken;
234#endif // PW_ASYNC2_DEBUG_WAIT_REASON
235};
236
237} // namespace pw::async2
Definition: intrusive_forward_list.h:86
Definition: dispatcher_base.h:47
Definition: task.h:61
Definition: waker.h:154
Waker & operator=(Waker &&other) noexcept
void Clear()
Definition: waker.h:198
bool IsEmpty() const
Definition: waker_queue.h:23