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/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)
41
42} // namespace internal
43
45
60#define PW_ASYNC_STORE_WAKER(context, waker_or_queue_out, wait_reason_string) \
61 do { \
62 bool waker_or_queue_had_space = PW_ASYNC_TRY_STORE_WAKER( \
63 context, waker_or_queue_out, wait_reason_string); \
64 PW_ASSERT(waker_or_queue_had_space); \
65 } while (0)
66
81#define PW_ASYNC_TRY_STORE_WAKER( \
82 context, waker_or_queue_out, wait_reason_string) \
83 _PW_ASYNC_TRY_GET_WAKER(::pw::async2::internal::StoreWaker, \
84 context, \
85 waker_or_queue_out, \
86 wait_reason_string)
87
102#define PW_ASYNC_CLONE_WAKER(waker_in, waker_or_queue_out, wait_reason_string) \
103 do { \
104 bool waker_or_queue_had_space = PW_ASYNC_TRY_CLONE_WAKER( \
105 waker_in, waker_or_queue_out, wait_reason_string); \
106 PW_ASSERT(waker_or_queue_had_space); \
107 } while (0)
108
123#define PW_ASYNC_TRY_CLONE_WAKER( \
124 waker_in, waker_or_queue_out, wait_reason_string) \
125 _PW_ASYNC_TRY_GET_WAKER(::pw::async2::internal::CloneWaker, \
126 waker_in, \
127 waker_or_queue_out, \
128 wait_reason_string)
129
131
132// Base implementation of the TRY_{STORE,CLONE}_WAKER macros.
133#define _PW_ASYNC_TRY_GET_WAKER( \
134 func, source, waker_or_queue_out, wait_reason_string) \
135 ::pw::async2::internal::InvokeWithNodiscard( \
136 [&]() PW_NO_LOCK_SAFETY_ANALYSIS { \
137 [[maybe_unused]] constexpr const char* \
138 pw_async2_wait_reason_must_be_string = wait_reason_string; \
139 constexpr ::pw::log::Token pw_async2_wait_reason = \
140 PW_LOG_TOKEN("pw_async2", wait_reason_string); \
141 return func(source, waker_or_queue_out, pw_async2_wait_reason); \
142 })
143
145
160class Waker : public pw::IntrusiveForwardList<Waker>::Item {
161 friend class Task;
162 friend class NativeDispatcherBase;
163 friend class internal::WakerQueueBase;
164
165 public:
166 constexpr Waker() = default;
168
172 Waker& operator=(Waker&& other) noexcept
174
175 ~Waker() noexcept { RemoveFromTaskWakerList(); }
176
187
196 [[nodiscard]] bool IsEmpty() const PW_LOCKS_EXCLUDED(impl::dispatcher_lock());
197
204 void Clear() PW_LOCKS_EXCLUDED(impl::dispatcher_lock()) {
205 RemoveFromTaskWakerList();
206 }
207
208 private:
209 friend bool internal::CloneWaker(Waker& waker_in,
210 Waker& waker_out,
211 log::Token wait_reason);
212
213 Waker(Task& task) PW_LOCKS_EXCLUDED(impl::dispatcher_lock()) : task_(&task) {
214 InsertIntoTaskWakerList();
215 }
216
225 void InternalCloneIntoLocked(Waker& waker_out, log::Token wait_reason) &
227
228 void InsertIntoTaskWakerList();
229 void InsertIntoTaskWakerListLocked()
230 PW_EXCLUSIVE_LOCKS_REQUIRED(impl::dispatcher_lock());
231 void RemoveFromTaskWakerList();
232 void RemoveFromTaskWakerListLocked()
233 PW_EXCLUSIVE_LOCKS_REQUIRED(impl::dispatcher_lock());
234
235 // The ``Task`` to poll when awoken.
236 Task* task_ PW_GUARDED_BY(impl::dispatcher_lock()) = nullptr;
237
238#if PW_ASYNC2_DEBUG_WAIT_REASON
239 log::Token wait_reason_ = log::kDefaultToken;
240#endif // PW_ASYNC2_DEBUG_WAIT_REASON
241};
242
244
245} // namespace pw::async2
Definition: intrusive_forward_list.h:91
Definition: dispatcher_base.h:49
Definition: task.h:63
Definition: waker.h:160
Waker & operator=(Waker &&other) noexcept
void Clear()
Definition: waker.h:204
bool IsEmpty() const
Definition: waker_queue.h:23
pw::sync::InterruptSpinLock & dispatcher_lock()
Definition: lock.h:33
#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