|
28 | 28 | //! undefined behavior to perform two concurrent accesses to the same location from different
|
29 | 29 | //! threads unless both accesses only read from memory. Notice that this explicitly
|
30 | 30 | //! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot
|
31 |
| -//! be used for inter-thread synchronization. |
| 31 | +//! be used for inter-thread synchronization, regardless of whether it is acting on |
| 32 | +//! Rust memory or not. |
32 | 33 | //! * The result of casting a reference to a pointer is valid for as long as the
|
33 | 34 | //! underlying allocation is live and no reference (just raw pointers) is used to
|
34 | 35 | //! access the same memory. That is, reference and pointer accesses cannot be
|
|
114 | 115 | //! fully contiguous (i.e., has no "holes"), there is no guarantee that this
|
115 | 116 | //! will not change in the future.
|
116 | 117 | //!
|
| 118 | +//! Allocations must behave like "normal" memory: in particular, reads must not have |
| 119 | +//! side-effects, and writes must become visible to other threads using the usual synchronization |
| 120 | +//! primitives. |
| 121 | +//! |
117 | 122 | //! For any allocation with `base` address, `size`, and a set of
|
118 | 123 | //! `addresses`, the following are guaranteed:
|
119 | 124 | //! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base +
|
@@ -2021,54 +2026,68 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
|
2021 | 2026 | }
|
2022 | 2027 | }
|
2023 | 2028 |
|
2024 |
| -/// Performs a volatile read of the value from `src` without moving it. This |
2025 |
| -/// leaves the memory in `src` unchanged. |
2026 |
| -/// |
2027 |
| -/// Volatile operations are intended to act on I/O memory, and are guaranteed |
2028 |
| -/// to not be elided or reordered by the compiler across other volatile |
2029 |
| -/// operations. |
2030 |
| -/// |
2031 |
| -/// # Notes |
2032 |
| -/// |
2033 |
| -/// Rust does not currently have a rigorously and formally defined memory model, |
2034 |
| -/// so the precise semantics of what "volatile" means here is subject to change |
2035 |
| -/// over time. That being said, the semantics will almost always end up pretty |
2036 |
| -/// similar to [C11's definition of volatile][c11]. |
2037 |
| -/// |
2038 |
| -/// The compiler shouldn't change the relative order or number of volatile |
2039 |
| -/// memory operations. However, volatile memory operations on zero-sized types |
2040 |
| -/// (e.g., if a zero-sized type is passed to `read_volatile`) are noops |
2041 |
| -/// and may be ignored. |
| 2029 | +/// Performs a volatile read of the value from `src` without moving it. |
| 2030 | +/// |
| 2031 | +/// Rust does not currently have a rigorously and formally defined memory model, so the precise |
| 2032 | +/// semantics of what "volatile" means here is subject to change over time. That being said, the |
| 2033 | +/// semantics will almost always end up pretty similar to [C11's definition of volatile][c11]. |
| 2034 | +/// |
| 2035 | +/// Volatile operations are intended to act on I/O memory. As such, they are considered externally |
| 2036 | +/// observable events (just like syscalls), and are guaranteed to not be elided or reordered by the |
| 2037 | +/// compiler across other externally observable events. With this in mind, there are two cases of |
| 2038 | +/// usage that need to be distinguished: |
| 2039 | +/// |
| 2040 | +/// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like |
| 2041 | +/// [`read`], except for the additional guarantee that it won't be elided or reordered (see |
| 2042 | +/// above). This implies that the operation will actually access memory and not e.g. be lowered to |
| 2043 | +/// reusing data from a previous read, such as a register that performed a previous load on that |
| 2044 | +/// memory. Other than that, all the usual rules for memory accesses apply (including provenance). |
| 2045 | +/// In particular, just like in C, whether an operation is volatile has no bearing whatsoever on |
| 2046 | +/// questions involving concurrent access from multiple threads. Volatile accesses behave exactly |
| 2047 | +/// like non-atomic accesses in that regard. |
| 2048 | +/// |
| 2049 | +/// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust |
| 2050 | +/// allocation. In this use-case, the pointer does *not* have to be [valid] for reads. This is |
| 2051 | +/// typically used for CPU and peripheral registers that must be accessed via an I/O memory |
| 2052 | +/// mapping, most commonly at fixed addresses reserved by the hardware. These often have special |
| 2053 | +/// semantics associated to their manipulation, and cannot be used as general purpose memory. |
| 2054 | +/// Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics |
| 2055 | +/// of such a read are well-defined by the target hardware. The provenance of the pointer is |
| 2056 | +/// irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It |
| 2057 | +/// can cause side-effects, but those must not affect Rust-allocated memory in in any way. This |
| 2058 | +/// access is still not considered [atomic], and as such it cannot be used for inter-thread |
| 2059 | +/// synchronization. |
| 2060 | +/// |
| 2061 | +/// Note that volatile memory operations on zero-sized types (e.g., if a zero-sized type is passed |
| 2062 | +/// to `read_volatile`) are noops and may be ignored. |
2042 | 2063 | ///
|
2043 | 2064 | /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
|
| 2065 | +/// [allocation]: crate::ptr#allocated-object |
| 2066 | +/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses |
2044 | 2067 | ///
|
2045 | 2068 | /// # Safety
|
2046 | 2069 | ///
|
| 2070 | +/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of whether `T` is |
| 2071 | +/// [`Copy`]. If `T` is not [`Copy`], using both the returned value and the value at `*src` can |
| 2072 | +/// [violate memory safety][read-ownership]. However, storing non-[`Copy`] types in volatile memory |
| 2073 | +/// is almost certainly incorrect. |
| 2074 | +/// |
2047 | 2075 | /// Behavior is undefined if any of the following conditions are violated:
|
2048 | 2076 | ///
|
2049 |
| -/// * `src` must be [valid] for reads. |
| 2077 | +/// * `src` must be either [valid] for reads, or it must point to memory outside of all Rust |
| 2078 | +/// allocations and reading from that memory must: |
| 2079 | +/// - not trap, and |
| 2080 | +/// - not cause any memory inside a Rust allocation to be modified. |
2050 | 2081 | ///
|
2051 | 2082 | /// * `src` must be properly aligned.
|
2052 | 2083 | ///
|
2053 |
| -/// * `src` must point to a properly initialized value of type `T`. |
2054 |
| -/// |
2055 |
| -/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of |
2056 |
| -/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned |
2057 |
| -/// value and the value at `*src` can [violate memory safety][read-ownership]. |
2058 |
| -/// However, storing non-[`Copy`] types in volatile memory is almost certainly |
2059 |
| -/// incorrect. |
| 2084 | +/// * Reading from `src` must produce a properly initialized value of type `T`. |
2060 | 2085 | ///
|
2061 | 2086 | /// Note that even if `T` has size `0`, the pointer must be properly aligned.
|
2062 | 2087 | ///
|
2063 | 2088 | /// [valid]: self#safety
|
2064 | 2089 | /// [read-ownership]: read#ownership-of-the-returned-value
|
2065 | 2090 | ///
|
2066 |
| -/// Just like in C, whether an operation is volatile has no bearing whatsoever |
2067 |
| -/// on questions involving concurrent access from multiple threads. Volatile |
2068 |
| -/// accesses behave exactly like non-atomic accesses in that regard. In particular, |
2069 |
| -/// a race between a `read_volatile` and any write operation to the same location |
2070 |
| -/// is undefined behavior. |
2071 |
| -/// |
2072 | 2091 | /// # Examples
|
2073 | 2092 | ///
|
2074 | 2093 | /// Basic usage:
|
@@ -2100,52 +2119,67 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
2100 | 2119 | }
|
2101 | 2120 | }
|
2102 | 2121 |
|
2103 |
| -/// Performs a volatile write of a memory location with the given value without |
2104 |
| -/// reading or dropping the old value. |
2105 |
| -/// |
2106 |
| -/// Volatile operations are intended to act on I/O memory, and are guaranteed |
2107 |
| -/// to not be elided or reordered by the compiler across other volatile |
2108 |
| -/// operations. |
2109 |
| -/// |
2110 |
| -/// `write_volatile` does not drop the contents of `dst`. This is safe, but it |
2111 |
| -/// could leak allocations or resources, so care should be taken not to overwrite |
2112 |
| -/// an object that should be dropped. |
2113 |
| -/// |
2114 |
| -/// Additionally, it does not drop `src`. Semantically, `src` is moved into the |
2115 |
| -/// location pointed to by `dst`. |
2116 |
| -/// |
2117 |
| -/// # Notes |
2118 |
| -/// |
2119 |
| -/// Rust does not currently have a rigorously and formally defined memory model, |
2120 |
| -/// so the precise semantics of what "volatile" means here is subject to change |
2121 |
| -/// over time. That being said, the semantics will almost always end up pretty |
2122 |
| -/// similar to [C11's definition of volatile][c11]. |
2123 |
| -/// |
2124 |
| -/// The compiler shouldn't change the relative order or number of volatile |
2125 |
| -/// memory operations. However, volatile memory operations on zero-sized types |
2126 |
| -/// (e.g., if a zero-sized type is passed to `write_volatile`) are noops |
2127 |
| -/// and may be ignored. |
| 2122 | +/// Performs a volatile write of a memory location with the given value without reading or dropping |
| 2123 | +/// the old value. |
| 2124 | +/// |
| 2125 | +/// Rust does not currently have a rigorously and formally defined memory model, so the precise |
| 2126 | +/// semantics of what "volatile" means here is subject to change over time. That being said, the |
| 2127 | +/// semantics will almost always end up pretty similar to [C11's definition of volatile][c11]. |
| 2128 | +/// |
| 2129 | +/// Volatile operations are intended to act on I/O memory. As such, they are considered externally |
| 2130 | +/// observable events (just like syscalls), and are guaranteed to not be elided or reordered by the |
| 2131 | +/// compiler across other externally observable events. With this in mind, there are two cases of |
| 2132 | +/// usage that need to be distinguished: |
| 2133 | +/// |
| 2134 | +/// - When a volatile operation is used for memory inside an [allocation], it behaves exactly like |
| 2135 | +/// [`write()`], except for the additional guarantee that it won't be elided or reordered (see |
| 2136 | +/// above). This implies that the operation will actually access memory and not e.g. be lowered to |
| 2137 | +/// a register access or stack pop. Other than that, all the usual rules for memory accesses apply |
| 2138 | +/// (including provenance). In particular, just like in C, whether an operation is volatile has no |
| 2139 | +/// bearing whatsoever on questions involving concurrent access from multiple threads. Volatile |
| 2140 | +/// accesses behave exactly like non-atomic accesses in that regard. |
| 2141 | +/// |
| 2142 | +/// - Volatile operations, however, may also be used to access memory that is _outside_ of any Rust |
| 2143 | +/// allocation. In this use-case, the pointer does *not* have to be [valid] for writes. This is |
| 2144 | +/// typically used for CPU and peripheral registers that must be accessed via an I/O memory |
| 2145 | +/// mapping, most commonly at fixed addresses reserved by the hardware. These often have special |
| 2146 | +/// semantics associated to their manipulation, and cannot be used as general purpose memory. |
| 2147 | +/// Here, any address value is possible, including 0 and [`usize::MAX`], so long as the semantics |
| 2148 | +/// of such a write are well-defined by the target hardware. The provenance of the pointer is |
| 2149 | +/// irrelevant, and it can be created with [`without_provenance`]. The access must not trap. It |
| 2150 | +/// can cause side-effects, but those must not affect Rust-allocated memory in any way. This |
| 2151 | +/// access is still not considered [atomic], and as such it cannot be used for inter-thread |
| 2152 | +/// synchronization. |
| 2153 | +/// |
| 2154 | +/// Note that volatile memory operations on zero-sized types (e.g., if a zero-sized type is passed |
| 2155 | +/// to `write_volatile`) are noops and may be ignored. |
| 2156 | +/// |
| 2157 | +/// `write_volatile` does not drop the contents of `dst`. This is safe, but it could leak |
| 2158 | +/// allocations or resources, so care should be taken not to overwrite an object that should be |
| 2159 | +/// dropped when operating on Rust memory. |
| 2160 | +/// |
| 2161 | +/// Additionally, it does not drop `src`. Semantically, `src` is moved into the location pointed to |
| 2162 | +/// by `dst`. |
2128 | 2163 | ///
|
2129 | 2164 | /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
|
| 2165 | +/// [allocation]: crate::ptr#allocated-object |
| 2166 | +/// [atomic]: crate::sync::atomic#memory-model-for-atomic-accesses |
2130 | 2167 | ///
|
2131 | 2168 | /// # Safety
|
2132 | 2169 | ///
|
2133 | 2170 | /// Behavior is undefined if any of the following conditions are violated:
|
2134 | 2171 | ///
|
2135 |
| -/// * `dst` must be [valid] for writes. |
| 2172 | +/// * `dst` must be either [valid] for writes, or it must point to memory outside of all Rust |
| 2173 | +/// allocations and writing to that memory must: |
| 2174 | +/// - not trap, and |
| 2175 | +/// - not cause any memory inside a Rust allocation to be modified. |
2136 | 2176 | ///
|
2137 | 2177 | /// * `dst` must be properly aligned.
|
2138 | 2178 | ///
|
2139 | 2179 | /// Note that even if `T` has size `0`, the pointer must be properly aligned.
|
2140 | 2180 | ///
|
2141 | 2181 | /// [valid]: self#safety
|
2142 | 2182 | ///
|
2143 |
| -/// Just like in C, whether an operation is volatile has no bearing whatsoever |
2144 |
| -/// on questions involving concurrent access from multiple threads. Volatile |
2145 |
| -/// accesses behave exactly like non-atomic accesses in that regard. In particular, |
2146 |
| -/// a race between a `write_volatile` and any other operation (reading or writing) |
2147 |
| -/// on the same location is undefined behavior. |
2148 |
| -/// |
2149 | 2183 | /// # Examples
|
2150 | 2184 | ///
|
2151 | 2185 | /// Basic usage:
|
|
0 commit comments