|
17 | 17 | //! |
18 | 18 | //! * For memory accesses of [size zero][zst], *every* pointer is valid, including the [null] |
19 | 19 | //! pointer. The following points are only concerned with non-zero-sized accesses. |
| 20 | +//! * Volatile operations may act on memory outside Rust allocations, such as |
| 21 | +//! I/O registers at hard-coded addresses. This case is exempt from the rules |
| 22 | +//! below, but it does have its own rules documented at each volatile operation. |
20 | 23 | //! * A [null] pointer is *never* valid. |
21 | 24 | //! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer be |
22 | 25 | //! *dereferenceable*. The [provenance] of the pointer is used to determine which [allocated |
|
28 | 31 | //! undefined behavior to perform two concurrent accesses to the same location from different |
29 | 32 | //! threads unless both accesses only read from memory. Notice that this explicitly |
30 | 33 | //! includes [`read_volatile`] and [`write_volatile`]: Volatile accesses cannot |
31 | | -//! be used for inter-thread synchronization. |
| 34 | +//! be used for inter-thread synchronization, regardless of whether it is acting on |
| 35 | +//! Rust memory or not. |
32 | 36 | //! * The result of casting a reference to a pointer is valid for as long as the |
33 | 37 | //! underlying object is live and no reference (just raw pointers) is used to |
34 | 38 | //! access the same memory. That is, reference and pointer accesses cannot be |
@@ -1744,54 +1748,73 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) { |
1744 | 1748 | } |
1745 | 1749 | } |
1746 | 1750 |
|
1747 | | -/// Performs a volatile read of the value from `src` without moving it. This |
1748 | | -/// leaves the memory in `src` unchanged. |
1749 | | -/// |
1750 | | -/// Volatile operations are intended to act on I/O memory, and are guaranteed |
1751 | | -/// to not be elided or reordered by the compiler across other volatile |
1752 | | -/// operations. |
1753 | | -/// |
1754 | | -/// # Notes |
| 1751 | +/// Performs a volatile read of the value from `src` without moving it. |
1755 | 1752 | /// |
1756 | 1753 | /// Rust does not currently have a rigorously and formally defined memory model, |
1757 | 1754 | /// so the precise semantics of what "volatile" means here is subject to change |
1758 | 1755 | /// over time. That being said, the semantics will almost always end up pretty |
1759 | 1756 | /// similar to [C11's definition of volatile][c11]. |
1760 | 1757 | /// |
| 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 | +/// |
1761 | 1786 | /// The compiler shouldn't change the relative order or number of volatile |
1762 | 1787 | /// memory operations. However, volatile memory operations on zero-sized types |
1763 | 1788 | /// (e.g., if a zero-sized type is passed to `read_volatile`) are noops |
1764 | 1789 | /// and may be ignored. |
1765 | 1790 | /// |
1766 | 1791 | /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf |
| 1792 | +/// [allocation]: crate::ptr#allocated-object |
1767 | 1793 | /// |
1768 | 1794 | /// # Safety |
1769 | 1795 | /// |
1770 | 1796 | /// Behavior is undefined if any of the following conditions are violated: |
1771 | 1797 | /// |
1772 | | -/// * `src` must be [valid] for reads. |
| 1798 | +/// * `src` must be readable without trapping. |
1773 | 1799 | /// |
1774 | 1800 | /// * `src` must be properly aligned. |
1775 | 1801 | /// |
1776 | | -/// * `src` must point to a properly initialized value of type `T`. |
| 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. |
1777 | 1807 | /// |
1778 | 1808 | /// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of |
1779 | 1809 | /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned |
1780 | 1810 | /// value and the value at `*src` can [violate memory safety][read-ownership]. |
1781 | | -/// However, storing non-[`Copy`] types in volatile memory is almost certainly |
1782 | | -/// incorrect. |
| 1811 | +/// However, modeling volatile memory with non-[`Copy`] types is almost |
| 1812 | +/// certainly incorrect. |
1783 | 1813 | /// |
1784 | 1814 | /// Note that even if `T` has size `0`, the pointer must be properly aligned. |
1785 | 1815 | /// |
1786 | | -/// [valid]: self#safety |
1787 | 1816 | /// [read-ownership]: read#ownership-of-the-returned-value |
1788 | 1817 | /// |
1789 | | -/// Just like in C, whether an operation is volatile has no bearing whatsoever |
1790 | | -/// on questions involving concurrent access from multiple threads. Volatile |
1791 | | -/// accesses behave exactly like non-atomic accesses in that regard. In particular, |
1792 | | -/// a race between a `read_volatile` and any write operation to the same location |
1793 | | -/// is undefined behavior. |
1794 | | -/// |
1795 | 1818 | /// # Examples |
1796 | 1819 | /// |
1797 | 1820 | /// Basic usage: |
@@ -1826,48 +1849,70 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T { |
1826 | 1849 | /// Performs a volatile write of a memory location with the given value without |
1827 | 1850 | /// reading or dropping the old value. |
1828 | 1851 | /// |
1829 | | -/// Volatile operations are intended to act on I/O memory, and are guaranteed |
1830 | | -/// to not be elided or reordered by the compiler across other volatile |
1831 | | -/// operations. |
1832 | | -/// |
1833 | | -/// `write_volatile` does not drop the contents of `dst`. This is safe, but it |
1834 | | -/// could leak allocations or resources, so care should be taken not to overwrite |
1835 | | -/// an object that should be dropped. |
1836 | | -/// |
1837 | | -/// Additionally, it does not drop `src`. Semantically, `src` is moved into the |
1838 | | -/// location pointed to by `dst`. |
1839 | | -/// |
1840 | | -/// # Notes |
1841 | | -/// |
1842 | 1852 | /// Rust does not currently have a rigorously and formally defined memory model, |
1843 | 1853 | /// so the precise semantics of what "volatile" means here is subject to change |
1844 | 1854 | /// over time. That being said, the semantics will almost always end up pretty |
1845 | 1855 | /// similar to [C11's definition of volatile][c11]. |
1846 | 1856 | /// |
| 1857 | +/// Volatile operations are intended to act on I/O memory, and are guaranteed |
| 1858 | +/// to not be elided or reordered by the compiler across other volatile |
| 1859 | +/// operations. With this in mind, there are two cases of usage that need to |
| 1860 | +/// be distinguished: |
| 1861 | +/// |
| 1862 | +/// - When a volatile operation is used for memory inside an [allocation], all |
| 1863 | +/// the typical restrictions of Rust-allocated memory apply, meaning things |
| 1864 | +/// like data races and mutable aliasing remain as undefined behavior. In |
| 1865 | +/// addition, the volatile rule that the operation won't be elided or |
| 1866 | +/// reordered applies, such that the operation will access memory and not e.g. |
| 1867 | +/// be lowered to a register access or stack pop. The memory in `src` should |
| 1868 | +/// remain unchanged. Just like in C, whether an operation is volatile has no |
| 1869 | +/// bearing whatsoever on questions involving concurrent access from multiple |
| 1870 | +/// threads. Volatile accesses behave exactly like non-atomic accesses in that |
| 1871 | +/// regard. All this is because this kind of target-memory may be used from |
| 1872 | +/// safe code at any time, and its validity assumptions must not be violated. |
| 1873 | +/// |
| 1874 | +/// - Volatile operations, however, provide a conditionally valid way to access |
| 1875 | +/// memory that is _outside_ of any allocation. The main use-case is CPU and |
| 1876 | +/// peripheral registers that must be accessed via an I/O memory mapping, most |
| 1877 | +/// commonly at fixed addresses reserved by the hardware. These often have |
| 1878 | +/// special semantics associated to their manipulation, and cannot be used as |
| 1879 | +/// general purpose memory. Here, any address value is possible, from 0 to |
| 1880 | +/// [`usize::MAX`], so long as its semantics are well-defined by the target |
| 1881 | +/// hardware. The access is restricted to not trap/interrupt. It can (and |
| 1882 | +/// usually will) cause side-effects, but note they shouldn't affect |
| 1883 | +/// Rust-allocated memory in any way. |
| 1884 | +/// |
1847 | 1885 | /// The compiler shouldn't change the relative order or number of volatile |
1848 | 1886 | /// memory operations. However, volatile memory operations on zero-sized types |
1849 | 1887 | /// (e.g., if a zero-sized type is passed to `write_volatile`) are noops |
1850 | 1888 | /// and may be ignored. |
1851 | 1889 | /// |
| 1890 | +/// `write_volatile` does not drop the contents of `dst`. This is safe, but it |
| 1891 | +/// could leak allocations or resources, so care should be taken not to |
| 1892 | +/// overwrite an object that should be dropped when operating on Rust memory. |
| 1893 | +/// |
| 1894 | +/// Additionally, it does not drop `src`. Semantically, `src` is moved into the |
| 1895 | +/// location pointed to by `dst`. |
| 1896 | +/// |
1852 | 1897 | /// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf |
| 1898 | +/// [allocation]: crate::ptr#allocated-object |
1853 | 1899 | /// |
1854 | 1900 | /// # Safety |
1855 | 1901 | /// |
1856 | 1902 | /// Behavior is undefined if any of the following conditions are violated: |
1857 | 1903 | /// |
1858 | | -/// * `dst` must be [valid] for writes. |
| 1904 | +/// * `dst` must be writable without trapping. |
1859 | 1905 | /// |
1860 | 1906 | /// * `dst` must be properly aligned. |
1861 | 1907 | /// |
1862 | | -/// Note that even if `T` has size `0`, the pointer must be properly aligned. |
| 1908 | +/// * `src` must be a properly initialized value of type `T`. |
1863 | 1909 | /// |
1864 | | -/// [valid]: self#safety |
| 1910 | +/// * If operating on an allocation, no Rust memory outside of `dst` may be |
| 1911 | +/// modified. |
1865 | 1912 | /// |
1866 | | -/// Just like in C, whether an operation is volatile has no bearing whatsoever |
1867 | | -/// on questions involving concurrent access from multiple threads. Volatile |
1868 | | -/// accesses behave exactly like non-atomic accesses in that regard. In particular, |
1869 | | -/// a race between a `write_volatile` and any other operation (reading or writing) |
1870 | | -/// on the same location is undefined behavior. |
| 1913 | +/// * If not operating on an allocation, no Rust memory may be affected. |
| 1914 | +/// |
| 1915 | +/// Note that even if `T` has size `0`, the pointer must be properly aligned. |
1871 | 1916 | /// |
1872 | 1917 | /// # Examples |
1873 | 1918 | /// |
|
0 commit comments