@@ -1839,72 +1839,63 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
1839
1839
}
1840
1840
}
1841
1841
1842
- /// Performs a volatile write of a memory location with the given value without
1843
- /// reading or dropping the old value.
1844
- ///
1845
- /// Rust does not currently have a rigorously and formally defined memory model,
1846
- /// so the precise semantics of what "volatile" means here is subject to change
1847
- /// over time. That being said, the semantics will almost always end up pretty
1848
- /// similar to [C11's definition of volatile][c11].
1849
- ///
1850
- /// Volatile operations are intended to act on I/O memory, and are guaranteed
1851
- /// to not be elided or reordered by the compiler across other volatile
1852
- /// operations. With this in mind, there are two cases of usage that need to
1853
- /// be distinguished:
1854
- ///
1855
- /// - When a volatile operation is used for memory inside an [allocation], all
1856
- /// the typical restrictions of Rust-allocated memory apply, meaning things
1857
- /// like data races and mutable aliasing remain as undefined behavior. In
1858
- /// addition, the volatile rule that the operation won't be elided or
1859
- /// reordered applies, such that the operation will access memory and not e.g.
1860
- /// be lowered to a register access or stack pop. The memory in `src` should
1861
- /// remain unchanged. Just like in C, whether an operation is volatile has no
1862
- /// bearing whatsoever on questions involving concurrent access from multiple
1863
- /// threads. Volatile accesses behave exactly like non-atomic accesses in that
1864
- /// regard. All this is because this kind of target-memory may be used from
1865
- /// safe code at any time, and its validity assumptions must not be violated.
1866
- ///
1867
- /// - Volatile operations, however, provide a conditionally valid way to access
1868
- /// memory that is _outside_ of any allocation. The main use-case is CPU and
1869
- /// peripheral registers that must be accessed via an I/O memory mapping, most
1870
- /// commonly at fixed addresses reserved by the hardware. These often have
1871
- /// special semantics associated to their manipulation, and cannot be used as
1872
- /// general purpose memory. Here, any address value is possible, from 0 to
1873
- /// [`usize::MAX`], so long as its semantics are well-defined by the target
1874
- /// hardware. The access is restricted to not trap/interrupt. It can (and
1875
- /// usually will) cause side-effects, but note they shouldn't affect
1876
- /// Rust-allocated memory in any way.
1877
- ///
1878
- /// The compiler shouldn't change the relative order or number of volatile
1879
- /// memory operations. However, volatile memory operations on zero-sized types
1880
- /// (e.g., if a zero-sized type is passed to `write_volatile`) are noops
1881
- /// and may be ignored.
1882
- ///
1883
- /// `write_volatile` does not drop the contents of `dst`. This is safe, but it
1884
- /// could leak allocations or resources, so care should be taken not to
1885
- /// overwrite an object that should be dropped when operating on Rust memory.
1842
+ /// Performs a volatile write of a memory location with the given value without reading or dropping
1843
+ /// the old value.
1886
1844
///
1887
- /// Additionally, it does not drop `src`. Semantically, `src` is moved into the
1888
- /// location pointed to by `dst`.
1845
+ /// Rust does not currently have a rigorously and formally defined memory model, so the precise
1846
+ /// semantics of what "volatile" means here is subject to change over time. That being said, the
1847
+ /// semantics will almost always end up pretty similar to [C11's definition of volatile][c11].
1848
+ ///
1849
+ /// Volatile operations are intended to act on I/O memory. As such, they are considered externally
1850
+ /// observable events (just like syscalls), and are guaranteed to not be elided or reordered by the
1851
+ /// compiler across other externally observable events. With this in mind, there are two cases of
1852
+ /// usage that need to be distinguished:
1853
+ ///
1854
+ /// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like
1855
+ /// [`write`], except for the additional guarantee that it won't be elided or reordered (see
1856
+ /// above). This implies that the operation will actually access memory and not e.g. be lowered to
1857
+ /// a register access or stack pop. Other than that, all the usual rules for memory accesses
1858
+ /// apply. In particular, just like in C, whether an operation is volatile has no bearing
1859
+ /// whatsoever on questions involving concurrent access from multiple threads. Volatile accesses
1860
+ /// behave exactly like non-atomic accesses in that regard.
1861
+ ///
1862
+ /// - Volatile operations, however, may also be used access memory that is _outside_ of any Rust
1863
+ /// allocation. The main use-case is CPU and peripheral registers that must be accessed via an I/O
1864
+ /// memory mapping, most commonly at fixed addresses reserved by the hardware. These often have
1865
+ /// special semantics associated to their manipulation, and cannot be used as general purpose
1866
+ /// memory. Here, any address value is possible, including 0 and [`usize::MAX`], so long as the
1867
+ /// semantics of such a write are well-defined by the target hardware. The access must not trap.
1868
+ /// It can (and usually will) cause side-effects, but those must not affect Rust-allocated memory
1869
+ /// in any way. In this use-case, the pointer validity rules in the [module
1870
+ /// documentation][mod-docs] may not apply.
1871
+ ///
1872
+ /// Note that volatile memory operations on zero-sized types (e.g., if a zero-sized type is passed
1873
+ /// to `write_volatile`) are noops and may be ignored.
1874
+ ///
1875
+ /// `write_volatile` does not drop the contents of `dst`. This is safe, but it could leak
1876
+ /// allocations or resources, so care should be taken not to overwrite an object that should be
1877
+ /// dropped when operating on Rust memory.
1878
+ ///
1879
+ /// Additionally, it does not drop `src`. Semantically, `src` is moved into the location pointed to
1880
+ /// by `dst`.
1889
1881
///
1890
1882
/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
1891
1883
/// [allocation]: crate::ptr#allocated-object
1884
+ /// [mod-docs]: crate::ptr
1892
1885
///
1893
1886
/// # Safety
1894
1887
///
1895
1888
/// Behavior is undefined if any of the following conditions are violated:
1896
1889
///
1897
- /// * `dst` must be writable without trapping.
1890
+ /// * `dst` must be either [valid] for writes, or it must point to memory outside of all Rust
1891
+ /// allocations and to that memory must:
1892
+ /// - not trap, and
1893
+ /// - not cause any memory inside a Rust allocation to be modified.
1898
1894
///
1899
1895
/// * `dst` must be properly aligned.
1900
1896
///
1901
1897
/// * `src` must be a properly initialized value of type `T`.
1902
1898
///
1903
- /// * If operating on an allocation, no Rust memory outside of `dst` may be
1904
- /// modified.
1905
- ///
1906
- /// * If not operating on an allocation, no Rust memory may be affected.
1907
- ///
1908
1899
/// Note that even if `T` has size `0`, the pointer must be properly aligned.
1909
1900
///
1910
1901
/// # Examples
0 commit comments