AsyncSignalWaker

Struct AsyncSignalWaker 

Source
pub struct AsyncSignalWaker { /* private fields */ }
Expand description

A cache-optimized waker that packs queue summaries and control flags into a single status word.

Implementations§

Source§

impl AsyncSignalWaker

Source

pub fn new() -> Self

Source

pub fn mark_active(&self, index: u64)

Marks a signal word at index (0..63) as active in the summary.

Called by producers when a queue transitions from empty to non-empty. If this is a 0→1 transition (bit was previously clear), adds 1 permit and wakes 1 sleeping thread.

§Fast Path

If the bit is already set, returns immediately without touching atomics. This is the common case when multiple producers push to the same word group.

§Arguments
  • index - Word index (0..63) to mark as active
§Example
// Producer pushes to queue 5 in word 0
let (was_empty, was_set) = signal.set(5);
if was_empty && was_set {
    waker.mark_active(0);  // Wake 1 consumer
}
Source

pub fn mark_active_mask(&self, mask: u64)

Batch version of mark_active(): marks multiple words as active at once.

Efficiently handles multiple queues becoming active simultaneously. Releases exactly k permits, where k is the number of 0→1 transitions (newly-active words).

§Optimization

Uses a single fetch_or instead of calling mark_active() in a loop, reducing atomic contention when many queues activate together.

§Arguments
  • mask - Bitmap of words to mark active (bit i = word i)
§Example
// Multiple queues became active
let mut active_words = 0u64;
for word_idx in 0..64 {
    if word_became_active(word_idx) {
        active_words |= 1 << word_idx;
    }
}
waker.mark_active_mask(active_words);  // Single atomic op
Source

pub fn try_unmark_if_empty(&self, bit_index: u64, signal: &AtomicU64)

Clears the summary bit for bit_index if the corresponding signal word is empty.

This is lazy cleanup - consumers call this after draining a word to prevent false positives in future snapshot_summary() calls. However, it’s safe to skip this; the system remains correct with stale summary bits.

§Arguments
  • bit_index - Word index (0..63) to potentially clear
  • signal - The actual signal word to check for emptiness
§Example
// After draining all queues in word 3
waker.try_unmark_if_empty(3, &signal_word_3);
Source

pub fn try_unmark(&self, bit_index: u64)

Unconditionally clears the summary bit for bit_index.

Faster than try_unmark_if_empty() when the caller already knows the word is empty (avoids checking the signal word).

§Arguments
  • bit_index - Word index (0..63) to clear
Source

pub fn snapshot_summary(&self) -> u64

Returns a snapshot of the current summary bitmap.

Consumers use this to quickly identify which word groups have potential work. If bit i is set, word i may have active queues (false positives possible due to lazy cleanup).

§Memory Ordering

Uses Relaxed because this is a hint, not a synchronization point. The actual queue data is synchronized via acquire/release on the permits counter.

§Returns

A u64 bitmap where bit i indicates word i has potential work.

§Example
let summary = waker.snapshot_summary();
for word_idx in 0..64 {
    if summary & (1 << word_idx) != 0 {
        // Check queues in word_idx
    }
}
Source

pub fn summary_select(&self, nearest_to_index: u64) -> u64

Finds the nearest set bit to nearest_to_index in the summary.

Useful for maintaining locality: continue working on queues near the last processed index, improving cache behavior.

§Arguments
  • nearest_to_index - Preferred starting point (0..63)
§Returns

The index of the nearest set bit, or undefined if summary is empty.

§Example
let mut last_word = 0;
loop {
    last_word = waker.summary_select(last_word);
    // Process queues in word last_word
}
Source

pub fn try_acquire(&self) -> bool

Non-blocking attempt to acquire a permit.

Atomically decrements the permit counter if available. This is the lock-free fast path used by consumers before resorting to blocking.

§Returns
  • true if a permit was consumed (consumer should process work)
  • false if no permits available (queue likely empty)
§Memory Ordering

Uses AcqRel to synchronize with producers’ Release in release(). This ensures queue data written by producers is visible to this consumer.

§Example
if waker.try_acquire() {
    // Process work (permit guarantees something is available)
} else {
    // No work, maybe park or spin
}
Source

pub fn acquire(&self)

Blocking acquire: parks the thread until a permit becomes available.

Tries the fast path first (try_acquire()), then falls back to parking on a condvar. Handles spurious wakeups by rechecking permits in a loop.

§Blocking Behavior
  1. Increment sleepers count
  2. Wait on condvar (releases mutex)
  3. Recheck permits after wakeup
  4. Decrement sleepers on exit
§Panics

Panics if the mutex or condvar is poisoned (indicates a panic in another thread while holding the lock).

§Example
loop {
    waker.acquire();  // Blocks until work available
    process_work();
}
Source

pub fn acquire_timeout(&self, timeout: Duration) -> bool

Blocking acquire with timeout.

Like acquire(), but returns after timeout if no permit becomes available. Useful for implementing shutdown or periodic maintenance.

§Arguments
  • timeout - Maximum duration to wait
§Returns
  • true if a permit was acquired
  • false if timed out without acquiring
§Example
use std::time::Duration;

loop {
    if waker.acquire_timeout(Duration::from_secs(1)) {
        process_work();
    } else {
        // Timeout - check for shutdown signal
        if should_shutdown() { break; }
    }
}
Source

pub fn release(&self, n: usize)

Releases n permits and wakes up to n sleeping threads.

Called by producers (indirectly via mark_active) when queues become active. Uses targeted wakeups: only notifies up to min(n, sleepers) threads, avoiding unnecessary notify_one() calls.

§Permit Accumulation

If no threads are sleeping, permits accumulate for future consumers. This guarantees no lost wakeups: late-arriving consumers find work immediately.

§Arguments
  • n - Number of permits to release (typically 1 or count of newly-active queues)
§Memory Ordering

Uses Release to ensure queue data is visible to consumers who Acquire via try_acquire().

§Example
// Producer activates 3 queues
waker.release(3);  // Wakes up to 3 sleeping consumers
Source

pub fn summary_bits(&self) -> u64

Returns the current summary bitmap.

Useful for debugging or metrics. Equivalent to snapshot_summary() but uses Acquire ordering for stronger visibility guarantees.

Source

pub fn permits(&self) -> u64

Returns the current number of available permits.

Useful for monitoring queue health or load. A high permit count may indicate consumers are falling behind.

Trait Implementations§

Source§

impl Default for AsyncSignalWaker

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V