Signal

Struct Signal 

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

A cache-line padded 64-bit atomic bitmap for tracking queue readiness.

Each Signal represents a group of up to 64 queues, where each bit indicates whether the corresponding queue has work available. Multiple Signal instances are coordinated via a SignalWaker to form a complete two-level bitmap.

§Design

Signal (64-bit AtomicU64)
┌───┬───┬───┬───┬─────┬───┐
│ 0 │ 1 │ 0 │ 1 │ ... │ 0 │  Each bit = one queue's scheduled state
└───┴───┴───┴───┴─────┴───┘
  Q0  Q1  Q2  Q3  ...  Q63

§Cache Optimization

The inner state is wrapped in Arc<CachePadded<...>> to:

  • Allow cheap cloning (single pointer copy)
  • Prevent false sharing between different signals
  • Optimize for hot paths (producers setting bits, executor clearing bits)

§Thread Safety

All operations use atomic instructions. Multiple producers can concurrently set bits (via set()), and the executor can concurrently acquire/clear bits (via acquire() or try_acquire()).

§Cloning

Signal is cheaply clonable via Arc. All clones share the same underlying atomic bitmap, making it suitable for distribution across multiple producer threads.

Implementations§

Source§

impl Signal

Source

pub fn index(&self) -> u64

Returns the signal’s index within the SignalWaker’s signal array.

This index is used to:

  • Map this signal to the corresponding bit in the summary bitmap
  • Identify which group of 64 queues this signal represents
§Example
let signal = Signal::with_index(5);
assert_eq!(signal.index(), 5);
// This signal controls queues 320-383 (5 * 64 through (5+1) * 64 - 1)
Source

pub fn value(&self) -> &AtomicU64

Returns a reference to the underlying atomic value.

Provides direct access to the 64-bit bitmap for advanced use cases that need custom atomic operations beyond the provided methods.

§Use Cases
  • Custom bit manipulation patterns
  • Debugging (observing raw bitmap state)
  • Integration with external synchronization primitives
§Example
let signal = Signal::new();
signal.set(10);
let raw_value = signal.value().load(Ordering::Relaxed);
assert_eq!(raw_value & (1 << 10), 1 << 10);  // Bit 10 is set
Source§

impl Signal

Source

pub fn new() -> Self

Creates a new Signal with index 0 and all bits cleared.

§Example
let signal = Signal::new();
assert_eq!(signal.index(), 0);
assert!(signal.is_empty());
Source

pub fn with_index(index: u64) -> Self

Creates a new Signal with the specified index and all bits cleared.

§Parameters
  • index: Position in the SignalWaker’s signal array (0-61)
§Example
let signal = Signal::with_index(10);
assert_eq!(signal.index(), 10);
assert!(signal.is_empty());
Source

pub fn with_value(index: u64, value: u64) -> Self

Creates a new Signal with the specified index and initial bitmap value.

This is primarily used for testing or restoring state. In normal operation, signals start with all bits cleared.

§Parameters
  • index: Position in the SignalWaker’s signal array (0-61)
  • value: Initial 64-bit bitmap value
§Example
// Create signal with bits 0, 5, and 10 already set
let signal = Signal::with_value(3, (1 << 0) | (1 << 5) | (1 << 10));
assert_eq!(signal.size(), 3);
assert!(signal.is_set(0));
assert!(signal.is_set(5));
assert!(signal.is_set(10));
Source

pub fn load(&self, ordering: Ordering) -> u64

Loads the current bitmap value with the specified memory ordering.

§Parameters
  • ordering: Memory ordering for the load operation
§Returns

The 64-bit bitmap value where each set bit represents a ready queue.

§Example
signal.set(5);
signal.set(10);
let value = signal.load(Ordering::Acquire);
assert_eq!(value, (1 << 5) | (1 << 10));
Source

pub fn size(&self) -> u64

Returns the number of set bits (ready queues) in this signal.

Equivalent to popcount(bitmap), this counts how many queues in this signal group currently have work available.

§Performance

Uses the POPCNT instruction on x86_64 (~3 cycles), making it very efficient.

§Example
let signal = Signal::new();
signal.set(0);
signal.set(5);
signal.set(63);
assert_eq!(signal.size(), 3);
Source

pub fn is_empty(&self) -> bool

