bbqueue 0.6.0

A SPSC, lockless, no_std, thread safe, queue, based on BipBuffers
Documentation

BBQueue

Documentation

BBQueue

BBQueue, short for "BipBuffer Queue", is a Single Producer Single Consumer, lockless, no_std, thread safe, queue, based on BipBuffers. For more info on the design of the lock-free algorithm used by bbqueue, see this blog post.

BBQueue is designed (primarily) to be a First-In, First-Out queue for use with DMA on embedded systems.

While Circular/Ring Buffers allow you to send data between two threads (or from an interrupt to main code), you must push the data one piece at a time. With BBQueue, you instead are granted a block of contiguous memory, which can be filled (or emptied) by a DMA engine.

Local usage

// The "Churrasco" flavor has inline storage, hardware atomic
// support, no async support, and is not reference counted.
use bbqueue::nicknames::Churrasco;

// Create a buffer with six elements
let bb: Churrasco<6> = Churrasco::new();
let prod = bb.stream_producer();
let cons = bb.stream_consumer();

// Request space for one byte
let mut wgr = prod.grant_exact(1).unwrap();

// Set the data
wgr[0] = 123;

assert_eq!(wgr.len(), 1);

// Make the data ready for consuming
wgr.commit(1);

// Read all available bytes
let rgr = cons.read().unwrap();

assert_eq!(rgr[0], 123);

// Release the space for later writes
rgr.release(1);

Static usage

use bbqueue::nicknames::Churrasco;
use std::{thread::{sleep, spawn}, time::Duration};

// Create a buffer with six elements
static BB: Churrasco<6> = Churrasco::new();

fn receiver() {
    let cons = BB.stream_consumer();
    loop {
        if let Ok(rgr) = cons.read() {
            assert_eq!(rgr.len(), 1);
            assert_eq!(rgr[0], 123);
            rgr.release(1);
            break;
        }
        // don't do this in real code, use Notify!
        sleep(Duration::from_millis(10));
    }
}

fn main() {
    let prod = BB.stream_producer();

    // spawn the consumer
    let hdl = spawn(receiver);

    // Request space for one byte
    let mut wgr = prod.grant_exact(1).unwrap();

    // Set the data
    wgr[0] = 123;

    assert_eq!(wgr.len(), 1);

    // Make the data ready for consuming
    wgr.commit(1);

    // make sure the receiver terminated
    hdl.join().unwrap();
}

Nicknames

bbqueue uses generics to customize the data structure in four main ways:

  • Whether the byte storage is inline (and const-generic), or heap allocated
  • Whether the queue is polling-only, or supports async/await sending/receiving
  • Whether the queue uses a lock-free algorithm with CAS atomics, or uses a critical section (for targets that don't have CAS atomics)
  • Whether the queue is reference counted, allowing Producer and Consumer halves to be passed around without lifetimes.

See the nicknames module for all sixteen variants.

Stability

bbqueue v0.6 is a breaking change from the older "classic" v0.5 interfaces. The intent is to have a few minor breaking changes in early 2026, and to get to v1.0 as quickly as possible.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.