mirror of
https://github.com/rust-embedded/heapless.git
synced 2025-09-26 20:10:24 +00:00
Simplify atomic availability detection.
- `cfg(target_has_atomic)` is stable now, use that. - Hardcode in `build.rs` the list of targets with load/store but no CAS, since `cfg(target_has_atomic_load_store)` is not stable yet. - Do not try to autodetect whether `portable-atomic` is needed or not, just let the user control it directly. If the user doesn't explicitly enable `portable-atomic` and native atomics are unavailable, the features requiring it will be missing.
This commit is contained in:
parent
db324a3ae0
commit
f58e509664
22
.github/workflows/build.yml
vendored
22
.github/workflows/build.yml
vendored
@ -80,13 +80,6 @@ jobs:
|
||||
- thumbv7m-none-eabi
|
||||
- thumbv8m.base-none-eabi
|
||||
- thumbv8m.main-none-eabi
|
||||
toolchain:
|
||||
- stable
|
||||
- nightly
|
||||
features:
|
||||
- ""
|
||||
- "cas,portable-atomic/critical-section"
|
||||
- "serde"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@ -113,14 +106,17 @@ jobs:
|
||||
${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
|
||||
${{ runner.OS }}-build-
|
||||
|
||||
- name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }})
|
||||
- name: Install Rust with target (${{ matrix.target }})
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
toolchain: stable
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: cargo check
|
||||
run: cargo check --target=${{ matrix.target }} --no-default-features --features=${{ matrix.features }}
|
||||
run: |
|
||||
cargo check --target=${{ matrix.target }}
|
||||
cargo check --target=${{ matrix.target }} --features="portable-atomic-critical-section"
|
||||
cargo check --target=${{ matrix.target }} --features="ufmt serde defmt-03 mpmc_large"
|
||||
|
||||
doc:
|
||||
name: doc
|
||||
@ -130,10 +126,6 @@ jobs:
|
||||
target:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- thumbv7m-none-eabi
|
||||
features:
|
||||
- ""
|
||||
- "cas"
|
||||
- "serde"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@ -166,7 +158,7 @@ jobs:
|
||||
targets: ${{ matrix.target }}
|
||||
|
||||
- name: cargo doc
|
||||
run: cargo doc --target=${{ matrix.target }} --no-default-features --features=${{ matrix.features }}
|
||||
run: cargo doc --target=${{ matrix.target }} --features="ufmt serde defmt-03 mpmc_large portable-atomic-critical-section"
|
||||
|
||||
# Run cpass tests
|
||||
testcpass:
|
||||
|
40
CHANGELOG.md
40
CHANGELOG.md
@ -34,6 +34,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- [breaking-change] this crate now uses `portable-atomic` v1.0 instead of `atomic-polyfill` for emulating
|
||||
CAS instructions on targets where they're not natively available.
|
||||
- [breaking-change] `From<&str>` for `String` was replaced with `TryFrom<&str>` because the `From` trait must not fail.
|
||||
- [breaking-change] Renamed Cargo features
|
||||
- `defmt-impl` is now `defmt-03`
|
||||
- `ufmt-impl` is now `ufmt`
|
||||
- `cas` is removed, atomic polyfilling is now opt-in via the `portable-atomic` feature.
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -91,31 +95,31 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
### Added
|
||||
|
||||
* Added support for AVR architecture.
|
||||
* Add `entry` API to `IndexMap`
|
||||
* Implement `IntoIterator` trait for `Indexmap`
|
||||
* Implement `FromIterator` for `String`
|
||||
* Add `first` and `last` methods to `IndexMap` and `IndexSet`
|
||||
* Add `pop_{front_back}_unchecked` methods to `Deque`
|
||||
- Added support for AVR architecture.
|
||||
- Add `entry` API to `IndexMap`
|
||||
- Implement `IntoIterator` trait for `Indexmap`
|
||||
- Implement `FromIterator` for `String`
|
||||
- Add `first` and `last` methods to `IndexMap` and `IndexSet`
|
||||
- Add `pop_{front_back}_unchecked` methods to `Deque`
|
||||
|
||||
### Changed
|
||||
|
||||
* Optimize the codegen of `Vec::clone`
|
||||
* `riscv32i` and `riscv32imc` targets unconditionally (e.g. `build --no-default-features`) depends on `atomic-polyfill`
|
||||
- Optimize the codegen of `Vec::clone`
|
||||
- `riscv32i` and `riscv32imc` targets unconditionally (e.g. `build --no-default-features`) depends on `atomic-polyfill`
|
||||
|
||||
### Fixed
|
||||
|
||||
* Inserting an item that replaces an already present item will no longer
|
||||
fail with an error
|
||||
- Inserting an item that replaces an already present item will no longer
|
||||
fail with an error
|
||||
|
||||
## [v0.7.11] - 2022-05-09
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed `pool` example in docstring.
|
||||
* Fixed undefined behavior in `Vec::truncate()`, `Vec::swap_remove_unchecked()`,
|
||||
- Fixed `pool` example in docstring.
|
||||
- Fixed undefined behavior in `Vec::truncate()`, `Vec::swap_remove_unchecked()`,
|
||||
and `Hole::move_to()` (internal to the binary heap implementation).
|
||||
* Fixed `BinaryHeap` elements are being dropped twice
|
||||
- Fixed `BinaryHeap` elements are being dropped twice
|
||||
|
||||
## [v0.7.10] - 2022-01-21
|
||||
|
||||
@ -295,8 +299,8 @@ fail with an error
|
||||
### Added
|
||||
|
||||
- opt-out `cas` feature to disable parts of the API that use CAS instructions.
|
||||
Useful if using a custom (i.e. not built-in) rustc target that does not have CAS
|
||||
instructions.
|
||||
Useful if using a custom (i.e. not built-in) rustc target that does not have CAS
|
||||
instructions.
|
||||
|
||||
- singleton `Pool` support on ARMv7-A devices
|
||||
|
||||
@ -315,7 +319,7 @@ instructions.
|
||||
- `Pool` now implements the `Sync` trait when targeting ARMv7-R.
|
||||
|
||||
- Most data structures can now be constructed in "const context" (e.g. `static
|
||||
[mut]` variables) using a newtype in `heapless::i`.
|
||||
[mut]` variables) using a newtype in `heapless::i`.
|
||||
|
||||
- `Pool` has gained a `grow_exact` method to more efficiently use statically
|
||||
allocated memory.
|
||||
@ -360,7 +364,7 @@ instructions.
|
||||
### Added
|
||||
|
||||
- Added a memory pool that's lock-free and interrupt-safe on the ARMv7-M
|
||||
architecture.
|
||||
architecture.
|
||||
|
||||
- `IndexMap` have gained `Eq` and `PartialEq` implementations.
|
||||
|
||||
@ -548,7 +552,7 @@ architecture.
|
||||
- [breaking-change] The error type of all operations that may fail has changed from `()` to
|
||||
`BufferFullError`.
|
||||
|
||||
- Both `RingBuffer` and `Vec` now support arrays of *any* size for their backup storage.
|
||||
- Both `RingBuffer` and `Vec` now support arrays of _any_ size for their backup storage.
|
||||
|
||||
## [v0.1.0] - 2017-04-27
|
||||
|
||||
|
47
Cargo.toml
47
Cargo.toml
@ -15,35 +15,32 @@ repository = "https://github.com/rust-embedded/heapless"
|
||||
version = "0.8.0"
|
||||
|
||||
[features]
|
||||
default = ["cas"]
|
||||
cas = ["portable-atomic"]
|
||||
ufmt-impl = ["ufmt-write"]
|
||||
# only for tests
|
||||
__trybuild = []
|
||||
# Enable polyfilling of atomics via `portable-atomic`.
|
||||
# `portable-atomic` polyfills some functionality by default, but to get full atomics you must
|
||||
# enable one of its features to tell it how to do it. See `portable-atomic` documentation for details.
|
||||
portable-atomic = ["dep:portable-atomic"]
|
||||
|
||||
# Enable polyfilling of atomics via portable-atomic, using critical section for locking
|
||||
portable-atomic-critical-section = ["dep:portable-atomic", "portable-atomic?/critical-section"]
|
||||
|
||||
# Enable polyfilling of atomics via portable-atomic, using disabling interrupts for locking.
|
||||
# WARNING: this is only sound for single-core bare-metal privileged-mode targets!
|
||||
portable-atomic-unsafe-assume-single-core = ["dep:portable-atomic", "portable-atomic?/unsafe-assume-single-core"]
|
||||
|
||||
# implement serde traits.
|
||||
serde = ["dep:serde"]
|
||||
|
||||
# implement ufmt traits.
|
||||
ufmt = ["dep:ufmt-write"]
|
||||
|
||||
# Implement defmt::Format from defmt v0.3
|
||||
defmt-03 = ["dep:defmt"]
|
||||
|
||||
# Enable larger MPMC sizes.
|
||||
mpmc_large = []
|
||||
# This flag has no version guarantee, the `defmt` dependency can be updated in a patch release
|
||||
defmt-impl = ["defmt"]
|
||||
|
||||
[target.thumbv6m-none-eabi.dependencies]
|
||||
portable-atomic = { version = "1.0", optional = true }
|
||||
|
||||
[target.riscv32i-unknown-none-elf.dependencies]
|
||||
portable-atomic = { version = "1.0" }
|
||||
|
||||
[target.riscv32imc-unknown-none-elf.dependencies]
|
||||
portable-atomic = { version = "1.0" }
|
||||
|
||||
[target.msp430-none-elf.dependencies]
|
||||
portable-atomic = { version = "1.0" }
|
||||
|
||||
[target.xtensa-esp32s2-none-elf.dependencies]
|
||||
portable-atomic = { version = "1.0", optional = true }
|
||||
|
||||
[target.'cfg(target_arch = "avr")'.dependencies]
|
||||
portable-atomic = { version = "1.0", optional = true }
|
||||
|
||||
[dependencies]
|
||||
portable-atomic = { version = "1.0", optional = true }
|
||||
hash32 = "0.3.0"
|
||||
serde = { version = "1", optional = true, default-features = false }
|
||||
stable_deref_trait = { version = "1", default-features = false }
|
||||
|
87
build.rs
87
build.rs
@ -11,82 +11,21 @@ use std::{
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let target = env::var("TARGET")?;
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
println!("cargo:rustc-cfg=armv6m");
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
} else if target.starts_with("armv7r-") | target.starts_with("armebv7r-") {
|
||||
println!("cargo:rustc-cfg=armv7r");
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
println!("cargo:rustc-cfg=armv8m_base");
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
println!("cargo:rustc-cfg=armv8m_main");
|
||||
} else if target.starts_with("armv7-") | target.starts_with("armv7a-") {
|
||||
println!("cargo:rustc-cfg=armv7a");
|
||||
}
|
||||
|
||||
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 portable-atomic crate
|
||||
// see the `no-atomics.sh` / `no-cas.sh` script sitting next to this file
|
||||
if is_avr {
|
||||
// lacks cas
|
||||
} else {
|
||||
match &target[..] {
|
||||
"avr-unknown-gnu-atmega328"
|
||||
| "bpfeb-unknown-none"
|
||||
| "bpfel-unknown-none"
|
||||
// | "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
|
||||
=> {}
|
||||
|
||||
_ => {
|
||||
println!("cargo:rustc-cfg=has_cas");
|
||||
}
|
||||
}
|
||||
// Manually list targets that have atomic load/store, but no CAS.
|
||||
// Remove when `cfg(target_has_atomic_load_store)` is stable.
|
||||
// last updated nightly-2023-10-28
|
||||
match &target[..] {
|
||||
"armv4t-none-eabi"
|
||||
| "armv5te-none-eabi"
|
||||
| "avr-unknown-gnu-atmega328"
|
||||
| "bpfeb-unknown-none"
|
||||
| "bpfel-unknown-none"
|
||||
| "thumbv4t-none-eabi"
|
||||
| "thumbv5te-none-eabi"
|
||||
| "thumbv6m-none-eabi" => println!("cargo:rustc-cfg=has_atomic_load_store"),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
if is_avr {
|
||||
// lacks atomics
|
||||
} else {
|
||||
println!("cargo:rustc-cfg=has_atomics");
|
||||
}
|
||||
|
||||
// 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=use_portable_atomic");
|
||||
println!("cargo:rustc-cfg=use_portable_atomic_cas");
|
||||
} else {
|
||||
match &target[..] {
|
||||
"riscv32i-unknown-none-elf"
|
||||
| "riscv32imc-unknown-none-elf"
|
||||
| "xtensa-esp32s2-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=use_portable_atomic_cas");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// AArch64 instruction set contains `clrex` but not `ldrex` or `strex`; the
|
||||
// probe will succeed when we already know to deny this target from LLSC.
|
||||
if !target.starts_with("aarch64") {
|
||||
|
@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
main() {
|
||||
IFS='
|
||||
'
|
||||
for t in $(rustc --print target-list); do
|
||||
rustc +nightly --print cfg --target $t | grep 'target_has_atomic_load_store=' >/dev/null || echo $t
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
main
|
14
no-cas.sh
14
no-cas.sh
@ -1,14 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
main() {
|
||||
IFS='
|
||||
'
|
||||
for t in $(rustc --print target-list); do
|
||||
rustc +nightly --print cfg --target $t | grep 'target_has_atomic=' >/dev/null || echo $t
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
main
|
24
src/lib.rs
24
src/lib.rs
@ -61,7 +61,7 @@
|
||||
//!
|
||||
//! The `heapless` crate provides the following optional Cargo features:
|
||||
//!
|
||||
//! - `ufmt-impl`: Implement [`ufmt_write::uWrite`] for `String<N>` and `Vec<u8, N>`
|
||||
//! - `ufmt`: Implement [`ufmt_write::uWrite`] for `String<N>` and `Vec<u8, N>`
|
||||
//!
|
||||
//! [`ufmt_write::uWrite`]: https://docs.rs/ufmt-write/
|
||||
//!
|
||||
@ -108,17 +108,31 @@ mod de;
|
||||
mod ser;
|
||||
|
||||
pub mod binary_heap;
|
||||
#[cfg(feature = "defmt-impl")]
|
||||
#[cfg(feature = "defmt-03")]
|
||||
mod defmt;
|
||||
#[cfg(all(has_cas, feature = "cas"))]
|
||||
#[cfg(any(
|
||||
// assume we have all atomics available if we're using portable-atomic
|
||||
feature = "portable-atomic",
|
||||
// target has native atomic CAS (mpmc_large requires usize, otherwise just u8)
|
||||
all(feature = "mpmc_large", target_has_atomic = "ptr"),
|
||||
all(not(feature = "mpmc_large"), target_has_atomic = "8")
|
||||
))]
|
||||
pub mod mpmc;
|
||||
#[cfg(any(arm_llsc, target_arch = "x86"))]
|
||||
pub mod pool;
|
||||
pub mod sorted_linked_list;
|
||||
#[cfg(has_atomics)]
|
||||
#[cfg(any(
|
||||
// assume we have all atomics available if we're using portable-atomic
|
||||
feature = "portable-atomic",
|
||||
// target has native atomic CAS. Note this is too restrictive, spsc requires load/store only, not CAS.
|
||||
// This should be `cfg(target_has_atomic_load_store)`, but that's not stable yet.
|
||||
target_has_atomic = "ptr",
|
||||
// or the current target is in a list in build.rs of targets known to have load/store but no CAS.
|
||||
has_atomic_load_store
|
||||
))]
|
||||
pub mod spsc;
|
||||
|
||||
#[cfg(feature = "ufmt-impl")]
|
||||
#[cfg(feature = "ufmt")]
|
||||
mod ufmt;
|
||||
|
||||
mod sealed;
|
||||
|
@ -88,9 +88,9 @@
|
||||
|
||||
use core::{cell::UnsafeCell, mem::MaybeUninit};
|
||||
|
||||
#[cfg(not(use_portable_atomic_cas))]
|
||||
#[cfg(not(feature = "portable-atomic"))]
|
||||
use core::sync::atomic;
|
||||
#[cfg(use_portable_atomic_cas)]
|
||||
#[cfg(feature = "portable-atomic")]
|
||||
use portable_atomic as atomic;
|
||||
|
||||
use atomic::Ordering;
|
||||
|
@ -96,9 +96,9 @@
|
||||
|
||||
use core::{cell::UnsafeCell, fmt, hash, mem::MaybeUninit, ptr};
|
||||
|
||||
#[cfg(not(use_portable_atomic))]
|
||||
#[cfg(not(feature = "portable-atomic"))]
|
||||
use core::sync::atomic;
|
||||
#[cfg(use_portable_atomic)]
|
||||
#[cfg(feature = "portable-atomic")]
|
||||
use portable_atomic as atomic;
|
||||
|
||||
use atomic::{AtomicUsize, Ordering};
|
||||
|
Loading…
x
Reference in New Issue
Block a user