Returns true if no bits are set (no ready queues).

This is more efficient than size() == 0 for checking emptiness.

§Example
let signal = Signal::new();
assert!(signal.is_empty());
signal.set(10);
assert!(!signal.is_empty());
Source

pub fn set(&self, index: u64) -> (bool, bool)

Atomically sets a bit in the bitmap using fetch_or.

This is the primary method for producers to signal that a queue has work available.

§Parameters
  • index: Bit position to set (0-63)
§Returns

A tuple (was_empty, was_set):

  • was_empty: true if this was the first bit set (signal transitioned from empty to non-empty)
  • was_set: true if the bit was successfully set (wasn’t already set)
§Use Cases

The return values are used for summary bitmap updates:

let (was_empty, was_set) = signal.set(queue_bit);
if was_empty && was_set {
    // This signal was empty, now has work - update summary
    waker.mark_active(signal.index());
}
§Performance

~5-10 ns (one atomic fetch_or operation)

§Example
let signal = Signal::new();
let (was_empty, was_set) = signal.set(5);
assert!(was_empty);  // Signal was empty
assert!(was_set);    // Bit 5 was not previously set

let (was_empty, was_set) = signal.set(5);
assert!(!was_empty); // Signal already had bits set
assert!(!was_set);   // Bit 5 was already set
Source

pub fn set_with_bit(&self, bit: u64) -> u64

Atomically sets a bit using a precomputed bitmask.

Similar to set(), but takes a precomputed 1 << index value for cases where the bit position is computed once and reused.

§Parameters
  • bit: Precomputed bitmask with exactly one bit set (e.g., 1 << 5)
§Returns

The previous bitmap value before setting the bit.

§Example
let signal = Signal::new();
let bit_mask = 1u64 << 10;
let prev = signal.set_with_bit(bit_mask);
assert_eq!(prev, 0);  // Was empty
assert!(signal.is_set(10));
Source

pub fn acquire(&self, index: u64) -> bool

Atomically clears a bit if it is currently set (CAS-based).

This is the primary method for the executor to claim ownership of a ready queue. Uses a CAS loop to ensure the bit is cleared atomically.

§Parameters
  • index: Bit position to clear (0-63)
§Returns
  • true: Bit was set and has been successfully cleared (queue acquired)
  • false: Bit was not set (queue not ready or already acquired)
§Use Cases
// Executor loop
if signal.acquire(queue_bit) {
    // Successfully acquired queue, process it
    process_queue(queue_id);
}
§Performance

~10-20 ns (CAS loop, typically succeeds on first iteration)

§Example
let signal = Signal::new();
signal.set(5);
assert!(signal.acquire(5));  // Successfully cleared bit 5
assert!(!signal.acquire(5)); // Bit already clear, returns false
Source

pub fn try_acquire(&self, index: u64) -> (u64, u64, bool)

Attempts to atomically clear a bit, returning detailed state information.

Similar to acquire(), but provides additional information about the before/after state of the bitmap, useful for debugging or advanced scheduling.

§Parameters
  • index: Bit position to clear (0-63)
§Returns

A tuple (before, after, success):

  • before: Bitmap value before the operation
  • after: Bitmap value after the operation (if successful)
  • success: true if the bit was cleared, false if it wasn’t set
§Example
let signal = Signal::with_value(0, 0b101010);  // Bits 1, 3, 5 set
let (before, after, success) = signal.try_acquire(3);
assert_eq!(before, 0b101010);
assert_eq!(after, 0b100010);   // Bit 3 cleared
assert!(success);
Source

pub fn is_set(&self, index: u64) -> bool

Checks if a specific bit is set without modifying the bitmap.

Non-atomic read followed by bit test. Suitable for non-critical checks where races are acceptable.

§Parameters
  • index: Bit position to check (0-63)
§Returns

true if the bit is set, false otherwise.

§Example
let signal = Signal::new();
assert!(!signal.is_set(5));
signal.set(5);
assert!(signal.is_set(5));

Trait Implementations§

Source§

impl Clone for Signal

Source§

fn clone(&self) -> Signal

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl Freeze for Signal

§

impl RefUnwindSafe for Signal

§

impl Send for Signal

§

impl Sync for Signal

§

impl Unpin for Signal

§

impl UnwindSafe for Signal

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. 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