Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use portable atomic, remove explicit/redundant feature declaration & move to edition 2021 #103

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions .github/workflows/doctests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,10 @@ name: Documentation Tests
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- features: thumbv6
nodefault: "--no-default-features"
- features: ""
nodefault: ""

steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions-rs/cargo@v1
with:
command: test
args: ${{ matrix.nodefault }} --features=${{ matrix.features }} --manifest-path core/Cargo.toml
args: --manifest-path core/Cargo.toml
2 changes: 1 addition & 1 deletion .github/workflows/embedded-builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
include:
- features: ""
target: thumbv7em-none-eabihf
- feature: thumbv6
- feature: portable-atomic/critical-section
target: thumbv6m-none-eabi

steps:
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[workspace]
resolver = "2"
members = ["bbqtest", "core"]
2 changes: 1 addition & 1 deletion bbqtest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "bbqtest"
version = "0.1.0"
authors = ["James Munns <james.munns@ferrous-systems.com>"]
edition = "2018"
edition = "2021"
license = "MIT OR Apache-2.0"

[dependencies]
Expand Down
13 changes: 3 additions & 10 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.5.1"
description = "A SPSC, lockless, no_std, thread safe, queue, based on BipBuffers"
repository = "https://github.com/jamesmunns/bbqueue"
authors = ["James Munns <james.munns@ferrous-systems.com>"]
edition = "2018"
edition = "2021"
readme = "../README.md"

