From 10017597bcb03ff69defe7608ae516fe86538929 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 23 Dec 2022 19:01:06 +0100 Subject: [PATCH] Use `portable-atomic` instead of `atomic-polyfill`. --- .github/workflows/build.yml | 4 ++++ CHANGELOG.md | 4 ++-- Cargo.toml | 13 ++++++---- build.rs | 48 ++++++++++++++++++------------------- src/mpmc.rs | 34 ++++++++++++-------------- src/spsc.rs | 19 ++++++++++----- 6 files changed, 66 insertions(+), 56 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8793ed2fbf..7c8fa19235 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -126,6 +126,10 @@ jobs: target: ${{ matrix.target }} override: true + - name: Export variables + run: | + echo RUSTFLAGS="--cfg=portable_atomic_unsafe_assume_single_core" >> $GITHUB_ENV + - name: cargo check uses: actions-rs/cargo@v1 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index d2cd3a651e..98ae8b54d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,8 +23,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [breaking-change] changed the target support of memory pool API to only support 32-bit x86 and a subset of ARM targets. See the module level documentation of the `pool` module for details -- [breaking-change] this crate now depends on `atomic-polyfill` v1.0.1, meaning that targets that - require a polyfill need a `critical-section` **v1.x.x** implementation. +- [breaking-change] this crate now uses `portable-atomic` v0.3 instead of `atomic-polyfill` for emulating + CAS instructions on targets where they're not natively available. ### Fixed diff --git a/Cargo.toml b/Cargo.toml index 1292800e13..fa564d2ae4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ version = "0.8.0" [features] default = ["cas"] -cas = ["atomic-polyfill"] +cas = ["portable-atomic"] ufmt-impl = ["ufmt-write"] # only for tests __trybuild = [] @@ -26,16 +26,19 @@ mpmc_large = [] defmt-impl = ["defmt"] [target.thumbv6m-none-eabi.dependencies] -atomic-polyfill = { version = "1.0.1", optional = true } +portable-atomic = { version = "0.3.18", optional = true } [target.riscv32i-unknown-none-elf.dependencies] -atomic-polyfill = { version = "1.0.1" } +portable-atomic = { version = "0.3.18" } [target.riscv32imc-unknown-none-elf.dependencies] -atomic-polyfill = { version = "1.0.1" } +portable-atomic = { version = "0.3.18" } + +[target.msp430-none-elf.dependencies] +portable-atomic = { version = "0.3.18" } [target.'cfg(target_arch = "avr")'.dependencies] -atomic-polyfill = { version = "1.0.1", optional = true } +portable-atomic = { version = "0.3.18", optional = true } [dependencies] hash32 = "0.3.0" diff --git a/build.rs b/build.rs index d787a26691..38818931b3 100644 --- a/build.rs +++ b/build.rs @@ -31,8 +31,14 @@ fn main() -> Result<(), Box> { let is_avr = env::var("CARGO_CFG_TARGET_ARCH").as_deref() == Ok("avr"); + // Set some cfg's depending on the target. + // - has_atomics: atomic load/store is available (either natively or through portable-atomic) + // - has_cas: atomic CAS is available (either natively or through portable-atomic) + // - use_portable_atomic: Use portable-atomic for all atomics (load/store and CAS). + // - use_portable_atomic_cas: Use portable-atomic for CAS atomic operations. Load/store can keep using core::sync:atomic. + // built-in targets with no atomic / CAS support as of nightly-2022-01-13 - // AND not supported by the atomic-polyfill crate + // AND not supported by the portable-atomic crate // see the `no-atomics.sh` / `no-cas.sh` script sitting next to this file if is_avr { // lacks cas @@ -41,11 +47,11 @@ fn main() -> Result<(), Box> { "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 + // | "msp430-none-elf" // supported by portable-atomic + // | "riscv32i-unknown-none-elf" // supported by portable-atomic + // | "riscv32imc-unknown-none-elf" // supported by portable-atomic + // | "thumbv4t-none-eabi" // supported by portable-atomic + // | "thumbv6m-none-eabi" // supported by portable-atomic => {} _ => { @@ -57,32 +63,26 @@ fn main() -> Result<(), Box> { if is_avr { // lacks atomics } else { - match &target[..] { - "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 + // Let the code know if it should use portable-atomic or not, for either + // only CAS, or for all atomics. if is_avr { - println!("cargo:rustc-cfg=full_atomic_polyfill"); - println!("cargo:rustc-cfg=cas_atomic_polyfill"); + println!("cargo:rustc-cfg=use_portable_atomic"); + println!("cargo:rustc-cfg=use_portable_atomic_cas"); } else { match &target[..] { - "riscv32i-unknown-none-elf" | "riscv32imc-unknown-none-elf" => { - println!("cargo:rustc-cfg=full_atomic_polyfill"); - println!("cargo:rustc-cfg=cas_atomic_polyfill"); + "riscv32i-unknown-none-elf" + | "riscv32imc-unknown-none-elf" + | "thumbv4t-none-eabi" + | "msp430-none-elf" => { + println!("cargo:rustc-cfg=use_portable_atomic"); + println!("cargo:rustc-cfg=use_portable_atomic_cas"); } "thumbv6m-none-eabi" => { - println!("cargo:rustc-cfg=cas_atomic_polyfill"); + println!("cargo:rustc-cfg=use_portable_atomic_cas"); } _ => {} } diff --git a/src/mpmc.rs b/src/mpmc.rs index 99191c6ebf..53c515ea09 100644 --- a/src/mpmc.rs +++ b/src/mpmc.rs @@ -1,8 +1,7 @@ //! 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 and are not -//! emulated by the [`atomic_polyfill`](https://crates.io/crates/atomic-polyfill) crate (e.g., -//! MSP430). +//! NOTE: This module requires atomic CAS operations. On targets where they're not natively available, +//! they are emulated by the [`portable-atomic`](https://crates.io/crates/portable-atomic) crate. //! //! # Example //! @@ -77,10 +76,9 @@ //! //! This module requires CAS atomic instructions which are not available on all architectures //! (e.g. ARMv6-M (`thumbv6m-none-eabi`) and MSP430 (`msp430-none-elf`)). These atomics can be -//! emulated however with [`atomic_polyfill`](https://crates.io/crates/atomic-polyfill), which is +//! emulated however with [`portable-atomic`](https://crates.io/crates/portable-atomic), 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`](https://crates.io/crates/atomic-polyfill). +//! targets. //! //! # References //! @@ -90,19 +88,17 @@ use core::{cell::UnsafeCell, mem::MaybeUninit}; -#[cfg(all(feature = "mpmc_large", not(cas_atomic_polyfill)))] -type AtomicTargetSize = core::sync::atomic::AtomicUsize; -#[cfg(all(feature = "mpmc_large", cas_atomic_polyfill))] -type AtomicTargetSize = atomic_polyfill::AtomicUsize; -#[cfg(all(not(feature = "mpmc_large"), not(cas_atomic_polyfill)))] -type AtomicTargetSize = core::sync::atomic::AtomicU8; -#[cfg(all(not(feature = "mpmc_large"), cas_atomic_polyfill))] -type AtomicTargetSize = atomic_polyfill::AtomicU8; - -#[cfg(not(cas_atomic_polyfill))] -type Ordering = core::sync::atomic::Ordering; -#[cfg(cas_atomic_polyfill)] -type Ordering = atomic_polyfill::Ordering; +#[cfg(not(use_portable_atomic_cas))] +use core::sync::atomic; +#[cfg(use_portable_atomic_cas)] +use portable_atomic as atomic; + +use atomic::Ordering; + +#[cfg(feature = "mpmc_large")] +type AtomicTargetSize = atomic::AtomicUsize; +#[cfg(not(feature = "mpmc_large"))] +type AtomicTargetSize = atomic::AtomicU8; #[cfg(feature = "mpmc_large")] type IntSize = usize; diff --git a/src/spsc.rs b/src/spsc.rs index 1846db681e..8cf4493df1 100644 --- a/src/spsc.rs +++ b/src/spsc.rs @@ -2,8 +2,13 @@ //! //! Implementation based on //! -//! NOTE: This module is not available on targets that do *not* support atomic loads and are not -//! supported by [`atomic_polyfill`](https://crates.io/crates/atomic-polyfill). (e.g., MSP430). +//! # Portability +//! +//! This module requires CAS atomic instructions which are not available on all architectures +//! (e.g. ARMv6-M (`thumbv6m-none-eabi`) and MSP430 (`msp430-none-elf`)). These atomics can be +//! emulated however with [`portable-atomic`](https://crates.io/crates/portable-atomic), which is +//! enabled with the `cas` feature and is enabled by default for `thumbv6m-none-eabi` and `riscv32` +//! targets. //! //! # Examples //! @@ -91,10 +96,12 @@ use core::{cell::UnsafeCell, fmt, hash, mem::MaybeUninit, ptr}; -#[cfg(full_atomic_polyfill)] -use atomic_polyfill::{AtomicUsize, Ordering}; -#[cfg(not(full_atomic_polyfill))] -use core::sync::atomic::{AtomicUsize, Ordering}; +#[cfg(not(use_portable_atomic))] +use core::sync::atomic; +#[cfg(use_portable_atomic)] +use portable_atomic as atomic; + +use atomic::{AtomicUsize, Ordering}; /// A statically allocated single producer single consumer queue with a capacity of `N - 1` elements ///