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