39个版本 (15个稳定版)
1.7.0 | 2024年7月19日 |
---|---|
1.6.0 | 2023年12月6日 |
1.5.1 | 2023年10月29日 |
1.4.2 | 2023年7月27日 |
0.3.0 | 2022年3月25日 |
#2 in 嵌入式开发
每月 3,638,410 次下载
在 3,132 个crate中(130个直接使用) 使用
1MB
16K SLoC
portable-atomic
支持128位原子、原子浮点等可移植原子类型。
- 为所有可以使用原子CAS的目标提供所有原子整数类型(
Atomic{I,U}})。(即所有可以使用
std
的目标和大多数无std目标) - 提供
AtomicI128
和AtomicU128
。 - 提供
AtomicF32
和AtomicF64
。(可选,需要float
功能) - 为在标准库中根本无法使用原子的目标提供原子加载/存储。(无A扩展的RISC-V、MSP430、AVR)
- 为在标准库中无法使用原子CAS的目标提供原子CAS。(thumbv6m、v6之前的ARM、无A扩展的RISC-V、MSP430、AVR、Xtensa等。)(MSP430和AVR始终启用,否则为可选)
- 提供标准库原子类型不稳定API的稳定等效,例如
AtomicPtr::fetch_*
、AtomicBool::fetch_not
。 - 创建需要较新编译器的功能,例如
fetch_max
、fetch_update
、as_ptr
、from_ptr
和 更强的CAS失败顺序,这些功能在 Rust 1.34+ 上可用。 - 为标准库中原子相关API的bug提供解决方案,例如 rust-lang/rust#100650,在MSP430上使用
fence/
compiler_fence
导致LLVM错误等。
由 portable-atomic-util 包提供了 std::sync::Arc
的可移植原子版本。
使用方法
将以下内容添加到您的 Cargo.toml
[dependencies]
portable-atomic = "1"
默认功能主要针对使用指针宽度以上的原子的用户。如果您不需要它们,禁用默认功能可能会略微减少代码大小和编译时间。
[dependencies]
portable-atomic = { version = "1", default-features = false }
如果您的包支持no-std环境且需要原子CAS,启用 require-cas
功能将允许 portable-atomic
显示一个 有用的错误信息,告知用户在需要用户端额外操作的目标上提供原子CAS。
[dependencies]
portable-atomic = { version = "1.3", default-features = false, features = ["require-cas"] }
128位原子支持
在 x86_64(Rust 1.59+)、aarch64(Rust 1.59+)、powerpc64(仅限nightly)和 s390x(仅限nightly)上提供本机128位原子操作,否则使用后备实现。
在 x86_64 上,即使编译时没有 cmpxchg16b
(注意:默认情况下仅在 Apple 和 Windows(除Windows 7)目标上启用 cmpxchg16b
目标功能),运行时会检测 cmpxchg16b
是否可用。如果编译时或运行时检测到 cmpxchg16b
不可用,则使用后备实现。另请参阅 portable_atomic_no_outline_atomics
cfg。
它们通常使用内联汇编实现,当使用不支持内联汇编的 Miri 或 ThreadSanitizer 时,如果可能,则使用内联汇编而不是核心内省。
有关详细信息,请参阅 atomic128
模块的说明。
可选功能
-
fallback
(默认启用)
启用后备实现。禁用此选项仅允许平台原生支持原子操作的原子类型。
-
请注意,大多数原子浮点数的
fetch_*
操作都使用CAS循环实现,这比等效的原子整数操作要慢。(GPU目标有浮点数的原子指令,所以我们计划在未来为GPU目标使用这些指令。) -
std
使用std
。 -
serde
为原子类型实现serde::{Serialize,Deserialize}
。注意
- 当此功能启用时,MSRV取决于serde的MSRV。
-
critical-section
当此功能启用时,此crate在原生不可用的目标上使用critical-section来提供原子 CAS。启用时,您应该为当前目标提供一个合适的临界区实现,有关如何操作的详细信息,请参阅critical-section文档。critical-section
支持在无法使用unsafe-assume-single-core
功能的情况下很有用,例如在多核目标、某些 RTOS 下运行的无特权代码或需要额外注意禁用中断的环境(例如实时要求)。请注意,使用
critical-section
功能时,所有原子操作都会采取临界区,而使用unsafe-assume-single-core
功能时,某些操作不需要禁用中断(加载和存储,但在 MSP430 上还有add
、sub
、and
、or
、xor
、not
)。因此,为了更好的性能,如果您的目标的critical-section
实现仅仅是禁用中断,则建议使用unsafe-assume-single-core
功能。注意
-
当此功能启用时,MSRV取决于critical-section的MSRV。
-
通常不推荐在库的依赖项中始终启用此功能。
启用此功能将阻止最终用户利用其他(可能)高效实现的机会(例如
unsafe-assume-single-core
功能提供的实现、MSP430 和 AVR 上的默认实现、在#60中提出的实现等。未来也可能支持其他系统)。对于库,建议让最终用户自己决定是否启用此功能。(然而,对于已知其他实现不起作用的特定平台库,默认启用此功能可能是有意义的。)
例如,最终用户的
Cargo.toml
可能如下所示,该Cargo.toml
使用了一个提供临界区实现的crate和一个依赖portable-atomic作为选项的crate[dependencies] portable-atomic = { version = "1", default-features = false, features = ["critical-section"] } crate-provides-critical-section-impl = "..." crate-uses-portable-atomic-as-feature = { version = "...", features = ["portable-atomic"] }
-
-
unsafe-assume-single-core
假设目标是单核。当此功能启用时,此crate通过禁用中断为标准库中不可用的目标提供原子 CAS。此功能是
unsafe
,请注意以下安全要求-
对于多核系统,启用此功能始终是不安全的。
-
此功能使用特权指令来禁用中断,因此通常在无特权模式下无法工作。如果在没有特权指令的环境中使用此功能,或者使用的指令不足以在系统中禁用中断,通常也认为它是不安全的,尽管具体取决于系统。
以下是一些已知情况
- 在预v6 ARM架构上,默认情况下此功能仅禁用中断请求(IRQs)。对于许多系统(例如GBA),这已经足够。如果系统需要同时禁用中断请求和快速中断请求(FIQs),则需要一起启用
disable-fiq
功能。 - 在无A扩展的RISC-V上,默认情况下,它生成机器模式(M模式)的代码。如果您同时启用
s-mode
,则生成监督模式(S模式)的代码。特别是,qemu-system-riscv*
默认使用OpenSBI作为固件。
另请参阅
interrupt
模块的README。 - 在预v6 ARM架构上,默认情况下此功能仅禁用中断请求(IRQs)。对于许多系统(例如GBA),这已经足够。如果系统需要同时禁用中断请求和快速中断请求(FIQs),则需要一起启用
对于无法使用此功能的系统,请考虑使用
critical-section
功能。在依赖
portable-atomic
的库中启用此功能是强烈不建议的。对于库的建议方法是让最终用户决定是否启用此功能。(然而,对于确保始终是有效的特定平台的库,例如针对单核芯片的硬件抽象层,默认启用此功能可能是合理的。)目前支持ARMv6-M (thumbv6m)、预v6 ARM(例如,thumbv4t、thumbv5te)、无A扩展的RISC-V和Xtensa。
由于所有MSP430和AVR都是单核,因此我们始终为它们提供此功能下的原子比较并交换(CAS)操作,而不需要此功能。
对于具有原子CAS的目标启用此功能将导致编译错误。
如果您不支持的目标,请随时提交问题。
-
可选配置
启用配置的一种方法是在cargo配置中设置rustflags
# .cargo/config.toml
[target.<target>]
rustflags = ["--cfg", "portable_atomic_no_outline_atomics"]
或设置环境变量
RUSTFLAGS="--cfg portable_atomic_no_outline_atomics" cargo ...
-
--cfg portable_atomic_unsafe_assume_single_core
从1.4.0版本开始,此配置是unsafe-assume-single-core
特性的别名。最初,我们提供的是配置而不是特性,但根据嵌入式生态系统的强烈请求,我们同意也提供这些特性。有关更多信息,请参阅#94。
-
--cfg portable_atomic_no_outline_atomics
通过运行时CPU特性检测禁用动态分派。如果启用了通过运行时CPU特性检测的动态分派,则允许在保持对旧CPU的支持的同时使用不支持旧CPU的功能,例如CMPXCHG16B(x86_64)和FEAT_LSE/FEAT_LSE2(aarch64)。
注意
- 当前,动态检测仅在Rust 1.59+的aarch64和x86_64上启用,对于powerpc64(默认禁用)的nightly版本仅限启用,否则与设置此配置时的工作方式相同。
- 如果编译时启用了所需的目标特性,则原子操作将被内联。
- 这与no-std(除了
std
之外的所有特性)兼容。 - 在某些目标上,默认禁用运行时检测主要是为了与旧版操作系统或不完整的构建环境兼容,可以通过
--cfg portable_atomic_outline_atomics
启用。 (当两个配置都启用时,优先选择*_no_*
配置。) - 一些aarch64目标默认启用LLVM的
outline-atomics
目标特性,因此如果您设置了此配置,可能还需要禁用它。(portable-atomic的outline-atomics不依赖于compiler-rt符号,所以即使您需要禁用LLVM的outline-atomics,也可能不需要禁用portable-atomic的outline-atomics。)
相关项目
- atomic-maybe-uninit:对可能未初始化的整数的原子操作。
- atomic-memcpy:字节级别的原子memcpy。
许可证
根据您的选择,许可协议为Apache许可证,版本2.0或MIT许可证。
除非您明确表示,否则根据Apache-2.0许可证定义的,您有意提交以包含在作品中的任何贡献,都将按照上述方式双重许可,不附加任何额外的条款或条件。