116116//! fully contiguous (i.e., has no "holes"), there is no guarantee that this
117117//! will not change in the future.
118118//!
119+ //! Allocated objects must behave like "normal" memory: in particular, reads must not have
120+ //! side-effects, and writes must become visible to other threads using the usual synchronization
121+ //! primitives.
122+ //!
119123//! For any allocated object with `base` address, `size`, and a set of
120124//! `addresses`, the following are guaranteed:
121125//! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base +
@@ -1755,38 +1759,30 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
17551759/// over time. That being said, the semantics will almost always end up pretty
17561760/// similar to [C11's definition of volatile][c11].
17571761///
1758- /// Volatile operations are intended to act on I/O memory, and are guaranteed
1759- /// to not be elided or reordered by the compiler across other volatile
1760- /// operations. With this in mind, there are two cases of usage that need to
1761- /// be distinguished:
1762- ///
1763- /// - When a volatile operation is used for memory inside an [allocation], all
1764- /// the typical restrictions of Rust-allocated memory apply, meaning things
1765- /// like data races and mutable aliasing remain as undefined behavior. In
1766- /// addition, the volatile rule that the operation won't be elided or
1767- /// reordered applies, such that the operation will access memory and not e.g.
1768- /// be lowered to a register access or stack pop. The memory in `src` should
1769- /// remain unchanged. Just like in C, whether an operation is volatile has no
1770- /// bearing whatsoever on questions involving concurrent access from multiple
1771- /// threads. Volatile accesses behave exactly like non-atomic accesses in that
1772- /// regard. All this is because this kind of target-memory may be used from
1773- /// safe code at any time, and its validity assumptions must not be violated.
1774- ///
1775- /// - Volatile operations, however, provide a conditionally valid way to access
1776- /// memory that is _outside_ of any allocation. The main use-case is CPU and
1777- /// peripheral registers that must be accessed via an I/O memory mapping, most
1778- /// commonly at fixed addresses reserved by the hardware. These often have
1779- /// special semantics associated to their manipulation, and cannot be used as
1780- /// general purpose memory. Here, any address value is possible, from 0 to
1781- /// [`usize::MAX`], so long as its semantics are well-defined by the target
1782- /// hardware. The access is restricted to not trap/interrupt. It can (and
1783- /// usually will) cause side-effects, but note they shouldn't affect
1784- /// Rust-allocated memory in any way.
1785- ///
1786- /// The compiler shouldn't change the relative order or number of volatile
1787- /// memory operations. However, volatile memory operations on zero-sized types
1788- /// (e.g., if a zero-sized type is passed to `read_volatile`) are noops
1789- /// and may be ignored.
1762+ /// Volatile operations are intended to act on I/O memory. As such, they are considered externally
1763+ /// observable events (just like syscalls), and are guaranteed to not be elided or reordered by the
1764+ /// compiler across other externally observable events. With this in mind, there are two cases of
1765+ /// usage that need to be distinguished:
1766+ ///
1767+ /// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like
1768+ /// [`read`], except for the additional guarantee that it won't be elided or reordered (see
1769+ /// above). This implies that the operation will actually access memory and not e.g. be lowered to
1770+ /// a register access or stack pop. Other than that, all the usual rules for memory accesses
1771+ /// apply. In particular, just like in C, whether an operation is volatile has no bearing
1772+ /// whatsoever on questions involving concurrent access from multiple threads. Volatile accesses
1773+ /// behave exactly like non-atomic accesses in that regard.
1774+ ///
1775+ /// - Volatile operations, however, may also be used access memory that is _outside_ of any Rust
1776+ /// allocation. The main use-case is CPU and peripheral registers that must be accessed via an I/O
1777+ /// memory mapping, most commonly at fixed addresses reserved by the hardware. These often have
1778+ /// special semantics associated to their manipulation, and cannot be used as general purpose
1779+ /// memory. Here, any address value is possible, including 0 and [`usize::MAX`], so long as the
1780+ /// semantics of such a read are well-defined by the target hardware. The access must not trap. It
1781+ /// can (and usually will) cause side-effects, but those must not affect Rust-allocated memory in
1782+ /// any way.
1783+ ///
1784+ /// Note that volatile memory operations on zero-sized types (e.g., if a zero-sized type is passed
1785+ /// to `read_volatile`) are noops and may be ignored.
17901786///
17911787/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
17921788/// [allocation]: crate::ptr#allocated-object
@@ -1795,15 +1791,14 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
17951791///
17961792/// Behavior is undefined if any of the following conditions are violated:
17971793///
1798- /// * `src` must be readable without trapping.
1794+ /// * `src` must be either [valid] for reads, or it must point to memory outside of all Rust
1795+ /// allocations and reading from that memory must:
1796+ /// - not trap, and
1797+ /// - not cause any memory inside a Rust allocation to be modified.
17991798///
18001799/// * `src` must be properly aligned.
18011800///
1802- /// * No Rust memory may be modified.
1803- ///
1804- /// * If operating on an allocation, `src` must point to a properly initialized
1805- /// value of type `T`, and the safe usage assumptions of the data must be
1806- /// satisfied.
1801+ /// * Reading from `src` must produce a properly initialized value of type `T`.
18071802///
18081803/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of
18091804/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned
0 commit comments