#thread-safe #queue #lockless #spsc #atomic #operations

no-std bbqueue-ng

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

5 unstable releases

0.101.1 Jan 2, 2021
0.101.0 Jan 2, 2021
0.100.1 Dec 28, 2020
0.100.0 Dec 28, 2020
0.4.11 Nov 26, 2020

#1549 in Embedded development

MIT/Apache

63KB
689 lines

BBQueue(-ng)

EXPERIMENTAL NOTICE

NOTE: This is the experimental next-generation version of bbqueue. This version generally doesn't respect semver, and may have incorrect documentation. If you want something more stable, use the regular version of bbqueue!

Probably out of date docs

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.

For a 90 minute guided tour of BBQueue, you can also view this guide on YouTube.

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

// Create a buffer with six elements
let bb: BBBuffer<6> = BBBuffer::new();
let (mut prod, mut cons) = bb.try_split().unwrap();

// 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_ng::BBBuffer;

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

fn main() {
    // Split the bbqueue into producer and consumer halves.
    // These halves can be sent to different threads or to
    // an interrupt handler for thread safe SPSC usage
    let (mut prod, mut cons) = BB.try_split().unwrap();

    // 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);

    // The buffer cannot be split twice
    assert!(BB.try_split().is_err());
}

Features

By default BBQueue uses atomic operations which are available on most platforms. However on some (mostly embedded) platforms atomic support is limited and with the default features you will get a compiler error about missing atomic methods.

This crate contains special support for Cortex-M0(+) targets with the thumbv6 feature. By enabling the feature, unsupported atomic operations will be replaced with critical sections implemented by disabling interrupts. The critical sections are very short, a few instructions at most, so they should make no difference to most applications.

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.

Dependencies

~180KB