Skip to content

Commit b4487e7

Browse files
authored
[bbq2]: Minimal docs pass (jamesmunns#117)
* Add a minimal coat of docs paint * Cargo fmt * test on non-atomic target * Fix TODO
1 parent da1a0c2 commit b4487e7

16 files changed

Lines changed: 293 additions & 84 deletions

File tree

.github/workflows/build.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ jobs:
1818
steps:
1919
- uses: actions/checkout@v4
2020
- name: Install embedded target
21-
# Note: once https://github.com/hawkw/mycelium/pull/538 lands we can test on
22-
# thumbv6m-none-eabi
23-
run: rustup target add thumbv7em-none-eabi
21+
run: rustup target add thumbv6m-none-eabi
2422
#
2523
# BUILD + TEST
2624
#
@@ -39,8 +37,8 @@ jobs:
3937

4038
# no features, on mcu
4139
- name: Check bbq2 (no features, on mcu)
42-
run: cargo build --no-default-features --target=thumbv7em-none-eabi
40+
run: cargo build --no-default-features --target=thumbv6m-none-eabi
4341
# default features, on mcu
4442
- name: Check bbq2 (no features, on mcu)
45-
run: cargo build --target=thumbv7em-none-eabi
43+
run: cargo build --target=thumbv6m-none-eabi
4644

bbq2/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ default = [
4545
]
4646
critical-section = [
4747
"dep:critical-section",
48+
"maitake-sync?/critical-section",
4849
]
4950
disable-cache-padding = [
5051
"maitake-sync?/no-cache-pad",

bbq2/src/lib.rs

Lines changed: 106 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,103 @@
1-
//! bbq2
1+
//! # BBQueue
22
//!
3-
//! A new and improved bipbuffer queue.
3+
//! BBQueue, short for "BipBuffer Queue", is a Single Producer Single Consumer,
4+
//! lockless, no_std, thread safe, queue, based on [BipBuffers]. For more info on
5+
//! the design of the lock-free algorithm used by bbqueue, see [this blog post].
46
//!
5-
//! NOTE: This will soon be moved into the `bbqueue` crate, and `bbq2` will be
6-
//! deprecated!
7+
//! [BipBuffers]: https://www.codeproject.com/Articles/3479/%2FArticles%2F3479%2FThe-Bip-Buffer-The-Circular-Buffer-with-a-Twist
8+
//! [this blog post]: https://ferrous-systems.com/blog/lock-free-ring-buffer/
9+
//!
10+
//! BBQueue is designed (primarily) to be a First-In, First-Out queue for use with DMA on embedded
11+
//! systems.
12+
//!
13+
//! While Circular/Ring Buffers allow you to send data between two threads (or from an interrupt to
14+
//! main code), you must push the data one piece at a time. With BBQueue, you instead are granted a
15+
//! block of contiguous memory, which can be filled (or emptied) by a DMA engine.
16+
//!
17+
//! ## Local usage
18+
//!
19+
//! ```rust
20+
//! // The "Churrasco" flavor has inline storage, hardware atomic
21+
//! // support, no async support, and is not reference counted.
22+
//! use bbq2::nicknames::Churrasco;
23+
//!
24+
//! // Create a buffer with six elements
25+
//! let bb: Churrasco<6> = Churrasco::new();
26+
//! let prod = bb.stream_producer();
27+
//! let cons = bb.stream_consumer();
28+
//!
29+
//! // Request space for one byte
30+
//! let mut wgr = prod.grant_exact(1).unwrap();
31+
//!
32+
//! // Set the data
33+
//! wgr[0] = 123;
34+
//!
35+
//! assert_eq!(wgr.len(), 1);
36+
//!
37+
//! // Make the data ready for consuming
38+
//! wgr.commit(1);
39+
//!
40+
//! // Read all available bytes
41+
//! let rgr = cons.read().unwrap();
42+
//!
43+
//! assert_eq!(rgr[0], 123);
44+
//!
45+
//! // Release the space for later writes
46+
//! rgr.release(1);
47+
//! ```
48+
//!
49+
//! ## Static usage
50+
//!
51+
//! ```rust
52+
//! use bbq2::nicknames::Churrasco;
53+
//! use std::{thread::{sleep, spawn}, time::Duration};
54+
//!
55+
//! // Create a buffer with six elements
56+
//! static BB: Churrasco<6> = Churrasco::new();
57+
//!
58+
//! fn receiver() {
59+
//! let cons = BB.stream_consumer();
60+
//! loop {
61+
//! if let Ok(rgr) = cons.read() {
62+
//! assert_eq!(rgr.len(), 1);
63+
//! assert_eq!(rgr[0], 123);
64+
//! rgr.release(1);
65+
//! break;
66+
//! }
67+
//! // don't do this in real code, use Notify!
68+
//! sleep(Duration::from_millis(10));
69+
//! }
70+
//! }
71+
//!
72+
//! fn main() {
73+
//! let prod = BB.stream_producer();
74+
//!
75+
//! // spawn the consumer
76+
//! let hdl = spawn(receiver);
77+
//!
78+
//! // Request space for one byte
79+
//! let mut wgr = prod.grant_exact(1).unwrap();
80+
//!
81+
//! // Set the data
82+
//! wgr[0] = 123;
83+
//!
84+
//! assert_eq!(wgr.len(), 1);
85+
//!
86+
//! // Make the data ready for consuming
87+
//! wgr.commit(1);
88+
//!
89+
//! // make sure the receiver terminated
90+
//! hdl.join().unwrap();
91+
//! }
92+
//! ```
93+
//!
94+
//! ## Features
95+
//!
96+
//! TODO
797
898
#![cfg_attr(not(any(test, feature = "std")), no_std)]
99+
#![deny(missing_docs)]
100+
#![deny(warnings)]
9101

10102
#[cfg(feature = "alloc")]
11103
extern crate alloc;
@@ -48,30 +140,30 @@ mod test {
48140
#[cfg(all(target_has_atomic = "ptr", feature = "alloc"))]
49141
#[test]
50142
fn ux() {
51-
use crate::traits::{notifier::blocking::Blocking, storage::BoxedSlice};
143+
use crate::traits::{notifier::polling::Polling, storage::BoxedSlice};
52144

53-
static BBQ: BBQueue<Inline<64>, AtomicCoord, Blocking> = BBQueue::new();
145+
static BBQ: BBQueue<Inline<64>, AtomicCoord, Polling> = BBQueue::new();
54146
let _ = BBQ.stream_producer();
55147
let _ = BBQ.stream_consumer();
56148

57149
let buf2 = Inline::<64>::new();
58-
let bbq2: BBQueue<_, AtomicCoord, Blocking> = BBQueue::new_with_storage(&buf2);
150+
let bbq2: BBQueue<_, AtomicCoord, Polling> = BBQueue::new_with_storage(&buf2);
59151
let _ = bbq2.stream_producer();
60152
let _ = bbq2.stream_consumer();
61153

62154
let buf3 = BoxedSlice::new(64);
63-
let bbq3: BBQueue<_, AtomicCoord, Blocking> = BBQueue::new_with_storage(buf3);
155+
let bbq3: BBQueue<_, AtomicCoord, Polling> = BBQueue::new_with_storage(buf3);
64156
let _ = bbq3.stream_producer();
65157
let _ = bbq3.stream_consumer();
66158
}
67159

68160
#[cfg(target_has_atomic = "ptr")]
69161
#[test]
70162
fn smoke() {
71-
use crate::traits::notifier::blocking::Blocking;
163+
use crate::traits::notifier::polling::Polling;
72164
use core::ops::Deref;
73165

74-
static BBQ: BBQueue<Inline<64>, AtomicCoord, Blocking> = BBQueue::new();
166+
static BBQ: BBQueue<Inline<64>, AtomicCoord, Polling> = BBQueue::new();
75167
let prod = BBQ.stream_producer();
76168
let cons = BBQ.stream_consumer();
77169

@@ -94,10 +186,10 @@ mod test {
94186
#[cfg(target_has_atomic = "ptr")]
95187
#[test]
96188
fn smoke_framed() {
97-
use crate::traits::notifier::blocking::Blocking;
189+
use crate::traits::notifier::polling::Polling;
98190
use core::ops::Deref;
99191

100-
static BBQ: BBQueue<Inline<64>, AtomicCoord, Blocking> = BBQueue::new();
192+
static BBQ: BBQueue<Inline<64>, AtomicCoord, Polling> = BBQueue::new();
101193
let prod = BBQ.framed_producer();
102194
let cons = BBQ.framed_consumer();
103195

@@ -116,9 +208,9 @@ mod test {
116208
#[cfg(target_has_atomic = "ptr")]
117209
#[test]
118210
fn framed_misuse() {
119-
use crate::traits::notifier::blocking::Blocking;
211+
use crate::traits::notifier::polling::Polling;
120212

121-
static BBQ: BBQueue<Inline<64>, AtomicCoord, Blocking> = BBQueue::new();
213+
static BBQ: BBQueue<Inline<64>, AtomicCoord, Polling> = BBQueue::new();
122214
let prod = BBQ.stream_producer();
123215
let cons = BBQ.framed_consumer();
124216

bbq2/src/nicknames.rs

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
//!
33
//! | Storage | Coordination | Notifier | Arc? | Nickname | Source |
44
//! | :--- | :--- | :--- | :--- | :--- | :--- |
5-
//! | Inline | Critical Section | Blocking | No | Jerk | Jamaica |
6-
//! | Inline | Critical Section | Blocking | Yes | Asado | Argentina |
5+
//! | Inline | Critical Section | Polling | No | Jerk | Jamaica |
6+
//! | Inline | Critical Section | Polling | Yes | Asado | Argentina |
77
//! | Inline | Critical Section | Async | No | Memphis | USA |
88
//! | Inline | Critical Section | Async | Yes | Carolina | USA |
9-
//! | Inline | Atomic | Blocking | No | Churrasco | Brazil |
10-
//! | Inline | Atomic | Blocking | Yes | Barbacoa | Mexico |
9+
//! | Inline | Atomic | Polling | No | Churrasco | Brazil |
10+
//! | Inline | Atomic | Polling | Yes | Barbacoa | Mexico |
1111
//! | Inline | Atomic | Async | No | Texas | USA |
1212
//! | Inline | Atomic | Async | Yes | KansasCity | USA |
13-
//! | Heap | Critical Section | Blocking | No | Braai | South Africa |
14-
//! | Heap | Critical Section | Blocking | Yes | Kebab | Türkiye |
13+
//! | Heap | Critical Section | Polling | No | Braai | South Africa |
14+
//! | Heap | Critical Section | Polling | Yes | Kebab | Türkiye |
1515
//! | Heap | Critical Section | Async | No | SiuMei | Hong Kong |
1616
//! | Heap | Critical Section | Async | Yes | Satay | SE Asia |
17-
//! | Heap | Atomic | Blocking | No | YakiNiku | Japan |
18-
//! | Heap | Atomic | Blocking | Yes | GogiGui | South Korea |
17+
//! | Heap | Atomic | Polling | No | YakiNiku | Japan |
18+
//! | Heap | Atomic | Polling | Yes | GogiGui | South Korea |
1919
//! | Heap | Atomic | Async | No | Tandoori | India |
2020
//! | Heap | Atomic | Async | Yes | Lechon | Philippines |
2121
@@ -31,68 +31,68 @@ use crate::traits::coordination::cs::CsCoord;
3131
use crate::traits::storage::BoxedSlice;
3232
use crate::{
3333
queue::BBQueue,
34-
traits::{notifier::blocking::Blocking, storage::Inline},
34+
traits::{notifier::polling::Polling, storage::Inline},
3535
};
3636

37-
/// Inline Storage, Critical Section, Blocking, Borrowed
37+
/// Inline Storage, Critical Section, Polling, Borrowed
3838
#[cfg(feature = "critical-section")]
39-
pub type Jerk<const N: usize> = BBQueue<Inline<N>, CsCoord, Blocking>;
39+
pub type Jerk<const N: usize> = BBQueue<Inline<N>, CsCoord, Polling>;
4040

4141
/// Inline Storage, Critical Section, Async, Borrowed
4242
#[cfg(feature = "critical-section")]
4343
pub type Memphis<const N: usize, A> = BBQueue<Inline<N>, CsCoord, A>;
4444

45-
/// Inline Storage, Atomics, Blocking, Borrowed
45+
/// Inline Storage, Atomics, Polling, Borrowed
4646
#[cfg(target_has_atomic = "ptr")]
47-
pub type Churrasco<const N: usize> = BBQueue<Inline<N>, AtomicCoord, Blocking>;
47+
pub type Churrasco<const N: usize> = BBQueue<Inline<N>, AtomicCoord, Polling>;
4848

4949
/// Inline Storage, Atomics, Async, Borrowed
5050
#[cfg(target_has_atomic = "ptr")]
5151
pub type Texas<const N: usize, A> = BBQueue<Inline<N>, AtomicCoord, A>;
5252

53-
/// Heap Buffer, Critical Section, Blocking, Borrowed
53+
/// Heap Buffer, Critical Section, Polling, Borrowed
5454
#[cfg(all(feature = "alloc", feature = "critical-section"))]
55-
pub type Braai = BBQueue<BoxedSlice, CsCoord, Blocking>;
55+
pub type Braai = BBQueue<BoxedSlice, CsCoord, Polling>;
5656

5757
/// Heap Buffer, Critical Section, Async, Borrowed
5858
#[cfg(all(feature = "alloc", feature = "critical-section"))]
5959
pub type SiuMei<A> = BBQueue<BoxedSlice, CsCoord, A>;
6060

61-
/// Heap Buffer, Atomics, Blocking, Borrowed
61+
/// Heap Buffer, Atomics, Polling, Borrowed
6262
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
63-
pub type YakiNiku = BBQueue<BoxedSlice, AtomicCoord, Blocking>;
63+
pub type YakiNiku = BBQueue<BoxedSlice, AtomicCoord, Polling>;
6464

6565
/// Heap Buffer, Atomics, Async, Borrowed
6666
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
6767
pub type Tandoori<A> = BBQueue<BoxedSlice, AtomicCoord, A>;
6868

69-
/// Inline Storage, Critical Section, Blocking, Arc
69+
/// Inline Storage, Critical Section, Polling, Arc
7070
#[cfg(all(feature = "alloc", feature = "critical-section"))]
71-
pub type Asado<const N: usize> = ArcBBQueue<Inline<N>, CsCoord, Blocking>;
71+
pub type Asado<const N: usize> = ArcBBQueue<Inline<N>, CsCoord, Polling>;
7272

7373
/// Inline Storage, Critical Section, Async, Arc
7474
#[cfg(all(feature = "alloc", feature = "critical-section"))]
7575
pub type Carolina<const N: usize, A> = ArcBBQueue<Inline<N>, CsCoord, A>;
7676

77-
/// Inline Storage, Atomics, Blocking, Arc
77+
/// Inline Storage, Atomics, Polling, Arc
7878
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
79-
pub type Barbacoa<const N: usize> = ArcBBQueue<Inline<N>, AtomicCoord, Blocking>;
79+
pub type Barbacoa<const N: usize> = ArcBBQueue<Inline<N>, AtomicCoord, Polling>;
8080

8181
/// Inline Storage, Atomics, Async, Arc
8282
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
8383
pub type KansasCity<const N: usize, A> = ArcBBQueue<Inline<N>, AtomicCoord, A>;
8484

85-
/// Heap Buffer, Critical Section, Blocking, Arc
85+
/// Heap Buffer, Critical Section, Polling, Arc
8686
#[cfg(all(feature = "alloc", feature = "critical-section"))]
87-
pub type Kebab = ArcBBQueue<BoxedSlice, CsCoord, Blocking>;
87+
pub type Kebab = ArcBBQueue<BoxedSlice, CsCoord, Polling>;
8888

8989
/// Heap Buffer, Critical Section, Async, Arc
9090
#[cfg(all(feature = "alloc", feature = "critical-section"))]
9191
pub type Satay<A> = ArcBBQueue<BoxedSlice, CsCoord, A>;
9292

93-
/// Heap Buffer, Atomics, Blocking, Arc
93+
/// Heap Buffer, Atomics, Polling, Arc
9494
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
95-
pub type GogiGui = ArcBBQueue<BoxedSlice, AtomicCoord, Blocking>;
95+
pub type GogiGui = ArcBBQueue<BoxedSlice, AtomicCoord, Polling>;
9696

9797
/// Heap Buffer, Atomics, Async, Arc
9898
#[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]

bbq2/src/prod_cons/framed.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ where
132132
/// a smaller size may be committed. Dropping the grant without calling
133133
/// commit means that no data will be made visible to the consumer.
134134
pub fn grant(&self, sz: H) -> Result<FramedGrantW<Q, H>, WriteGrantError> {
135-
let (ptr, cap) = self.bbq.sto.ptr_len();
135+
let (ptr, cap) = unsafe { self.bbq.sto.ptr_len() };
136136
let needed = sz.into() + core::mem::size_of::<H>();
137137

138138
let offset = self.bbq.cor.grant_exact(cap, needed)?;
@@ -182,7 +182,7 @@ where
182182
///
183183
/// The returned grant must be released to free the space in the buffer.
184184
pub fn read(&self) -> Result<FramedGrantR<Q, H>, ReadGrantError> {
185-
let (ptr, _cap) = self.bbq.sto.ptr_len();
185+
let (ptr, _cap) = unsafe { self.bbq.sto.ptr_len() };
186186
let (offset, grant_len) = self.bbq.cor.read()?;
187187

188188
// Calculate the size so we can figure out where the body
@@ -230,6 +230,12 @@ where
230230
Q::Notifier: AsyncNotifier,
231231
H: LenHeader,
232232
{
233+
/// Wait for a single frame
234+
///
235+
/// The FramedConsumer has no control over the size of the read grant,
236+
/// we see whatever size was written by the FramedProducer.
237+
///
238+
/// The returned grant must be released to free the space in the buffer.
233239
pub async fn wait_read(&self) -> FramedGrantR<Q, H> {
234240
self.bbq.not.wait_for_not_empty(|| self.read().ok()).await
235241
}
@@ -247,7 +253,7 @@ where
247253
/// If `used` is greater than the `sz` used to create this grant, the
248254
/// amount will be clamped to `sz`.
249255
pub fn commit(self, used: H) {
250-
let (_ptr, cap) = self.bbq.sto.ptr_len();
256+
let (_ptr, cap) = unsafe { self.bbq.sto.ptr_len() };
251257
let hdrlen: usize = const { core::mem::size_of::<H>() };
252258
let grant_len = hdrlen + self.hdr.into();
253259
let clamp_hdr = self.hdr.min(used);
@@ -313,7 +319,7 @@ where
313319
{
314320
fn drop(&mut self) {
315321
// Default drop performs an "abort"
316-
let (_ptr, cap) = self.bbq.sto.ptr_len();
322+
let (_ptr, cap) = unsafe { self.bbq.sto.ptr_len() };
317323
let hdrlen: usize = const { core::mem::size_of::<H>() };
318324
let grant_len = hdrlen + self.hdr.into();
319325
self.bbq.cor.commit_inner(cap, grant_len, 0);

0 commit comments

Comments
 (0)