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