Skip to content

Commit e55c95b

Browse files
committed
Move write_volatile to the volatile module
1 parent 8069abb commit e55c95b

File tree

2 files changed

+86
-81
lines changed

2 files changed

+86
-81
lines changed

library/core/src/ptr/mod.rs

Lines changed: 2 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,9 @@ pub use non_null::NonNull;
425425
mod unique;
426426
#[unstable(feature = "ptr_internals", issue = "none")]
427427
pub use unique::Unique;
428+
428429
#[stable(feature = "volatile", since = "1.9.0")]
429-
pub use volatile::read_volatile;
430+
pub use volatile::{read_volatile, write_volatile};
430431

431432
mod const_ptr;
432433
mod mut_ptr;
@@ -1672,86 +1673,6 @@ pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
16721673
}
16731674
}
16741675

1675-
/// Performs a volatile write of a memory location with the given value without
1676-
/// reading or dropping the old value.
1677-
///
1678-
/// Volatile operations are intended to act on I/O memory, and are guaranteed
1679-
/// to not be elided or reordered by the compiler across other volatile
1680-
/// operations.
1681-
///
1682-
/// `write_volatile` does not drop the contents of `dst`. This is safe, but it
1683-
/// could leak allocations or resources, so care should be taken not to overwrite
1684-
/// an object that should be dropped.
1685-
///
1686-
/// Additionally, it does not drop `src`. Semantically, `src` is moved into the
1687-
/// location pointed to by `dst`.
1688-
///
1689-
/// # Notes
1690-
///
1691-
/// Rust does not currently have a rigorously and formally defined memory model,
1692-
/// so the precise semantics of what "volatile" means here is subject to change
1693-
/// over time. That being said, the semantics will almost always end up pretty
1694-
/// similar to [C11's definition of volatile][c11].
1695-
///
1696-
/// The compiler shouldn't change the relative order or number of volatile
1697-
/// memory operations. However, volatile memory operations on zero-sized types
1698-
/// (e.g., if a zero-sized type is passed to `write_volatile`) are noops
1699-
/// and may be ignored.
1700-
///
1701-
/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
1702-
///
1703-
/// # Safety
1704-
///
1705-
/// Behavior is undefined if any of the following conditions are violated:
1706-
///
1707-
/// * `dst` must be [valid] for writes.
1708-
///
1709-
/// * `dst` must be properly aligned.
1710-
///
1711-
/// Note that even if `T` has size `0`, the pointer must be properly aligned.
1712-
///
1713-
/// [valid]: self#safety
1714-
///
1715-
/// Just like in C, whether an operation is volatile has no bearing whatsoever
1716-
/// on questions involving concurrent access from multiple threads. Volatile
1717-
/// accesses behave exactly like non-atomic accesses in that regard. In particular,
1718-
/// a race between a `write_volatile` and any other operation (reading or writing)
1719-
/// on the same location is undefined behavior.
1720-
///
1721-
/// # Examples
1722-
///
1723-
/// Basic usage:
1724-
///
1725-
/// ```
1726-
/// let mut x = 0;
1727-
/// let y = &mut x as *mut i32;
1728-
/// let z = 12;
1729-
///
1730-
/// unsafe {
1731-
/// std::ptr::write_volatile(y, z);
1732-
/// assert_eq!(std::ptr::read_volatile(y), 12);
1733-
/// }
1734-
/// ```
1735-
#[inline]
1736-
#[stable(feature = "volatile", since = "1.9.0")]
1737-
#[rustc_diagnostic_item = "ptr_write_volatile"]
1738-
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1739-
pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
1740-
// SAFETY: the caller must uphold the safety contract for `volatile_store`.
1741-
unsafe {
1742-
ub_checks::assert_unsafe_precondition!(
1743-
check_language_ub,
1744-
"ptr::write_volatile requires that the pointer argument is aligned and non-null",
1745-
(
1746-
addr: *mut () = dst as *mut (),
1747-
align: usize = align_of::<T>(),
1748-
is_zst: bool = T::IS_ZST,
1749-
) => ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
1750-
);
1751-
intrinsics::volatile_store(dst, src);
1752-
}
1753-
}
1754-
17551676
/// Align pointer `p`.
17561677
///
17571678
/// Calculate offset (in terms of elements of `size_of::<T>()` stride) that has to be applied

