C/C++ API Reference
Loading...
Searching...
No Matches
channel.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 <mutex>
17#include <optional>
18
19#include "pw_allocator/allocator.h"
20#include "pw_async2/callback_task.h"
21#include "pw_async2/dispatcher.h"
22#include "pw_async2/future.h"
23#include "pw_containers/deque.h"
24#include "pw_numeric/checked_arithmetic.h"
25#include "pw_result/result.h"
26#include "pw_sync/interrupt_spin_lock.h"
27#include "pw_sync/lock_annotations.h"
28#include "pw_sync/timed_thread_notification.h"
29
30namespace pw::async2 {
31
32template <typename T>
33class Receiver;
34
35template <typename T>
36class ReceiveFuture;
37
38template <typename T>
39class Sender;
40
41template <typename T>
42class SendFuture;
43
44template <typename T>
45class ReserveSendFuture;
46
47template <typename T>
48class SendReservation;
49
50template <typename T, uint16_t kCapacity>
51class ChannelStorage;
52
53namespace internal {
54
55template <typename T>
56class Channel;
57
58class BaseChannel;
59
61 public:
62 constexpr BaseChannelFuture() : channel_(nullptr) {}
63
64 BaseChannelFuture(const BaseChannelFuture&) = delete;
65 BaseChannelFuture& operator=(const BaseChannelFuture&) = delete;
66
67 // Derived classes call MoveAssignFrom to move rather than use the operator.
68 BaseChannelFuture& operator=(BaseChannelFuture&&) = delete;
69
71 [[nodiscard]] bool is_pendable() const { return core_.is_pendable(); }
72
74 [[nodiscard]] bool is_complete() const { return core_.is_complete(); }
75
76 protected:
77 // Creates a new future, storing nullptr if `channel` is nullptr or if the
78 // channel is closed.
79 explicit BaseChannelFuture(BaseChannel* channel) PW_LOCKS_EXCLUDED(*channel);
80
81 enum AllowClosed { kAllowClosed };
82
83 // Creates a new future. Always increases the ref count, even if the channel
84 // is closed. This allows ReceiveFutures to read values from closed channels.
85 BaseChannelFuture(BaseChannel* channel, AllowClosed)
86 PW_LOCKS_EXCLUDED(*channel)
87 : core_(FutureState::kPending) {
88 StoreAndAddRefIfNonnull(channel);
89 }
90
91 BaseChannelFuture(BaseChannelFuture&& other)
92 PW_LOCKS_EXCLUDED(*channel_, *other.channel_)
93 : channel_(other.channel_) {
94 MoveFrom(other);
95 }
96
97 BaseChannelFuture& MoveAssignFrom(BaseChannelFuture& other)
98 PW_LOCKS_EXCLUDED(*channel_, *other.channel_);
99
100 // Unlists this future and removes a reference from the channel.
101 void RemoveFromChannel() PW_LOCKS_EXCLUDED(*channel_);
102
103 bool StoreWakerForReceiveIfOpen(Context& cx) PW_UNLOCK_FUNCTION(*channel_);
104
105 void StoreWakerForSend(Context& cx) PW_UNLOCK_FUNCTION(*channel_);
106
107 void StoreWakerForReserveSend(Context& cx) PW_UNLOCK_FUNCTION(*channel_);
108
109 void MarkCompleted() { core_.MarkComplete(); }
110
111 void Complete() PW_UNLOCK_FUNCTION(*channel_);
112
113 BaseChannel* base_channel() PW_LOCK_RETURNED(channel_) { return channel_; }
114
115 private:
116 void StoreAndAddRefIfNonnull(BaseChannel* channel)
117 PW_LOCKS_EXCLUDED(*channel);
118
119 void MoveFrom(BaseChannelFuture& other) PW_LOCKS_EXCLUDED(*other.channel_);
120
121 BaseChannel* channel_;
122 FutureCore core_;
123
124 public:
125 using List = FutureList<&BaseChannelFuture::core_>;
126};
127
128// Adds a Pend function to BaseChannelFuture.
129template <typename Derived, typename T, typename FutureValue>
131 public:
132 using value_type = FutureValue;
133
134 Poll<value_type> Pend(Context& cx) PW_LOCKS_EXCLUDED(*this->channel()) {
135 Poll<value_type> result = static_cast<Derived&>(*this).DoPend(cx);
136 if (result.IsReady()) {
137 // If Ready(), the future is no longer associated with the channel, so it
138 // can be marked complete without the lock held.
139 MarkCompleted();
140 }
141 return result;
142 }
143
144 protected:
145 constexpr ChannelFuture() = default;
146
147 explicit ChannelFuture(Channel<T>* channel) : BaseChannelFuture(channel) {}
148
149 ChannelFuture(Channel<T>* channel, AllowClosed)
150 : BaseChannelFuture(channel, kAllowClosed) {}
151
152 ChannelFuture(ChannelFuture&& other) : BaseChannelFuture(std::move(other)) {}
153
154 Channel<T>* channel() PW_LOCK_RETURNED(this->base_channel()) {
155 return static_cast<Channel<T>*>(base_channel());
156 }
157
158 private:
159 using BaseChannelFuture::base_channel;
160 using BaseChannelFuture::MarkCompleted;
161};
162
163// Internal generic channel type. BaseChannel is not exposed to users. Its
164// public interface is for internal consumption.
165class PW_LOCKABLE("pw::async2::internal::BaseChannel") BaseChannel {
166 public:
167 static constexpr chrono::SystemClock::duration kWaitForever =
168 chrono::SystemClock::duration::max();
169
170 // Acquires the channel's lock.
171 void lock() PW_EXCLUSIVE_LOCK_FUNCTION() { lock_.lock(); }
172
173 // Releases the channel's lock.
174 void unlock() PW_UNLOCK_FUNCTION() { lock_.unlock(); }
175
176 [[nodiscard]] bool is_open() PW_LOCKS_EXCLUDED(*this) {
177 std::lock_guard lock(*this);
178 return is_open_locked();
179 }
180
181 bool is_open_locked() const PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
182 return !closed_;
183 }
184
185 [[nodiscard]] bool active_locked() const PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
186 return ref_count_ != 0;
187 }
188
189 // Removes a reference to this channel and destroys the channel if needed.
190 void RemoveRefAndDestroyIfUnreferenced() PW_UNLOCK_FUNCTION();
191
192 void Close() PW_LOCKS_EXCLUDED(*this) {
193 std::lock_guard lock(*this);
194 CloseLocked();
195 }
196
197 // Adds a SendFuture or ReserveSendFuture to the list of pending futures.
198 void add_send_future(BaseChannelFuture& future)
200 send_futures_.Push(future);
201 }
202
203 // Adds a ReceiveFuture to the list of pending futures.
204 void add_receive_future(BaseChannelFuture& future)
206 receive_futures_.Push(future);
207 }
208
209 void DropReservationAndRemoveRef() PW_LOCKS_EXCLUDED(*this);
210
211 void add_receiver() PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
212 add_object(receiver_count_);
213 }
214
215 void add_sender() PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
216 add_object(sender_count_);
217 }
218
219 void add_handle() PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
220 add_object(handle_count_);
221 }
222
223 void add_reservation() PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
224 reservations_ += 1;
225 }
226
227 void remove_reservation() PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
228 PW_DASSERT(reservations_ > 0);
229 reservations_ -= 1;
230 }
231
232 void remove_sender() PW_LOCKS_EXCLUDED(*this) {
233 remove_object(&sender_count_);
234 }
235
236 void remove_receiver() PW_LOCKS_EXCLUDED(*this) {
237 remove_object(&receiver_count_);
238 }
239
240 void remove_handle() PW_LOCKS_EXCLUDED(*this) {
241 remove_object(&handle_count_);
242 }
243
244 void add_ref() PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
245 PW_ASSERT(CheckedIncrement(ref_count_, 1));
246 }
247
248 protected:
249 constexpr BaseChannel() = default;
250
251 ~BaseChannel();
252
253 void WakeOneReceiver() PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
254 receive_futures_.ResolveOneIfAvailable();
255 }
256
257 void WakeOneSender() PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
258 send_futures_.ResolveOneIfAvailable();
259 }
260
261 uint16_t reservations() const PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
262 return reservations_;
263 }
264
265 private:
266 void add_object(uint8_t& counter) PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
267 if (is_open_locked()) {
268 PW_ASSERT(CheckedIncrement(counter, 1));
269 }
270 add_ref();
271 }
272
273 // Takes a pointer since otherwise Clang's thread safety analysis complains
274 // about taking a reference without the lock held.
275 void remove_object(uint8_t* counter) PW_LOCKS_EXCLUDED(*this);
276
277 // Returns true if the channel should be closed following a reference
278 // decrement.
279 //
280 // Handles can create new senders and receivers, so as long as one exists, the
281 // channel should remain open. Without active handles, the channel closes when
282 // either end fully hangs up.
283 bool should_close() const PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
284 return handle_count_ == 0 && (sender_count_ == 0 || receiver_count_ == 0);
285 }
286
287 void CloseLocked() PW_EXCLUSIVE_LOCKS_REQUIRED(*this);
288
289 // Destroys the channel if it is dynamically allocated.
290 virtual void Destroy() {}
291
292 BaseChannelFuture::List send_futures_ PW_GUARDED_BY(*this);
293 BaseChannelFuture::List receive_futures_ PW_GUARDED_BY(*this);
294
295 uint16_t reservations_ PW_GUARDED_BY(*this) = 0;
296 bool closed_ PW_GUARDED_BY(*this) = false;
297 mutable sync::InterruptSpinLock lock_;
298
299 // Channels are reference counted in two ways:
300 //
301 // - Senders and receivers are tracked independently. Once either reaches
302 // zero, the channel is closed, but not destroyed. No new values can be
303 // sent, but any buffered values can still be read.
304 //
305 // - Overall object reference count, including senders, receivers, futures,
306 // and channel handles. Once this reaches zero, the channel is destroyed.
307 //
308 uint8_t sender_count_ PW_GUARDED_BY(*this) = 0;
309 uint8_t receiver_count_ PW_GUARDED_BY(*this) = 0;
310 uint8_t handle_count_ PW_GUARDED_BY(*this) = 0;
311 uint16_t ref_count_ PW_GUARDED_BY(*this) = 0;
312};
313
314// Like BaseChannel, Channel is an internal class that is not exposed to users.
315// Its public interface is for internal consumption.
316template <typename T>
317class Channel : public BaseChannel {
318 public:
319 Sender<T> CreateSender() PW_LOCKS_EXCLUDED(*this) {
320 {
321 std::lock_guard guard(*this);
322 if (is_open_locked()) {
323 return Sender<T>(*this);
324 }
325 }
326 return Sender<T>();
327 }
328
329 Receiver<T> CreateReceiver() PW_LOCKS_EXCLUDED(*this) {
330 {
331 std::lock_guard guard(*this);
332 if (is_open_locked()) {
333 return Receiver<T>(*this);
334 }
335 }
336 return Receiver<T>();
337 }
338
339 void PushAndWake(T&& value) PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
340 deque_.push_back(std::move(value));
341 WakeOneReceiver();
342 }
343
344 void PushAndWake(const T& value) PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
345 deque_.push_back(value);
346 WakeOneReceiver();
347 }
348
349 template <typename... Args>
350 void EmplaceAndWake(Args&&... args) PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
351 deque_.emplace_back(std::forward<Args>(args)...);
352 WakeOneReceiver();
353 }
354
355 T PopAndWake() PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
356 T value = std::move(deque_.front());
357 deque_.pop_front();
358
359 WakeOneSender();
360 return value;
361 }
362
363 bool full() const PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
364 return remaining_capacity_locked() == 0;
365 }
366
367 uint16_t remaining_capacity() PW_LOCKS_EXCLUDED(*this) {
368 std::lock_guard guard(*this);
369 return remaining_capacity_locked();
370 }
371
372 uint16_t remaining_capacity_locked() const
374 return deque_.capacity() - deque_.size() - reservations();
375 }
376
377 uint16_t capacity() const PW_NO_LOCK_SAFETY_ANALYSIS {
378 // SAFETY: The capacity of `deque_` cannot change.
379 return deque_.capacity();
380 }
381
382 [[nodiscard]] bool empty() PW_EXCLUSIVE_LOCKS_REQUIRED(*this) {
383 return deque_.empty();
384 }
385
386 template <typename U>
387 Status TrySend(U&& value) PW_LOCKS_EXCLUDED(*this) {
388 std::lock_guard guard(*this);
389 if (!is_open_locked()) {
391 }
392 if (full()) {
393 return Status::Unavailable();
394 }
395 PushAndWake(std::forward<U>(value));
396 return OkStatus();
397 }
398
399 Result<T> TryReceive() PW_LOCKS_EXCLUDED(*this) {
400 std::lock_guard guard(*this);
401 if (deque_.empty()) {
402 return is_open_locked() ? Status::Unavailable()
404 }
405 return Result(PopAndWake());
406 }
407
408 Result<SendReservation<T>> TryReserveSend() PW_LOCKS_EXCLUDED(*this) {
409 std::lock_guard guard(*this);
410 if (!is_open_locked()) {
412 }
413 if (full()) {
414 return Status::Unavailable();
415 }
416 add_reservation();
417 return SendReservation<T>(*this);
418 }
419
420 template <typename... Args>
421 void CommitReservationAndRemoveRef(Args&&... args) PW_LOCKS_EXCLUDED(*this) {
422 lock();
423 remove_reservation();
424 if (is_open_locked()) {
425 EmplaceAndWake(std::forward<Args>(args)...);
426 }
427 RemoveRefAndDestroyIfUnreferenced();
428 }
429
430 protected:
431 constexpr explicit Channel(FixedDeque<T>&& deque)
432 : deque_(std::move(deque)) {}
433
434 template <size_t kAlignment, size_t kCapacity>
436 : deque_(storage) {}
437
438 ~Channel() = default;
439
440 Deallocator* deallocator() const PW_NO_LOCK_SAFETY_ANALYSIS {
441 // SAFETY: deque_.deallocator() cannot change.
442 return deque_.deallocator();
443 }
444
445 private:
446 FixedDeque<T> deque_ PW_GUARDED_BY(*this);
447};
448
449template <typename T>
450class DynamicChannel final : public Channel<T> {
451 public:
452 static Channel<T>* Allocate(Allocator& alloc, uint16_t capacity) {
453 FixedDeque<T> deque = FixedDeque<T>::TryAllocate(alloc, capacity);
454 if (deque.capacity() == 0) {
455 return nullptr;
456 }
457 return alloc.New<DynamicChannel<T>>(std::move(deque));
458 }
459
460 explicit DynamicChannel(FixedDeque<T>&& deque)
461 : Channel<T>(std::move(deque)) {}
462
463 private:
464 ~DynamicChannel() = default;
465
466 void Destroy() final PW_LOCKS_EXCLUDED(*this) {
467 Deallocator* const deallocator = this->deallocator();
468 this->~DynamicChannel();
469 deallocator->Deallocate(this);
470 }
471};
472
479 public:
480 constexpr BaseChannelHandle() : channel_(nullptr) {}
481
483
485
486 [[nodiscard]] bool is_open() const PW_LOCKS_EXCLUDED(channel_) {
487 return channel_ != nullptr && channel_->is_open();
488 }
489
492 void Close() PW_LOCKS_EXCLUDED(channel_);
493
500 void Release() PW_LOCKS_EXCLUDED(channel_);
501
502 protected:
503 explicit BaseChannelHandle(BaseChannel& channel)
505 : channel_(&channel) {
506 channel_->add_handle();
507 }
508
509 BaseChannelHandle& operator=(const BaseChannelHandle& other)
510 PW_LOCKS_EXCLUDED(channel_);
511
512 BaseChannelHandle(BaseChannelHandle&& other) noexcept
513 : channel_(std::exchange(other.channel_, nullptr)) {}
514
515 BaseChannelHandle& operator=(BaseChannelHandle&& other) noexcept
516 PW_LOCKS_EXCLUDED(channel_);
517
518 constexpr BaseChannel* channel() const PW_LOCK_RETURNED(channel_) {
519 return channel_;
520 }
521
522 private:
523 BaseChannel* channel_;
524};
525
526} // namespace internal
527
529
531template <typename T>
533 public:
534 constexpr ChannelHandle() = default;
535
536 ChannelHandle(const ChannelHandle&) = default;
537 ChannelHandle& operator=(const ChannelHandle&) = default;
538
539 ChannelHandle(ChannelHandle&&) = default;
540 ChannelHandle& operator=(ChannelHandle&&) = default;
541
542 protected:
543 explicit ChannelHandle(internal::Channel<T>& channel)
545 : internal::BaseChannelHandle(channel) {}
546
550 PW_ASSERT(channel() != nullptr);
551 return static_cast<internal::Channel<T>&>(*channel()).CreateSender();
552 }
553
557 PW_ASSERT(channel() != nullptr);
558 return static_cast<internal::Channel<T>&>(*channel()).CreateReceiver();
559 }
560};
561
563template <typename T>
564class MpmcChannelHandle final : public ChannelHandle<T> {
565 public:
566 constexpr MpmcChannelHandle() = default;
567
570
571 private:
572 explicit MpmcChannelHandle(internal::Channel<T>& channel)
573 : ChannelHandle<T>(channel) {}
574
575 template <typename U>
576 friend std::optional<MpmcChannelHandle<U>> CreateMpmcChannel(Allocator&,
577 uint16_t);
578
579 template <typename U, uint16_t kCapacity>
582};
583
585template <typename T>
586class MpscChannelHandle final : public ChannelHandle<T> {
587 public:
588 constexpr MpscChannelHandle() = default;
589
591
592 private:
593 explicit MpscChannelHandle(internal::Channel<T>& channel)
594 : ChannelHandle<T>(channel) {}
595
596 template <typename U>
597 friend std::optional<std::tuple<MpscChannelHandle<U>, Receiver<U>>>
598 CreateMpscChannel(Allocator&, uint16_t);
599
600 template <typename U, uint16_t kCapacity>
601 friend std::tuple<MpscChannelHandle<U>, Receiver<U>> CreateMpscChannel(
603};
604
606template <typename T>
607class SpmcChannelHandle final : public ChannelHandle<T> {
608 public:
609 constexpr SpmcChannelHandle() = default;
610
612
613 private:
614 explicit SpmcChannelHandle(internal::Channel<T>& channel)
615 : ChannelHandle<T>(channel) {}
616
617 template <typename U>
618 friend std::optional<std::tuple<SpmcChannelHandle<U>, Sender<U>>>
619 CreateSpmcChannel(Allocator&, uint16_t);
620
621 template <typename U, uint16_t kCapacity>
622 friend std::tuple<SpmcChannelHandle<U>, Sender<U>> CreateSpmcChannel(
624};
625
627template <typename T>
628class SpscChannelHandle final : public ChannelHandle<T> {
629 public:
630 constexpr SpscChannelHandle() = default;
631
632 private:
633 explicit SpscChannelHandle(internal::Channel<T>& channel)
634 : ChannelHandle<T>(channel) {}
635
636 template <typename U>
637 friend std::optional<std::tuple<SpscChannelHandle<U>, Sender<U>, Receiver<U>>>
638 CreateSpscChannel(Allocator&, uint16_t);
639
640 template <typename U, uint16_t kCapacity>
641 friend std::tuple<SpscChannelHandle<U>, Sender<U>, Receiver<U>>
643};
644
648template <typename T>
649class MpChannelHandle final : public ChannelHandle<T> {
650 public:
651 constexpr MpChannelHandle() = default;
652
654 : ChannelHandle<T>(other) {}
655
656 MpChannelHandle& operator=(const MpmcChannelHandle<T>& other) {
658 return *this;
659 }
660
662 : ChannelHandle<T>(std::move(other)) {}
663
664 MpChannelHandle& operator=(MpmcChannelHandle<T>&& other) {
665 ChannelHandle<T>::operator=(std::move(other));
666 return *this;
667 }
668
670 : ChannelHandle<T>(other) {}
671
672 MpChannelHandle& operator=(const MpscChannelHandle<T>& other) {
674 return *this;
675 }
676
678 : ChannelHandle<T>(std::move(other)) {}
679
680 MpChannelHandle& operator=(MpscChannelHandle<T>&& other) {
681 ChannelHandle<T>::operator=(std::move(other));
682 return *this;
683 }
684
686};
687
691template <typename T>
692class McChannelHandle final : public ChannelHandle<T> {
693 public:
694 constexpr McChannelHandle() = default;
695
697 : ChannelHandle<T>(other) {}
698
699 McChannelHandle& operator=(const MpmcChannelHandle<T>& other) {
701 return *this;
702 }
703
705 : ChannelHandle<T>(std::move(other)) {}
706
707 McChannelHandle& operator=(MpmcChannelHandle<T>&& other) {
708 ChannelHandle<T>::operator=(std::move(other));
709 return *this;
710 }
711
713 : ChannelHandle<T>(other) {}
714
715 McChannelHandle& operator=(const SpmcChannelHandle<T>& other) {
717 return *this;
718 }
719
721 : ChannelHandle<T>(std::move(other)) {}
722
723 McChannelHandle& operator=(SpmcChannelHandle<T>&& other) {
724 ChannelHandle<T>::operator=(std::move(other));
725 return *this;
726 }
727
729};
730
735template <typename T, uint16_t kCapacity>
736class ChannelStorage final : private containers::StorageBaseFor<T, kCapacity>,
737 private internal::Channel<T> {
738 public:
739 template <typename U, uint16_t kCap>
740 friend std::tuple<SpscChannelHandle<U>, Sender<U>, Receiver<U>>
741 CreateSpscChannel(ChannelStorage<U, kCap>& storage);
742
743 template <typename U, uint16_t kCap>
744 friend std::tuple<MpscChannelHandle<U>, Receiver<U>> CreateMpscChannel(
745 ChannelStorage<U, kCap>& storage);
746
747 template <typename U, uint16_t kCap>
748 friend std::tuple<SpmcChannelHandle<U>, Sender<U>> CreateSpmcChannel(
749 ChannelStorage<U, kCap>& storage);
750
751 template <typename U, uint16_t kCap>
752 friend MpmcChannelHandle<U> CreateMpmcChannel(
753 ChannelStorage<U, kCap>& storage);
754
755 ChannelStorage() : internal::Channel<T>(this->storage()) {}
756
757 ~ChannelStorage() = default;
758
761 [[nodiscard]] bool active() const PW_LOCKS_EXCLUDED(*this) {
762 std::lock_guard lock(*this);
763 return this->active_locked();
764 }
765
766 constexpr uint16_t capacity() const { return kCapacity; }
767};
768
769template <typename T>
770class [[nodiscard]] ReceiveFuture final
771 : public internal::ChannelFuture<ReceiveFuture<T>, T, std::optional<T>> {
772 private:
774
775 public:
776 constexpr ReceiveFuture() = default;
777
779 PW_LOCKS_EXCLUDED(*this->channel(), *other.channel())
780 : Base(std::move(other)) {}
781
782 ReceiveFuture& operator=(ReceiveFuture&& other)
783 PW_LOCKS_EXCLUDED(*this->channel(), *other.channel()) {
784 // NOLINTNEXTLINE(misc-unconventional-assign-operator)
785 return static_cast<ReceiveFuture&>(this->MoveAssignFrom(other));
786 }
787
788 ~ReceiveFuture() PW_LOCKS_EXCLUDED(*this->channel()) {
789 this->RemoveFromChannel();
790 }
791
792 private:
793 friend Base;
795 friend Receiver<T>;
796 template <typename, typename>
797 friend class CallbackTask;
798
799 explicit ReceiveFuture(internal::Channel<T>* channel)
800 PW_LOCKS_EXCLUDED(*channel)
801 : Base(channel, this->kAllowClosed) {}
802
803 PollOptional<T> DoPend(Context& cx) PW_LOCKS_EXCLUDED(*this->channel()) {
804 if (this->channel() == nullptr) {
805 PW_DASSERT(this->is_pendable());
806 return Ready<std::optional<T>>(std::nullopt);
807 }
808
809 this->channel()->lock();
810 PW_DASSERT(this->is_pendable());
811 if (this->channel()->empty()) {
812 return this->StoreWakerForReceiveIfOpen(cx)
813 ? Pending()
814 : Ready<std::optional<T>>(std::nullopt);
815 }
816
817 auto result = Ready(this->channel()->PopAndWake());
818 this->Complete();
819 return result;
820 }
821};
822
824template <typename T>
825class Receiver {
826 public:
827 constexpr Receiver() : channel_(nullptr) {}
828
829 Receiver(const Receiver& other) = delete;
830 Receiver& operator=(const Receiver& other) = delete;
831
832 Receiver(Receiver&& other) noexcept
833 : channel_(std::exchange(other.channel_, nullptr)) {}
834
835 Receiver& operator=(Receiver&& other) noexcept {
836 if (this == &other) {
837 return *this;
838 }
839 if (channel_ != nullptr) {
840 channel_->remove_receiver();
841 }
842 channel_ = std::exchange(other.channel_, nullptr);
843 return *this;
844 }
845
846 ~Receiver() {
847 if (channel_ != nullptr) {
848 channel_->remove_receiver();
849 }
850 }
851
864 PW_LOCKS_EXCLUDED(*channel_) {
865 if (channel_ == nullptr) {
867 }
868
869 // Return immediately if a value is available or the channel is closed.
870 if (Result<T> result = channel_->TryReceive();
871 result.ok() || result.status().IsFailedPrecondition()) {
872 return result;
873 }
874
875 std::optional<T> result;
877
879 [&result, &notification](std::optional<T>&& val) {
880 result = std::move(val);
881 notification.release();
882 },
883 channel_);
884 dispatcher.Post(task);
885
886 if (timeout == internal::Channel<T>::kWaitForever) {
887 notification.acquire();
888 if (!result.has_value()) {
890 }
891 return Result<T>(std::move(*result));
892 }
893
894 if (!notification.try_acquire_for(timeout)) {
896 }
897
898 if (!result.has_value()) {
900 }
901 return Result<T>(std::move(*result));
902 }
903
912 return ReceiveFuture<T>(channel_);
913 }
914
922 if (channel_ == nullptr) {
924 }
925 return channel_->TryReceive();
926 }
927
932 void Disconnect() {
933 if (channel_ != nullptr) {
934 channel_->remove_receiver();
935 channel_ = nullptr;
936 }
937 }
938
940 [[nodiscard]] bool is_open() const {
941 return channel_ != nullptr && channel_->is_open();
942 }
943
944 private:
945 template <typename U>
946 friend class internal::Channel;
947
948 template <typename U>
949 friend std::optional<std::tuple<MpscChannelHandle<U>, Receiver<U>>>
950 CreateMpscChannel(Allocator&, uint16_t);
951
952 template <typename U, uint16_t kCapacity>
953 friend std::tuple<MpscChannelHandle<U>, Receiver<U>> CreateMpscChannel(
955
956 template <typename U>
957 friend std::optional<std::tuple<SpscChannelHandle<U>, Sender<U>, Receiver<U>>>
958 CreateSpscChannel(Allocator&, uint16_t);
959
960 template <typename U, uint16_t kCapacity>
961 friend std::tuple<SpscChannelHandle<U>, Sender<U>, Receiver<U>>
963
964 explicit Receiver(internal::Channel<T>& channel)
966 : channel_(&channel) {
967 channel_->add_receiver();
968 }
969
970 internal::Channel<T>* channel_;
971};
972
973template <typename T>
974class [[nodiscard]] SendFuture final
975 : public internal::ChannelFuture<SendFuture<T>, T, bool> {
976 private:
978
979 public:
980 constexpr SendFuture() = default;
981
982 SendFuture(SendFuture&& other) PW_LOCKS_EXCLUDED(*other.channel())
983 : Base(static_cast<Base&&>(other)), value_(std::move(other.value_)) {}
984
985 SendFuture& operator=(SendFuture&& other)
986 PW_LOCKS_EXCLUDED(*this->channel(), *other.channel()) {
987 value_ = std::move(other.value_);
988 // NOLINTNEXTLINE(misc-unconventional-assign-operator)
989 return static_cast<SendFuture&>(this->MoveAssignFrom(other));
990 }
991
992 ~SendFuture() PW_LOCKS_EXCLUDED(*this->channel()) {
993 this->RemoveFromChannel();
994 }
995
996 private:
997 friend Base;
999 friend Sender<T>;
1000
1001 SendFuture(internal::Channel<T>* channel, const T& value)
1002 PW_LOCKS_EXCLUDED(*channel)
1003 : Base(channel), value_(value) {}
1004
1005 SendFuture(internal::Channel<T>* channel, T&& value)
1006 PW_LOCKS_EXCLUDED(*channel)
1007 : Base(channel), value_(std::move(value)) {}
1008
1009 Poll<bool> DoPend(Context& cx) PW_LOCKS_EXCLUDED(*this->channel()) {
1010 if (this->channel() == nullptr) {
1011 PW_DASSERT(this->is_pendable());
1012 return Ready(false);
1013 }
1014
1015 this->channel()->lock();
1016 PW_DASSERT(this->is_pendable());
1017 if (!this->channel()->is_open_locked()) {
1018 this->Complete();
1019 return Ready(false);
1020 }
1021
1022 if (this->channel()->full()) {
1023 this->StoreWakerForSend(cx);
1024 return Pending();
1025 }
1026
1027 this->channel()->PushAndWake(std::move(*value_));
1028 this->Complete();
1029 return Ready(true);
1030 }
1031
1032 std::optional<T> value_;
1033};
1034
1041template <typename T>
1043 public:
1044 SendReservation(const SendReservation& other) = delete;
1045 SendReservation& operator=(const SendReservation& other) = delete;
1046
1048 : channel_(std::exchange(other.channel_, nullptr)) {}
1049
1050 SendReservation& operator=(SendReservation&& other) {
1051 if (this == &other) {
1052 return *this;
1053 }
1054 Cancel();
1055 channel_ = std::exchange(other.channel_, nullptr);
1056 return *this;
1057 }
1058
1059 ~SendReservation() { Cancel(); }
1060
1062 template <typename... Args>
1063 void Commit(Args&&... args) {
1064 PW_ASSERT(channel_ != nullptr);
1065 channel_->CommitReservationAndRemoveRef(std::forward<Args>(args)...);
1066 channel_ = nullptr;
1067 }
1068
1070 void Cancel() {
1071 if (channel_ != nullptr) {
1072 channel_->DropReservationAndRemoveRef();
1073 channel_ = nullptr;
1074 }
1075 }
1076
1077 private:
1078 friend internal::Channel<T>;
1079 friend class ReserveSendFuture<T>;
1080 friend class Sender<T>;
1081
1082 explicit SendReservation(internal::Channel<T>& channel)
1084 : channel_(&channel) {
1085 channel_->add_ref();
1086 }
1087
1088 internal::Channel<T>* channel_;
1089};
1090
1091template <typename T>
1092class [[nodiscard]] ReserveSendFuture final
1093 : public internal::ChannelFuture<ReserveSendFuture<T>,
1094 T,
1095 std::optional<SendReservation<T>>> {
1096 private:
1097 using Base = internal::
1098 ChannelFuture<ReserveSendFuture, T, std::optional<SendReservation<T>>>;
1099
1100 public:
1101 constexpr ReserveSendFuture() = default;
1102
1103 ReserveSendFuture(ReserveSendFuture&& other) : Base(std::move(other)) {}
1104
1105 ReserveSendFuture& operator=(ReserveSendFuture&& other) {
1106 // NOLINTNEXTLINE(misc-unconventional-assign-operator)
1107 return static_cast<ReserveSendFuture&>(this->MoveAssignFrom(other));
1108 }
1109
1110 ~ReserveSendFuture() PW_LOCKS_EXCLUDED(*this->channel()) {
1111 this->RemoveFromChannel();
1112 }
1113
1114 private:
1115 friend Base;
1116 friend internal::Channel<T>;
1117 friend Sender<T>;
1118
1119 explicit ReserveSendFuture(internal::Channel<T>* channel)
1120 PW_LOCKS_EXCLUDED(*channel)
1121 : Base(channel) {}
1122
1124 PW_LOCKS_EXCLUDED(*this->channel()) {
1125 if (this->channel() == nullptr) {
1126 PW_DASSERT(this->is_pendable());
1127 return Ready<std::optional<SendReservation<T>>>(std::nullopt);
1128 }
1129
1130 this->channel()->lock();
1131 PW_DASSERT(this->is_pendable());
1132 if (!this->channel()->is_open_locked()) {
1133 this->Complete();
1134 return Ready<std::optional<SendReservation<T>>>(std::nullopt);
1135 }
1136
1137 if (this->channel()->remaining_capacity_locked() == 0) {
1138 this->StoreWakerForReserveSend(cx);
1139 return Pending();
1140 }
1141
1142 this->channel()->add_reservation();
1143 SendReservation<T> reservation(*this->channel());
1144 this->Complete();
1145 return reservation;
1146 }
1147};
1148
1150template <typename T>
1151class Sender {
1152 public:
1153 constexpr Sender() : channel_(nullptr) {}
1154
1155 Sender(const Sender& other) = delete;
1156 Sender& operator=(const Sender& other) = delete;
1157
1158 Sender(Sender&& other) noexcept
1159 : channel_(std::exchange(other.channel_, nullptr)) {}
1160
1161 Sender& operator=(Sender&& other) noexcept {
1162 if (this == &other) {
1163 return *this;
1164 }
1165 if (channel_ != nullptr) {
1166 channel_->remove_sender();
1167 }
1168 channel_ = std::exchange(other.channel_, nullptr);
1169 return *this;
1170 }
1171
1172 ~Sender() {
1173 if (channel_ != nullptr) {
1174 channel_->remove_sender();
1175 }
1176 }
1177
1186 template <typename U>
1187 SendFuture<T> Send(U&& value) {
1188 return SendFuture<T>(channel_, std::forward<U>(value));
1189 }
1190
1197
1208 if (channel_ == nullptr) {
1210 }
1211 return channel_->TryReserveSend();
1212 }
1213
1223 Status TrySend(const T& value) {
1224 if (channel_ == nullptr) {
1226 }
1227 return channel_->TrySend(value);
1228 }
1229
1231 Status TrySend(T&& value) {
1232 if (channel_ == nullptr) {
1234 }
1235 return channel_->TrySend(std::move(value));
1236 }
1237
1249 const T& value,
1252 return BlockingSendMoveOrCopy(dispatcher, value, timeout);
1253 }
1254
1257 T&& value,
1260 return BlockingSendMoveOrCopy(dispatcher, std::move(value), timeout);
1261 }
1262
1267 void Disconnect() {
1268 if (channel_ != nullptr) {
1269 channel_->remove_sender();
1270 channel_ = nullptr;
1271 }
1272 }
1273
1275 uint16_t remaining_capacity() const {
1276 return channel_ != nullptr ? channel_->remaining_capacity() : 0;
1277 }
1278
1280 uint16_t capacity() const {
1281 return channel_ != nullptr ? channel_->capacity() : 0;
1282 }
1283
1285 [[nodiscard]] bool is_open() const {
1286 return channel_ != nullptr && channel_->is_open();
1287 }
1288
1289 private:
1290 template <typename U>
1291 friend class internal::Channel;
1292
1293 template <typename U>
1294 friend std::optional<std::tuple<SpmcChannelHandle<U>, Sender<U>>>
1295 CreateSpmcChannel(Allocator&, uint16_t);
1296
1297 template <typename U, uint16_t kCapacity>
1298 friend std::tuple<SpmcChannelHandle<U>, Sender<U>> CreateSpmcChannel(
1300
1301 template <typename U>
1302 friend std::optional<std::tuple<SpscChannelHandle<U>, Sender<U>, Receiver<U>>>
1303 CreateSpscChannel(Allocator&, uint16_t);
1304
1305 template <typename U, uint16_t kCapacity>
1306 friend std::tuple<SpscChannelHandle<U>, Sender<U>, Receiver<U>>
1308
1309 explicit Sender(internal::Channel<T>& channel)
1311 : channel_(&channel) {
1312 channel_->add_sender();
1313 }
1314
1315 template <typename U>
1316 Status BlockingSendMoveOrCopy(Dispatcher& dispatcher,
1317 U&& value,
1319 PW_LOCKS_EXCLUDED(*channel_) {
1320 if (channel_ == nullptr) {
1322 }
1323
1324 if (Status status = channel_->TrySend(std::forward<U>(value));
1325 status.ok() || status.IsFailedPrecondition()) {
1326 return status;
1327 }
1328
1329 return BlockingSendFuture(
1330 dispatcher, // NOLINTNEXTLINE(bugprone-use-after-move)
1331 SendFuture<T>(channel_, std::forward<U>(value)),
1332 timeout);
1333 }
1334
1335 Status BlockingSendFuture(Dispatcher& dispatcher,
1336 SendFuture<T>&& future,
1338 PW_LOCKS_EXCLUDED(*channel_) {
1339 Status status;
1340 sync::TimedThreadNotification notification;
1341
1342 CallbackTask task(
1343 [&status, &notification](bool result) {
1344 status = result ? OkStatus() : Status::FailedPrecondition();
1345 notification.release();
1346 },
1347 std::move(future));
1348 dispatcher.Post(task);
1349
1350 if (timeout == internal::Channel<T>::kWaitForever) {
1351 notification.acquire();
1352 return status;
1353 }
1354
1355 if (!notification.try_acquire_for(timeout)) {
1356 task.Deregister();
1357 return Status::DeadlineExceeded();
1358 }
1359 return status;
1360 }
1361
1362 internal::Channel<T>* channel_;
1363};
1364
1378template <typename T>
1379std::optional<MpmcChannelHandle<T>> CreateMpmcChannel(Allocator& alloc,
1380 uint16_t capacity) {
1381 auto channel = internal::DynamicChannel<T>::Allocate(alloc, capacity);
1382 if (channel == nullptr) {
1383 return std::nullopt;
1384 }
1385 std::lock_guard lock(*channel);
1386 return MpmcChannelHandle<T>(*channel);
1387}
1388
1400template <typename T, uint16_t kCapacity>
1402 std::lock_guard lock(static_cast<internal::Channel<T>&>(storage));
1403 PW_DASSERT(!storage.active_locked());
1404 return MpmcChannelHandle<T>(storage);
1405}
1406
1420template <typename T>
1421std::optional<std::tuple<MpscChannelHandle<T>, Receiver<T>>> CreateMpscChannel(
1422 Allocator& alloc, uint16_t capacity) {
1423 auto channel = internal::DynamicChannel<T>::Allocate(alloc, capacity);
1424 if (channel == nullptr) {
1425 return std::nullopt;
1426 }
1427 std::lock_guard lock(*channel);
1428 return std::make_tuple(MpscChannelHandle<T>(*channel), Receiver<T>(*channel));
1429}
1430
1442template <typename T, uint16_t kCapacity>
1443std::tuple<MpscChannelHandle<T>, Receiver<T>> CreateMpscChannel(
1445 std::lock_guard lock(static_cast<internal::Channel<T>&>(storage));
1446 PW_DASSERT(!storage.active_locked());
1447 return std::make_tuple(MpscChannelHandle<T>(storage), Receiver<T>(storage));
1448}
1449
1463template <typename T>
1464std::optional<std::tuple<SpmcChannelHandle<T>, Sender<T>>> CreateSpmcChannel(
1465 Allocator& alloc, uint16_t capacity) {
1466 auto channel = internal::DynamicChannel<T>::Allocate(alloc, capacity);
1467 if (channel == nullptr) {
1468 return std::nullopt;
1469 }
1470 std::lock_guard lock(*channel);
1471 return std::make_tuple(SpmcChannelHandle<T>(*channel), Sender<T>(*channel));
1472}
1473
1485template <typename T, uint16_t kCapacity>
1486std::tuple<SpmcChannelHandle<T>, Sender<T>> CreateSpmcChannel(
1488 std::lock_guard lock(static_cast<internal::Channel<T>&>(storage));
1489 PW_DASSERT(!storage.active_locked());
1490 return std::make_tuple(SpmcChannelHandle<T>(storage), Sender<T>(storage));
1491}
1492
1506template <typename T>
1507std::optional<std::tuple<SpscChannelHandle<T>, Sender<T>, Receiver<T>>>
1508CreateSpscChannel(Allocator& alloc, uint16_t capacity) {
1509 auto channel = internal::DynamicChannel<T>::Allocate(alloc, capacity);
1510 if (channel == nullptr) {
1511 return std::nullopt;
1512 }
1513 std::lock_guard lock(*channel);
1514 return std::make_tuple(SpscChannelHandle<T>(*channel),
1515 Sender<T>(*channel),
1516 Receiver<T>(*channel));
1517}
1518
1530template <typename T, uint16_t kCapacity>
1531std::tuple<SpscChannelHandle<T>, Sender<T>, Receiver<T>> CreateSpscChannel(
1533 std::lock_guard lock(static_cast<internal::Channel<T>&>(storage));
1534 PW_DASSERT(!storage.active_locked());
1535 return std::make_tuple(
1536 SpscChannelHandle<T>(storage), Sender<T>(storage), Receiver<T>(storage));
1537}
1538
1540
1541namespace internal {
1542
1543inline void BaseChannelFuture::Complete() PW_UNLOCK_FUNCTION(*channel_) {
1544 channel_->RemoveRefAndDestroyIfUnreferenced();
1545 channel_ = nullptr;
1546}
1547
1548} // namespace internal
1549} // namespace pw::async2
Definition: allocator.h:45
std::enable_if_t<!std::is_array_v< T >, T * > New(Args &&... args)
Definition: allocator.h:66
Abstract interface for releasing memory.
Definition: deallocator.h:29
Definition: deque.h:207
Definition: result.h:143
Definition: status.h:120
static constexpr Status DeadlineExceeded()
Definition: status.h:177
static constexpr Status Unavailable()
Definition: status.h:304
static constexpr Status FailedPrecondition()
Definition: status.h:243
Definition: callback_task.h:44
Channel handle for a particular type T.
Definition: channel.h:532
Sender< T > CreateSender()
Definition: channel.h:549
Receiver< T > CreateReceiver()
Definition: channel.h:556
Definition: channel.h:737
bool active() const
Definition: channel.h:761
Definition: context.h:46
Definition: future.h:399
Definition: dispatcher.h:46
constexpr bool is_pendable() const
Definition: future.h:246
void MarkComplete()
Definition: future.h:297
constexpr bool is_complete() const
Definition: future.h:251
Definition: future.h:111
Definition: channel.h:692
Definition: channel.h:649
A handle to a multi-producer, multi-consumer channel.
Definition: channel.h:564
friend std::optional< MpmcChannelHandle< U > > CreateMpmcChannel(Allocator &, uint16_t)
Definition: channel.h:1379
A handle to a multi-producer, single-consumer channel.
Definition: channel.h:586
friend std::optional< std::tuple< MpscChannelHandle< U >, Receiver< U > > > CreateMpscChannel(Allocator &, uint16_t)
Definition: channel.h:1421
Definition: poll.h:138
Definition: channel.h:771
A receiver which reads values from an asynchronous channel.
Definition: channel.h:825
friend std::optional< std::tuple< MpscChannelHandle< U >, Receiver< U > > > CreateMpscChannel(Allocator &, uint16_t)
Definition: channel.h:1421
bool is_open() const
Returns true if the channel is open.
Definition: channel.h:940
Result< T > TryReceive()
Definition: channel.h:921
friend std::optional< std::tuple< SpscChannelHandle< U >, Sender< U >, Receiver< U > > > CreateSpscChannel(Allocator &, uint16_t)
Definition: channel.h:1508
Result< T > BlockingReceive(Dispatcher &dispatcher, chrono::SystemClock::duration timeout=internal::Channel< T >::kWaitForever)
Definition: channel.h:861
void Disconnect()
Definition: channel.h:932
ReceiveFuture< T > Receive()
Definition: channel.h:911
Definition: channel.h:1095
Definition: channel.h:975
Definition: channel.h:1042
void Cancel()
Releases the reservation, making the space available for other senders.
Definition: channel.h:1070
void Commit(Args &&... args)
Commits a value to a reserved slot.
Definition: channel.h:1063
A sender which writes values to an asynchronous channel.
Definition: channel.h:1151
SendFuture< T > Send(U &&value)
Definition: channel.h:1187
Result< SendReservation< T > > TryReserveSend()
Definition: channel.h:1207
friend std::optional< std::tuple< SpmcChannelHandle< U >, Sender< U > > > CreateSpmcChannel(Allocator &, uint16_t)
Definition: channel.h:1464
Status TrySend(const T &value)
Definition: channel.h:1223
friend std::optional< std::tuple< SpscChannelHandle< U >, Sender< U >, Receiver< U > > > CreateSpscChannel(Allocator &, uint16_t)
Definition: channel.h:1508
ReserveSendFuture< T > ReserveSend()
Definition: channel.h:1196
uint16_t capacity() const
Returns the maximum capacity of the channel.
Definition: channel.h:1280
Status TrySend(T &&value)
Definition: channel.h:1231
uint16_t remaining_capacity() const
Returns the remaining capacity of the channel.
Definition: channel.h:1275
void Disconnect()
Definition: channel.h:1267
bool is_open() const
Returns true if the channel is open.
Definition: channel.h:1285
Status BlockingSend(Dispatcher &dispatcher, const T &value, chrono::SystemClock::duration timeout=internal::Channel< T >::kWaitForever)
Definition: channel.h:1248
Status BlockingSend(Dispatcher &dispatcher, T &&value, chrono::SystemClock::duration timeout=internal::Channel< T >::kWaitForever)
Definition: channel.h:1256
A handle to a single-producer, multi-consumer channel.
Definition: channel.h:607
friend std::optional< std::tuple< SpmcChannelHandle< U >, Sender< U > > > CreateSpmcChannel(Allocator &, uint16_t)
Definition: channel.h:1464
A handle to a single-producer, single-consumer channel.
Definition: channel.h:628
friend std::optional< std::tuple< SpscChannelHandle< U >, Sender< U >, Receiver< U > > > CreateSpscChannel(Allocator &, uint16_t)
Definition: channel.h:1508
bool is_complete() const
True if the future has returned Ready().
Definition: channel.h:74
bool is_pendable() const
True if the Pend can be called on the future.
Definition: channel.h:71
Definition: channel.h:165
Definition: channel.h:130
Definition: channel.h:317
Definition: channel.h:450
Definition: storage.h:86
Definition: storage.h:39
constexpr size_type capacity() const noexcept
Returns the maximum number of elements in the deque.
Definition: generic_deque.h:74
Definition: interrupt_spin_lock.h:50
Definition: timed_thread_notification.h:40
bool try_acquire_for(chrono::SystemClock::duration timeout)
void Deallocate(void *ptr)
Definition: deallocator.h:60
std::optional< std::tuple< SpmcChannelHandle< T >, Sender< T > > > CreateSpmcChannel(Allocator &alloc, uint16_t capacity)
Definition: channel.h:1464
std::optional< std::tuple< MpscChannelHandle< T >, Receiver< T > > > CreateMpscChannel(Allocator &alloc, uint16_t capacity)
Definition: channel.h:1421
std::optional< MpmcChannelHandle< T > > CreateMpmcChannel(Allocator &alloc, uint16_t capacity)
Definition: channel.h:1379
std::optional< std::tuple< SpscChannelHandle< T >, Sender< T >, Receiver< T > > > CreateSpscChannel(Allocator &alloc, uint16_t capacity)
Definition: channel.h:1508
std::conditional_t< std::is_void_v< typename T::value_type >, ReadyType, typename T::value_type > FutureValue
Definition: future.h:107
constexpr bool IsReady() const noexcept
Returns whether or not this value is Ready.
Definition: poll.h:211
constexpr PendingType Pending()
Returns a value indicating that an operation was not yet able to complete.
Definition: poll.h:353
constexpr Poll Ready()
Returns a value indicating completion.
Definition: poll.h:337
std::chrono::duration< rep, period > duration
Alias for durations representable with this clock.
Definition: system_clock.h:90
constexpr bool CheckedIncrement(T &base, Inc inc)
Definition: checked_arithmetic.h:118
constexpr Status OkStatus()
Definition: status.h:450
#define PW_LOCKABLE(name)
Definition: lock_annotations.h:208
#define PW_GUARDED_BY(x)
Definition: lock_annotations.h:60
#define PW_NO_LOCK_SAFETY_ANALYSIS
Definition: lock_annotations.h:292
#define PW_EXCLUSIVE_LOCK_FUNCTION(...)
Definition: lock_annotations.h:230
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:146
#define PW_LOCK_RETURNED(x)
Definition: lock_annotations.h:197
#define PW_UNLOCK_FUNCTION(...)
Definition: lock_annotations.h:247
#define PW_LOCKS_EXCLUDED(...)
Definition: lock_annotations.h:176