Merge pull request #265 from TDHolmes/cas-fixup

Add cas support for risc-v via atomic-polyfill and fix mpmc/pool documentation
This commit is contained in:
Emil Fresk 2022-01-19 14:59:12 +01:00 committed by GitHub
commit 70cecc4147
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 73 additions and 28 deletions

View File

@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added `OldestOrdered` iterator for `HistoryBuffer` - Added `OldestOrdered` iterator for `HistoryBuffer`
### Changed
- `atomic-polyfill` is now enabled and used for `cas` atomic emulation on `riscv` targets
## [v0.7.9] - 2021-12-16 ## [v0.7.9] - 2021-12-16
### Fixed ### Fixed

View File

@ -33,6 +33,12 @@ scoped_threadpool = "0.1.8"
[target.thumbv6m-none-eabi.dependencies] [target.thumbv6m-none-eabi.dependencies]
atomic-polyfill = { version = "0.1.2", optional = true } atomic-polyfill = { version = "0.1.2", optional = true }
[target.riscv32i-unknown-none-elf.dependencies]
atomic-polyfill = { version = "0.1.4", optional = true }
[target.riscv32imc-unknown-none-elf.dependencies]
atomic-polyfill = { version = "0.1.4", optional = true }
[dependencies] [dependencies]
hash32 = "0.2.1" hash32 = "0.2.1"
@ -58,3 +64,6 @@ version = "0.1"
[dependencies.defmt] [dependencies.defmt]
version = ">=0.2.0,<0.4" version = ">=0.2.0,<0.4"
optional = true optional = true
[package.metadata.docs.rs]
all-features = true

View File

