Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::runtime::Slot< T > Class Template Reference

Lock-free publication to a reader that must never block. More...

#include <slot.hpp>

Classes

class  ReadGuard
 RAII pin. More...

Public Member Functions

 Slot ()=default
 Slot (const Slot &)=delete
Slot & operator= (const Slot &)=delete
 ~Slot ()
 Blocks until every reader has left, then frees everything.
ReadGuard read () const noexcept
 Audio-thread-callable.
void prepare_publish ()
 Publisher thread.
void publish_prepared (std::shared_ptr< T > next) noexcept
 Publish after prepare_publish().
void publish (std::shared_ptr< T > next)
void publish (std::unique_ptr< T > next)
void unpublish ()
 Publisher thread.
void reclaim_if_quiescent ()
 Publisher thread.
void wait_and_clear ()
 Publisher thread, teardown only.
const std::shared_ptr< T > & live () const noexcept
 Publisher thread only.
std::size_t retired_count () const noexcept
 Number of displaced values still awaiting reclamation.
bool has_value () const noexcept
 True once something has been published.

Detailed Description

template<typename T>
class pulp::runtime::Slot< T >

Lock-free publication to a reader that must never block.

The reader pins the slot for the duration of its access; the writer swaps in a new value and parks the old one until every reader has left.

Slot manages the published object's LIFETIME, not its constness. A pin guarantees only that the object will not be destroyed while you hold it. RCU is a reclamation scheme, not an immutability scheme.

That distinction is load-bearing. SignalGraph's published CompiledGraph is emphatically not immutable: the audio thread writes every node's scratch buffer through it on every block, and control-thread readers drain telemetry and inject MIDI through the same pin. What is immutable is the topology. If you want a genuinely read-only value, say so in the type — Slot<const T> — and the guard hands back const T* for free.

The audio thread's cost is one seq_cst increment, one atomic load, and one seq_cst decrement. No allocation, no destructor, no lock.

Slot<CompiledGraph> graph; // interior mutable: audio thread writes scratch
Slot<const ImpulseResponse> ir; // genuinely read-only
// Control thread:
graph.publish(std::make_unique<CompiledGraph>(rebuild()));
// Audio thread:
if (auto pin = graph.read()) {
run(*pin); // valid for the lifetime of `pin`
}
Definition graph_runtime_buffer_assignment.hpp:8
Warning
Exactly one publisher thread. Any number of readers. Whether two readers may safely mutate the same interior state concurrently is the published type's problem, not Slot's.

Constructor & Destructor Documentation

◆ Slot() [1/2]

template<typename T>
pulp::runtime::Slot< T >::Slot ( )
default

◆ Slot() [2/2]

template<typename T>
pulp::runtime::Slot< T >::Slot ( const Slot< T > & )
delete

◆ ~Slot()

template<typename T>
pulp::runtime::Slot< T >::~Slot ( )
inline

Blocks until every reader has left, then frees everything.

Publisher thread only, and only once both sides have stopped racing to publish.

Member Function Documentation

◆ has_value()

template<typename T>
bool pulp::runtime::Slot< T >::has_value ( ) const
inlinenoexcept

True once something has been published.

◆ live()

template<typename T>
const std::shared_ptr< T > & pulp::runtime::Slot< T >::live ( ) const
inlinenoexcept

Publisher thread only.

The currently published value, as a shared_ptr the publisher may keep. Readers must use read() — this accessor is not synchronized against a concurrent publish().

◆ operator=()

template<typename T>
Slot & pulp::runtime::Slot< T >::operator= ( const Slot< T > & )
delete

◆ prepare_publish()

template<typename T>
void pulp::runtime::Slot< T >::prepare_publish ( )
inline

Publisher thread.

Swap in a new value; the displaced one is parked and freed as soon as no reader holds it. Publishing nullptr unpublishes. Publisher-thread allocation preflight for publish_prepared(). Call this before an external transaction reaches its irreversible commit point. Any allocation failure is reported here, while all external state is still untouched.

◆ publish() [1/2]

template<typename T>
void pulp::runtime::Slot< T >::publish ( std::shared_ptr< T > next)
inline

◆ publish() [2/2]

template<typename T>
void pulp::runtime::Slot< T >::publish ( std::unique_ptr< T > next)
inline

◆ publish_prepared()

template<typename T>
void pulp::runtime::Slot< T >::publish_prepared ( std::shared_ptr< T > next)
inlinenoexcept

Publish after prepare_publish().

This operation cannot allocate or throw, so it is safe to pair immediately after an external commit.

◆ read()

template<typename T>
ReadGuard pulp::runtime::Slot< T >::read ( ) const
inlinenodiscardnoexcept

Audio-thread-callable.

Pin and read the currently published value. Returns a falsy guard when nothing has been published yet.

RT contract: never allocates, never blocks, never frees.

◆ reclaim_if_quiescent()

template<typename T>
void pulp::runtime::Slot< T >::reclaim_if_quiescent ( )
inline

Publisher thread.

Free any parked values if no reader is currently inside read(). Non-blocking: does nothing when a reader is active. Call it opportunistically (e.g. after each block) to bound memory.

◆ retired_count()

template<typename T>
std::size_t pulp::runtime::Slot< T >::retired_count ( ) const
inlinenoexcept

Number of displaced values still awaiting reclamation.

◆ unpublish()

template<typename T>
void pulp::runtime::Slot< T >::unpublish ( )
inline

Publisher thread.

Drop the published value: readers immediately see nothing, and the displaced value is reclaimed once they drain.

Spelled out rather than publish(nullptr) — which is ambiguous between the two overloads above, and reads worse at the call site.

◆ wait_and_clear()

template<typename T>
void pulp::runtime::Slot< T >::wait_and_clear ( )
inline

Publisher thread, teardown only.

Spins until readers drain, then frees. Never call this from the audio thread.


The documentation for this class was generated from the following file:
  • /home/runner/work/pulp/pulp/core/runtime/include/pulp/runtime/slot.hpp