Skip to content

Commit 93e62a2

Browse files
committed
Auto merge of #115577 - RalfJung:atomic-load, r=Amanieu
document when atomic loads are guaranteed read-only Based on this [discussion in Zulip](https://rust-lang.zulipchat.com/#narrow/stream/136281-t-opsem/topic/Can.20.60Atomic*.3A.3Aload.60.20perform.20a.20write). The values for x86 and x86_64 are complete guesswork on my side, and I have no clue what the values might be for other architectures. I hope we can get the right people to chime in to gather the required information. :) I'll update Miri to respect these rules once we have more data.
2 parents 616e379 + e494df4 commit 93e62a2

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

library/core/src/sync/atomic.rs

+34
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,40 @@
7979
//!
8080
//! [lock-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm
8181
//!
82+
//! # Atomic accesses to read-only memory
83+
//!
84+
//! In general, *all* atomic accesses on read-only memory are Undefined Behavior. For instance, attempting
85+
//! to do a `compare_exchange` that will definitely fail (making it conceptually a read-only
86+
//! operation) can still cause a page fault if the underlying memory page is mapped read-only. Since
87+
//! atomic `load`s might be implemented using compare-exchange operations, even a `load` can fault
88+
//! on read-only memory.
89+
//!
90+
//! For the purpose of this section, "read-only memory" is defined as memory that is read-only in
91+
//! the underlying target, i.e., the pages are mapped with a read-only flag and any attempt to write
92+
//! will cause a page fault. In particular, an `&u128` reference that points to memory that is
93+
//! read-write mapped is *not* considered to point to "read-only memory". In Rust, almost all memory
94+
//! is read-write; the only exceptions are memory created by `const` items or `static` items without
95+
//! interior mutability, and memory that was specifically marked as read-only by the operating
96+
//! system via platform-specific APIs.
97+
//!
98+
//! As an exception from the general rule stated above, "sufficiently small" atomic loads with
99+
//! `Ordering::Relaxed` are implemented in a way that works on read-only memory, and are hence not
100+
//! Undefined Behavior. The exact size limit for what makes a load "sufficiently small" varies
101+
//! depending on the target:
102+
//!
103+
//! | `target_arch` | Size limit |
104+
//! |---------------|---------|
105+
//! | `x86`, `arm`, `mips`, `mips32r6, `powerpc`, `riscv32`, `sparc`, `hexagon` | 4 bytes |
106+
//! | `x86_64`, `aarch64`, `loongarch64`, `mips64`, `mips64r6`, `powerpc64`, `riscv64`, `sparc64`, `s390x` | 8 bytes |
107+
//!
108+
//! Atomics loads that are larger than this limit as well as atomic loads with ordering other
109+
//! than `Relaxed`, as well as *all* atomic loads on targets not listed in the table, might still be
110+
//! read-only under certain conditions, but that is not a stable guarantee and should not be relied
111+
//! upon.
112+
//!
113+
//! If you need to do an acquire load on read-only memory, you can do a relaxed load followed by an
114+
//! acquire fence instead.
115+
//!
82116
//! # Examples
83117
//!
84118
//! A simple spinlock:

0 commit comments

Comments
 (0)