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
impl AsyncSignalWaker
pub fn new() -> Self
Sourcepub fn mark_active(&self, index: u64)
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
}Sourcepub fn mark_active_mask(&self, mask: u64)
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 (biti= wordi)
§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 opSourcepub fn try_unmark_if_empty(&self, bit_index: u64, signal: &AtomicU64)
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 clearsignal- 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);Sourcepub fn try_unmark(&self, bit_index: u64)
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
Sourcepub fn snapshot_summary(&self) -> u64
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
}
}Sourcepub fn summary_select(&self, nearest_to_index: u64) -> u64
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
}Sourcepub fn try_acquire(&self) -> bool
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
trueif a permit was consumed (consumer should process work)falseif 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
}Sourcepub fn acquire(&self)
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
- Increment
sleeperscount - Wait on condvar (releases mutex)
- Recheck permits after wakeup
- Decrement
sleeperson 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();
}Sourcepub fn acquire_timeout(&self, timeout: Duration) -> bool
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
trueif a permit was acquiredfalseif 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; }
}
}Sourcepub fn release(&self, n: usize)
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 consumersSourcepub fn summary_bits(&self) -> u64
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.