@ -21,10 +21,19 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("cargo:rustc-cfg=armv7a"); println!("cargo:rustc-cfg=armv7a");
} }
// built-in targets with no atomic / CAS support as of nightly-2019-12-17 // built-in targets with no atomic / CAS support as of nightly-2022-01-13
// AND not supported by the atomic-polyfill crate
// see the `no-atomics.sh` / `no-cas.sh` script sitting next to this file // see the `no-atomics.sh` / `no-cas.sh` script sitting next to this file
match &target[..] { match &target[..] {
"msp430-none-elf" | "riscv32i-unknown-none-elf" | "riscv32imc-unknown-none-elf" => {} "avr-unknown-gnu-atmega328"
| "bpfeb-unknown-none"
| "bpfel-unknown-none"
| "msp430-none-elf"
// | "riscv32i-unknown-none-elf" // supported by atomic-polyfill
// | "riscv32imc-unknown-none-elf" // supported by atomic-polyfill
| "thumbv4t-none-eabi"
// | "thumbv6m-none-eabi" // supported by atomic-polyfill
=> {}
_ => { _ => {
println!("cargo:rustc-cfg=has_cas"); println!("cargo:rustc-cfg=has_cas");
@ -32,12 +41,30 @@ fn main() -> Result<(), Box<dyn Error>> {
}; };
match &target[..] { match &target[..] {
"msp430-none-elf" | "riscv32i-unknown-none-elf" | "riscv32imc-unknown-none-elf" => {} "avr-unknown-gnu-atmega328"
| "msp430-none-elf"
// | "riscv32i-unknown-none-elf" // supported by atomic-polyfill
// | "riscv32imc-unknown-none-elf" // supported by atomic-polyfill
=> {}
_ => { _ => {
println!("cargo:rustc-cfg=has_atomics"); println!("cargo:rustc-cfg=has_atomics");
} }
}; };
// Let the code know if it should use atomic-polyfill or not, and what aspects
// of polyfill it requires
match &target[..] {
"riscv32i-unknown-none-elf" | "riscv32imc-unknown-none-elf" => {
println!("cargo:rustc-cfg=full_atomic_polyfill");
println!("cargo:rustc-cfg=cas_atomic_polyfill");
}
"thumbv6m-none-eabi" => {
println!("cargo:rustc-cfg=cas_atomic_polyfill");
}
_ => {}
}
Ok(()) Ok(())
} }

View File

@ -1,6 +1,7 @@
//! A fixed capacity Multiple-Producer Multiple-Consumer (MPMC) lock-free queue //! A fixed capacity Multiple-Producer Multiple-Consumer (MPMC) lock-free queue
//! //!
//! NOTE: This module is not available on targets that do *not* support CAS operations, e.g. ARMv6-M //! NOTE: This module is not available on targets that do *not* support CAS operations and are not
//! emulated by the [`atomic_polyfill`] crate (e.g., MSP430).
//! //!
//! # Example //! # Example
//! //!
@ -73,8 +74,10 @@
//! //!
//! # Portability //! # Portability
//! //!
//! This module is not exposed to architectures that lack the instructions to implement CAS loops. //! This module requires CAS atomic instructions which are not available on all architectures
//! Those architectures include ARMv6-M (`thumbv6m-none-eabi`) and MSP430 (`msp430-none-elf`). //! (e.g. ARMv6-M (`thumbv6m-none-eabi`) and MSP430 (`msp430-none-elf`)). These atomics can be emulated
//! however with [`atomic_polyfill`], which is enabled with the `cas` feature and is enabled by default
//! for `thumbv6m-none-eabi` and `riscv32` targets. MSP430 is currently not supported by [`atomic_polyfill`].
//! //!
//! # References //! # References
//! //!
@ -84,18 +87,18 @@
use core::{cell::UnsafeCell, mem::MaybeUninit}; use core::{cell::UnsafeCell, mem::MaybeUninit};
#[cfg(all(feature = "mpmc_large", not(armv6m)))] #[cfg(all(feature = "mpmc_large", not(cas_atomic_polyfill)))]
type AtomicTargetSize = core::sync::atomic::AtomicUsize; type AtomicTargetSize = core::sync::atomic::AtomicUsize;
#[cfg(all(feature = "mpmc_large", armv6m))] #[cfg(all(feature = "mpmc_large", cas_atomic_polyfill))]
type AtomicTargetSize = atomic_polyfill::AtomicUsize; type AtomicTargetSize = atomic_polyfill::AtomicUsize;
#[cfg(all(not(feature = "mpmc_large"), not(armv6m)))] #[cfg(all(not(feature = "mpmc_large"), not(cas_atomic_polyfill)))]
type AtomicTargetSize = core::sync::atomic::AtomicU8; type AtomicTargetSize = core::sync::atomic::AtomicU8;
#[cfg(all(not(feature = "mpmc_large"), armv6m))] #[cfg(all(not(feature = "mpmc_large"), cas_atomic_polyfill))]
type AtomicTargetSize = atomic_polyfill::AtomicU8; type AtomicTargetSize = atomic_polyfill::AtomicU8;
#[cfg(not(armv6m))] #[cfg(not(cas_atomic_polyfill))]
type Ordering = core::sync::atomic::Ordering; type Ordering = core::sync::atomic::Ordering;
#[cfg(armv6m)] #[cfg(cas_atomic_polyfill)]
type Ordering = atomic_polyfill::Ordering; type Ordering = atomic_polyfill::Ordering;
#[cfg(feature = "mpmc_large")] #[cfg(feature = "mpmc_large")]

View File

@ -3,10 +3,10 @@
pub use core::ptr::NonNull as Ptr; pub use core::ptr::NonNull as Ptr;
use core::{cell::UnsafeCell, ptr}; use core::{cell::UnsafeCell, ptr};
#[cfg(armv6m)] #[cfg(cas_atomic_polyfill)]
use atomic_polyfill::{AtomicPtr, Ordering}; use atomic_polyfill::{AtomicPtr, Ordering};
#[cfg(not(armv6m))] #[cfg(not(cas_atomic_polyfill))]
use core::sync::atomic::{AtomicPtr, Ordering}; use core::sync::atomic::{AtomicPtr, Ordering};
/// Unfortunate implementation detail required to use the /// Unfortunate implementation detail required to use the

View File

@ -1,6 +1,7 @@
//! A heap-less, interrupt-safe, lock-free memory pool (\*) //! A heap-less, interrupt-safe, lock-free memory pool (\*)
//! //!
//! NOTE: This module is not available on targets that do *not* support CAS operations, e.g. ARMv6-M //! NOTE: This module is not available on targets that do *not* support CAS operations and are not
//! emulated by the [`atomic_polyfill`] crate (e.g., MSP430).
//! //!
//! (\*) Currently, the implementation is only lock-free *and* `Sync` on ARMv6, ARMv7-{A,R,M} & ARMv8-M //! (\*) Currently, the implementation is only lock-free *and* `Sync` on ARMv6, ARMv7-{A,R,M} & ARMv8-M
//! devices //! devices
@ -59,8 +60,10 @@
//! on the target architecture (see section on ['Soundness'](#soundness) for more information). For //! on the target architecture (see section on ['Soundness'](#soundness) for more information). For
//! this reason, `Pool` only implements `Sync` when compiling for some ARM cores. //! this reason, `Pool` only implements `Sync` when compiling for some ARM cores.
//! //!
//! Also note that ARMv6-M architecture lacks the primitives for CAS loops so this module does *not* //! This module requires CAS atomic instructions which are not available on all architectures
//! exist for `thumbv6m-none-eabi`. //! (e.g. ARMv6-M (`thumbv6m-none-eabi`) and MSP430 (`msp430-none-elf`)). These atomics can be emulated
//! however with [`atomic_polyfill`], which is enabled with the `cas` feature and is enabled by default
//! for `thumbv6m-none-eabi` and `riscv32` targets. MSP430 is currently not supported by [`atomic_polyfill`].
//! //!
//! # Soundness //! # Soundness
//! //!

View File

@ -81,10 +81,10 @@ use core::{
sync::atomic, sync::atomic,
}; };
#[cfg(armv6m)] #[cfg(cas_atomic_polyfill)]
use atomic_polyfill::{AtomicUsize, Ordering}; use atomic_polyfill::{AtomicUsize, Ordering};
#[cfg(not(armv6m))] #[cfg(not(cas_atomic_polyfill))]
use core::sync::atomic::{AtomicUsize, Ordering}; use core::sync::atomic::{AtomicUsize, Ordering};
use crate::pool::{self, stack::Ptr, Node}; use crate::pool::{self, stack::Ptr, Node};

