ci(no_std): matrix over 8 embedded targets, add critical-section feature - #20
Merged
Merged
Conversation
The no_std job checked one target, thumbv7m-none-eabi. Extending it per atomic capability class found two targets that did not compile at all: thumbv6m-none-eabi Cortex-M0 / M0+, both RP2040 cores riscv32imc-unknown-none-elf ESP32-C3 Both fail with `unresolved import portable_atomic::AtomicU64`. ARMv6-M has no LDREX/STREX and RISC-V without the A extension has no atomics at all, so portable-atomic's `fallback` spinlock has no CAS to build itself out of and never defines AtomicU64. MetaWord is an AtomicU64, so the crate simply does not build there. New opt-in `critical-section` feature forwards to portable-atomic/critical-section, which does the CAS with interrupts masked. Both targets check clean with it. Off by default: sound only on single-core targets, and the impl belongs to the binary (cortex-m's critical-section-single-core, or esp-hal). Also newly covered, clean with no extra feature: thumbv7em-none-eabihf, thumbv8m.main-none-eabi, riscv32imac-unknown-none-elf, aarch64-unknown-none, wasm32-unknown-unknown. These are compile checks. Nothing runs on silicon or under QEMU, and cargo check does not link, so a downstream thumbv6m/riscv32imc binary still has to supply the critical-section impl.
Adds a "When `std` Isn't Available" section: QuickCache and Moka both need std, so the no_std field is PulseMap vs lru, and there PulseMap is 40.0B vs 83.1B per resident entry (measured as RSS delta, x86_64) and keeps 1000/1000 hot keys through a 200K-key scan where lru keeps 0/1000. Includes the verified-target table from the new CI matrix, which targets need the critical-section feature and why, the inline-mode window (6-byte key / 7-byte value, a u64 key misses it and costs 113.2B), and the 4-slots-no- chaining caveat: inserting exactly `capacity` distinct keys leaves ~81% resident, so size for 1.3-1.5x. Feature Flags table gains the critical-section row.
This was referenced Sep 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this found
The
no_stdjob checked exactly one target,thumbv7m-none-eabi. Extending it to one job per atomic capability class — the only axis that can actually break a bare-metal build here — turned up two targets where the crate did not compile at all:thumbv6m-none-eabicritical-sectionriscv32imc-unknown-none-elfcritical-sectionBoth failed identically:
MetaWordis anAtomicU64. ARMv6-M has noLDREX/STREX, and RISC-V without the A extension has no atomic instructions at all — soportable-atomic'sfallbackspinlock has no CAS to build itself out of, and doesn't defineAtomicU64. The crate'sno_stdsupport was real, just narrower than advertised, and CI had no way to notice.The fix
One new opt-in feature, off by default:
portable-atomicthen performs the CAS with interrupts masked. Default-off is deliberate — it is only sound on single-core targets, and the impl belongs to the binary rather than the library:cortex-mwithcritical-section-single-core, oresp-halon the ESP32-C3.Coverage now
fail-fast: false, so one unsupported target can't mask the other seven.thumbv7m-none-eabithumbv7em-none-eabihfthumbv8m.main-none-eabithumbv6m-none-eabicritical-sectionriscv32imac-unknown-none-elfriscv32imc-unknown-none-elfcritical-sectionaarch64-unknown-nonewasm32-unknown-unknownAll 8 verified locally before this PR; the failures above are reproducible by reverting the
Cargo.tomlfeature and dropping--features critical-section.Scope
These are compile checks. Nothing was executed on real silicon or under QEMU, and
cargo checkdoes not link — a downstreamthumbv6m/riscv32imcbinary still has to supply thecritical-sectionimpl or it fails at link time.src/is unchanged; the only non-CI change is the feature line inCargo.toml.The second commit documents all of this in the README (
When std Isn't Available), together with the measuredno_stdcomparison againstlru.