categories = [
Expand All @@ -15,15 +15,8 @@ categories = [
license = "MIT OR Apache-2.0"

[dependencies]
cortex-m = { version = "0.6.0", optional = true }

[dependencies.defmt]
version = "0.3.0"
optional = true

[features]
thumbv6 = ["cortex-m"]
defmt_0_3 = ["defmt"]
portable-atomic = { version = "1.5.1", default-features = false, features = ["require-cas"] }
defmt = { version = "0.3.0", optional = true }

[package.metadata.docs.rs]
all-features = true
110 changes: 11 additions & 99 deletions core/src/bbbuffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ use core::{
ptr::NonNull,
result::Result as CoreResult,
slice::from_raw_parts_mut,
sync::atomic::{
AtomicBool, AtomicUsize,
Ordering::{AcqRel, Acquire, Release},
},
sync::atomic::Ordering::{AcqRel, Acquire, Release},
};
use portable_atomic::{AtomicBool, AtomicUsize};

#[derive(Debug)]
/// A backing structure for a BBQueue. Can be used to create either
/// a BBQueue or a split Producer/Consumer pair
Expand Down Expand Up @@ -63,9 +62,6 @@ impl<'a, const N: usize> BBBuffer<N> {
/// is placed at `static` scope within the `.bss` region, the explicit initialization
/// will be elided (as it is already performed as part of memory initialization)
///
/// NOTE: If the `thumbv6` feature is selected, this function takes a short critical section
/// while splitting.
///
/// ```rust
/// # // bbqueue test shim!
/// # fn bbqtest() {
Expand All @@ -81,12 +77,11 @@ impl<'a, const N: usize> BBBuffer<N> {
/// # }
/// #
/// # fn main() {
/// # #[cfg(not(feature = "thumbv6"))]
/// # bbqtest();
/// # }
/// ```
pub fn try_split(&'a self) -> Result<(Producer<'a, N>, Consumer<'a, N>)> {
if atomic::swap(&self.already_split, true, AcqRel) {
if self.already_split.swap(true, AcqRel) {
return Err(Error::AlreadySplit);
}

Expand Down Expand Up @@ -122,9 +117,6 @@ impl<'a, const N: usize> BBBuffer<N> {
/// of the buffer. This is necessary to prevent undefined behavior. If the buffer
/// is placed at `static` scope within the `.bss` region, the explicit initialization
/// will be elided (as it is already performed as part of memory initialization)
///
/// NOTE: If the `thumbv6` feature is selected, this function takes a short critical
/// section while splitting.
pub fn try_split_framed(&'a self) -> Result<(FrameProducer<'a, N>, FrameConsumer<'a, N>)> {
let (producer, consumer) = self.try_split()?;
Ok((FrameProducer { producer }, FrameConsumer { consumer }))
Expand Down Expand Up @@ -159,7 +151,6 @@ impl<'a, const N: usize> BBBuffer<N> {
/// # }
/// #
/// # fn main() {
/// # #[cfg(not(feature = "thumbv6"))]
/// # bbqtest();
/// # }
/// ```
Expand Down Expand Up @@ -345,14 +336,13 @@ impl<'a, const N: usize> Producer<'a, N> {
/// # }
/// #
/// # fn main() {
/// # #[cfg(not(feature = "thumbv6"))]
/// # bbqtest();
/// # }
/// ```
pub fn grant_exact(&mut self, sz: usize) -> Result<GrantW<'a, N>> {
let inner = unsafe { &self.bbq.as_ref() };

if atomic::swap(&inner.write_in_progress, true, AcqRel) {
if inner.write_in_progress.swap(true, AcqRel) {
return Err(Error::GrantInProgress);
}

Expand Down Expand Up @@ -443,14 +433,13 @@ impl<'a, const N: usize> Producer<'a, N> {
/// # }
/// #
/// # fn main() {
/// # #[cfg(not(feature = "thumbv6"))]
/// # bbqtest();
/// # }
/// ```
pub fn grant_max_remaining(&mut self, mut sz: usize) -> Result<GrantW<'a, N>> {
let inner = unsafe { &self.bbq.as_ref() };

if atomic::swap(&inner.write_in_progress, true, AcqRel) {
if inner.write_in_progress.swap(true, AcqRel) {
return Err(Error::GrantInProgress);
}

Expand Down Expand Up @@ -548,14 +537,13 @@ impl<'a, const N: usize> Consumer<'a, N> {
/// # }
/// #
/// # fn main() {
/// # #[cfg(not(feature = "thumbv6"))]
/// # bbqtest();
/// # }
/// ```
pub fn read(&mut self) -> Result<GrantR<'a, N>> {
let inner = unsafe { &self.bbq.as_ref() };

if atomic::swap(&inner.read_in_progress, true, AcqRel) {
if inner.read_in_progress.swap(true, AcqRel) {
return Err(Error::GrantInProgress);
}

Expand Down Expand Up @@ -607,7 +595,7 @@ impl<'a, const N: usize> Consumer<'a, N> {
pub fn split_read(&mut self) -> Result<SplitGrantR<'a, N>> {
let inner = unsafe { &self.bbq.as_ref() };

if atomic::swap(&inner.read_in_progress, true, AcqRel) {
if inner.read_in_progress.swap(true, AcqRel) {
return Err(Error::GrantInProgress);
}

Expand Down Expand Up @@ -674,7 +662,6 @@ impl<const N: usize> BBBuffer<N> {
/// # }
/// #
/// # fn main() {
/// # #[cfg(not(feature = "thumbv6"))]
/// # bbqtest();
/// # }
/// ```
Expand All @@ -690,9 +677,6 @@ impl<const N: usize> BBBuffer<N> {
/// the contents, or by setting a the number of bytes to
/// automatically be committed with `to_commit()`, then no bytes
/// will be comitted for writing.
///
/// If the `thumbv6` feature is selected, dropping the grant
/// without committing it takes a short critical section,
#[derive(Debug, PartialEq)]
pub struct GrantW<'a, const N: usize> {
pub(crate) buf: &'a mut [u8],
Expand All @@ -710,10 +694,6 @@ unsafe impl<'a, const N: usize> Send for GrantW<'a, N> {}
/// the contents, or by setting the number of bytes to automatically
/// be released with `to_release()`, then no bytes will be released
/// as read.
///
///
/// If the `thumbv6` feature is selected, dropping the grant
/// without releasing it takes a short critical section,
#[derive(Debug, PartialEq)]
pub struct GrantR<'a, const N: usize> {
pub(crate) buf: &'a mut [u8],
Expand Down Expand Up @@ -743,9 +723,6 @@ impl<'a, const N: usize> GrantW<'a, N> {
///
/// If `used` is larger than the given grant, the maximum amount will
/// be commited
///
/// NOTE: If the `thumbv6` feature is selected, this function takes a short critical
/// section while committing.
pub fn commit(mut self, used: usize) {
self.commit_inner(used);
forget(self);
Expand All @@ -770,7 +747,6 @@ impl<'a, const N: usize> GrantW<'a, N> {
/// # }
/// #
/// # fn main() {
/// # #[cfg(not(feature = "thumbv6"))]
/// # bbqtest();
/// # }
/// ```
Expand Down Expand Up @@ -814,7 +790,7 @@ impl<'a, const N: usize> GrantW<'a, N> {
let used = min(len, used);

let write = inner.write.load(Acquire);
atomic::fetch_sub(&inner.reserve, len - used, AcqRel);
inner.reserve.fetch_sub(len - used, AcqRel);

let max = N;
let last = inner.last.load(Acquire);
Expand Down Expand Up @@ -860,9 +836,6 @@ impl<'a, const N: usize> GrantR<'a, N> {
///
/// If `used` is larger than the given grant, the full grant will
/// be released.
///
/// NOTE: If the `thumbv6` feature is selected, this function takes a short critical
/// section while releasing.
pub fn release(mut self, used: usize) {
// Saturate the grant release
let used = min(self.buf.len(), used);
Expand Down Expand Up @@ -903,7 +876,6 @@ impl<'a, const N: usize> GrantR<'a, N> {
/// # }
/// #
/// # fn main() {
/// # #[cfg(not(feature = "thumbv6"))]
/// # bbqtest();
/// # }
/// ```
Expand Down Expand Up @@ -951,7 +923,7 @@ impl<'a, const N: usize> GrantR<'a, N> {
debug_assert!(used <= self.buf.len());

// This should be fine, purely incrementing
let _ = atomic::fetch_add(&inner.read, used, Release);
let _ = inner.read.fetch_add(used, Release);

inner.read_in_progress.store(false, Release);
}
Expand All @@ -968,9 +940,6 @@ impl<'a, const N: usize> SplitGrantR<'a, N> {
///
/// If `used` is larger than the given grant, the full grant will
/// be released.
///
/// NOTE: If the `thumbv6` feature is selected, this function takes a short critical
/// section while releasing.
pub fn release(mut self, used: usize) {
// Saturate the grant release
let used = min(self.combined_len(), used);
Expand Down Expand Up @@ -1004,7 +973,6 @@ impl<'a, const N: usize> SplitGrantR<'a, N> {
/// # }
/// #
/// # fn main() {
/// # #[cfg(not(feature = "thumbv6"))]
/// # bbqtest();
/// # }
/// ```
Expand Down Expand Up @@ -1036,7 +1004,7 @@ impl<'a, const N: usize> SplitGrantR<'a, N> {

if used <= self.buf1.len() {
// This should be fine, purely incrementing
let _ = atomic::fetch_add(&inner.read, used, Release);
let _ = inner.read.fetch_add(used, Release);
} else {
// Also release parts of the second buffer
inner.read.store(used - self.buf1.len(), Release);
Expand Down Expand Up @@ -1101,59 +1069,3 @@ impl<'a, const N: usize> DerefMut for GrantR<'a, N> {
self.buf
}
}

#[cfg(feature = "thumbv6")]
mod atomic {
use core::sync::atomic::{
AtomicBool, AtomicUsize,
Ordering::{self, Acquire, Release},
};
use cortex_m::interrupt::free;

#[inline(always)]
pub fn fetch_add(atomic: &AtomicUsize, val: usize, _order: Ordering) -> usize {
free(|_| {
let prev = atomic.load(Acquire);
atomic.store(prev.wrapping_add(val), Release);
prev
})
}

#[inline(always)]
pub fn fetch_sub(atomic: &AtomicUsize, val: usize, _order: Ordering) -> usize {
free(|_| {
let prev = atomic.load(Acquire);
atomic.store(prev.wrapping_sub(val), Release);
prev
})
}

#[inline(always)]
pub fn swap(atomic: &AtomicBool, val: bool, _order: Ordering) -> bool {
free(|_| {
let prev = atomic.load(Acquire);
atomic.store(val, Release);
prev
})
}
}

#[cfg(not(feature = "thumbv6"))]
mod atomic {
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

#[inline(always)]
pub fn fetch_add(atomic: &AtomicUsize, val: usize, order: Ordering) -> usize {
atomic.fetch_add(val, order)
}

#[inline(always)]
pub fn fetch_sub(atomic: &AtomicUsize, val: usize, order: Ordering) -> usize {
atomic.fetch_sub(val, order)
}

#[inline(always)]
pub fn swap(atomic: &AtomicBool, val: bool, order: Ordering) -> bool {
atomic.swap(val, order)
}
}
1 change: 0 additions & 1 deletion core/src/framed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
//! # }
//! #
//! # fn main() {
//! # #[cfg(not(feature = "thumbv6"))]
//! # bbqtest();
//! # }
//! ```
Expand Down
13 changes: 1 addition & 12 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,6 @@
//! 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.

#![cfg_attr(not(feature = "std"), no_std)]
#![deny(missing_docs)]
Expand All @@ -112,7 +101,7 @@ pub type Result<T> = CoreResult<T, Error>;

/// Error type used by the `BBQueue` interfaces
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[cfg_attr(feature = "defmt_0_3", derive(defmt::Format))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
/// The buffer does not contain sufficient size for the requested action
InsufficientSize,
Expand Down
Loading