100 : owner_(
other.owner_), value_(
other.value_) {
101 other.owner_ =
nullptr;
102 other.value_ =
nullptr;
106 if (owner_ !=
nullptr)
107 owner_->readers_.fetch_sub(1, std::memory_order_seq_cst);
110 T*
get() const noexcept {
return value_; }
113 explicit operator bool() const noexcept {
return value_ !=
nullptr; }
117 ReadGuard(
const Slot* owner, T* value) noexcept : owner_(owner), value_(value) {}
119 const Slot* owner_ =
nullptr;
135 [[nodiscard]] ReadGuard
read() const noexcept {
136 readers_.fetch_add(1, std::memory_order_seq_cst);
140 T* value = live_raw_.load(std::memory_order_seq_cst);
141 if (value ==
nullptr) {
142 readers_.fetch_sub(1, std::memory_order_seq_cst);
145 return ReadGuard{
this, value};
157 retired_.reserve(retired_.size() + 1);
163 assert((!live_ || retired_.size() < retired_.capacity()) &&
164 "Slot::publish_prepared requires prepare_publish");
165 live_raw_.store(next.get(), std::memory_order_seq_cst);
167 retired_.push_back(std::move(live_));
168 live_ = std::move(next);
179 void publish(std::unique_ptr<T> next) {
publish(std::shared_ptr<T>(std::move(next))); }
192 if (readers_.load(std::memory_order_seq_cst) == 0)
199 while (readers_.load(std::memory_order_seq_cst) != 0)
200 std::this_thread::yield();
207 const std::shared_ptr<T>&
live() const noexcept {
return live_; }
214 return live_raw_.load(std::memory_order_acquire) !=
nullptr;
220 std::shared_ptr<T> live_;
221 std::atomic<T*> live_raw_{
nullptr};
222 std::vector<std::shared_ptr<T>> retired_;
223 mutable std::atomic<std::uint32_t> readers_{0};
253template <
typename T, std::
size_t RetireCapacity = 8>
262 delete pending_.exchange(
nullptr, std::memory_order_acquire);
263 while (T* raw = pop_retired_raw())
delete raw;
272 if (!next)
return false;
275 T* raw = next.release();
276 delete pending_.exchange(raw, std::memory_order_acq_rel);
285 return std::unique_ptr<T>(pending_.exchange(
nullptr, std::memory_order_acquire));
297 [[nodiscard]]
bool retire(std::unique_ptr<T>& displaced)
noexcept {
298 if (!displaced)
return true;
299 if (!retired_.try_push(displaced.get()))
return false;
300 (void)displaced.release();
308 return retired_.size_approx() + n <= RetireCapacity;
313 std::size_t freed = 0;
314 while (T* raw = pop_retired_raw()) {
315 std::unique_ptr<T> owned(raw);
326 return pending_.load(std::memory_order_acquire) !=
nullptr;
328 bool has_retired() const noexcept {
return retired_.size_approx() > 0; }
333 T* pop_retired_raw() {
334 auto popped = retired_.try_pop();
335 return popped ? *popped :
nullptr;
339 std::atomic<T*> pending_{
nullptr};
342 SpscQueue<T*, RetireCapacity> retired_;
Handoff(const Handoff &)=delete
std::unique_ptr< T > drain_retired_one()
Producer / worker thread.
Definition slot.hpp:323
bool retire(std::unique_ptr< T > &displaced) noexcept
Audio-thread-callable.
Definition slot.hpp:297
bool has_retired() const noexcept
Definition slot.hpp:328
bool has_retire_capacity(std::size_t n=1) const noexcept
Room in the retire ring for n more values.
Definition slot.hpp:307
~Handoff()
Reclaims anything still parked. Both threads must have stopped.
Definition slot.hpp:261
bool has_pending() const noexcept
Definition slot.hpp:325
std::size_t drain_retired()
Producer / worker thread. Free every parked value. Returns the count.
Definition slot.hpp:312
Handoff & operator=(const Handoff &)=delete
static constexpr std::size_t retire_capacity() noexcept
Definition slot.hpp:330
bool publish(std::unique_ptr< T > next)
Producer thread.
Definition slot.hpp:271
std::unique_ptr< T > try_consume() noexcept
Audio-thread-callable.
Definition slot.hpp:284
~ReadGuard()
Definition slot.hpp:105
T * operator->() const noexcept
Definition slot.hpp:112
T * get() const noexcept
Definition slot.hpp:110
ReadGuard() noexcept=default
friend class Slot
Definition slot.hpp:116
T & operator*() const noexcept
Definition slot.hpp:111
void publish(std::unique_ptr< T > next)
Definition slot.hpp:179
std::size_t retired_count() const noexcept
Number of displaced values still awaiting reclamation.
Definition slot.hpp:210
void prepare_publish()
Publisher thread.
Definition slot.hpp:154
void reclaim_if_quiescent()
Publisher thread.
Definition slot.hpp:191
void unpublish()
Publisher thread.
Definition slot.hpp:186
ReadGuard read() const noexcept
Audio-thread-callable.
Definition slot.hpp:135
void wait_and_clear()
Publisher thread, teardown only.
Definition slot.hpp:198
Slot(const Slot &)=delete
const std::shared_ptr< T > & live() const noexcept
Publisher thread only.
Definition slot.hpp:207
bool has_value() const noexcept
True once something has been published.
Definition slot.hpp:213
Slot & operator=(const Slot &)=delete
void publish_prepared(std::shared_ptr< T > next) noexcept
Publish after prepare_publish().
Definition slot.hpp:162
void publish(std::shared_ptr< T > next)
Definition slot.hpp:172
~Slot()
Blocks until every reader has left, then frees everything.
Definition slot.hpp:129
Definition generated_event_source.hpp:33
@ other
Definition udev_monitor.hpp:26