View File

@ -2,8 +2,8 @@
//! //!
//! Implementation based on <https://www.codeproject.com/Articles/43510/Lock-Free-Single-Producer-Single-Consumer-Circular> //! Implementation based on <https://www.codeproject.com/Articles/43510/Lock-Free-Single-Producer-Single-Consumer-Circular>
//! //!
//! NOTE: This module is not available on targets that do *not* support atomic loads, e.g. RISC-V //! NOTE: This module is not available on targets that do *not* support atomic loads and are not
//! cores w/o the A (Atomic) extension //! supported by [`atomic_polyfill`]. (e.g., MSP430).
//! //!
//! # Examples //! # Examples
//! //!
@ -84,13 +84,12 @@
//! - The numbers reported correspond to the successful path (i.e. `Some` is returned by `dequeue` //! - The numbers reported correspond to the successful path (i.e. `Some` is returned by `dequeue`
//! and `Ok` is returned by `enqueue`). //! and `Ok` is returned by `enqueue`).
use core::{ use core::{cell::UnsafeCell, fmt, hash, mem::MaybeUninit, ptr};
cell::UnsafeCell,
fmt, hash, #[cfg(full_atomic_polyfill)]
mem::MaybeUninit, use atomic_polyfill::{AtomicUsize, Ordering};
ptr, #[cfg(not(full_atomic_polyfill))]
sync::atomic::{AtomicUsize, Ordering}, use core::sync::atomic::{AtomicUsize, Ordering};
};
/// A statically allocated single producer single consumer queue with a capacity of `N - 1` elements /// A statically allocated single producer single consumer queue with a capacity of `N - 1` elements
/// ///