library/core/src/ptr/volatile.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,87 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
125125
}
126126
}
127127
}
128+
129+
/// Performs a volatile write of a memory location with the given value without
130+
/// reading or dropping the old value.
131+
///
132+
/// Volatile operations are intended to act on I/O memory, and are guaranteed
133+
/// to not be elided or reordered by the compiler across other volatile
134+
/// operations.
135+
///
136+
/// `write_volatile` does not drop the contents of `dst`. This is safe, but it
137+
/// could leak allocations or resources, so care should be taken not to overwrite
138+
/// an object that should be dropped.
139+
///
140+
/// Additionally, it does not drop `src`. Semantically, `src` is moved into the
141+
/// location pointed to by `dst`.
142+
///
143+
/// # Notes
144+
///
145+
/// Rust does not currently have a rigorously and formally defined memory model,
146+
/// so the precise semantics of what "volatile" means here is subject to change
147+
/// over time. That being said, the semantics will almost always end up pretty
148+
/// similar to [C11's definition of volatile][c11].
149+
///
150+
/// The compiler shouldn't change the relative order or number of volatile
151+
/// memory operations. However, volatile memory operations on zero-sized types
152+
/// (e.g., if a zero-sized type is passed to `write_volatile`) are noops
153+
/// and may be ignored.
154+
///
155+
/// [c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
156+
///
157+
/// # Safety
158+
///
159+
/// Behavior is undefined if any of the following conditions are violated:
160+
///
161+
/// * `dst` must be [valid] for writes.
162+
///
163+
/// * `dst` must be properly aligned.
164+
///
165+
/// Note that even if `T` has size `0`, the pointer must be properly aligned.
166+
///
167+
/// [valid]: self#safety
168+
///
169+
/// Just like in C, whether an operation is volatile has no bearing whatsoever
170+
/// on questions involving concurrent access from multiple threads. Volatile
171+
/// accesses behave exactly like non-atomic accesses in that regard. In particular,
172+
/// a race between a `write_volatile` and any other operation (reading or writing)
173+
/// on the same location is undefined behavior.
174+
///
175+
/// # Examples
176+
///
177+
/// Basic usage:
178+
///
179+
/// ```
180+
/// let mut x = 0;
181+
/// let y = &mut x as *mut i32;
182+
/// let z = 12;
183+
///
184+
/// unsafe {
185+
/// std::ptr::write_volatile(y, z);
186+
/// assert_eq!(std::ptr::read_volatile(y), 12);
187+
/// }
188+
/// ```
189+
#[inline]
190+
#[stable(feature = "volatile", since = "1.9.0")]
191+
#[cfg_attr(miri, track_caller)] // Even without panics, this helps for Miri backtraces
192+
#[rustc_diagnostic_item = "ptr_write_volatile"]
193+
pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
194+
// SAFETY: the caller must uphold the safety contract for `volatile_write`.
195+
unsafe {
196+
crate::ub_checks::assert_unsafe_precondition!(
197+
check_language_ub,
198+
"ptr::write_volatile requires that the pointer argument is aligned and non-null",
199+
(
200+
addr: *mut () = dst as *mut (),
201+
align: usize = crate::mem::align_of::<T>(),
202+
is_zst: bool = T::IS_ZST,
203+
) => crate::ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
204+
);
205+
cfg_match! {
206+
_ => {
207+
intrinsics::volatile_store(dst, src);
208+
}
209+
}
210+
}
211+
}

0 commit comments

Comments
 (0)