Skip to content

Commit c94ee9b

Browse files
committed
Move write_volatile to the volatile module
1 parent cd96f3f commit c94ee9b

File tree

3 files changed

+76
-82
lines changed

3 files changed

+76
-82
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: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ macro_rules! read_volatile {
1515
"ptr::read_volatile requires that the pointer argument is aligned and non-null",
1616
(
1717
addr: *const () = $name as *const (),
18-
align: usize = align_of::<T>(),
18+
align: usize = crate::mem::align_of::<T>(),
1919
is_zst: bool = T::IS_ZST,
2020
) => crate::ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
2121
);
@@ -73,3 +73,34 @@ cfg_match! {
7373
read_volatile!(src, intrinsics::volatile_load(src));
7474
}
7575
}
76+
77+
macro_rules! write_volatile {
78+
($dst:ident, $src:ident, $express:expr) => {
79+
#[inline]
80+
#[stable(feature = "volatile", since = "1.9.0")]
81+
#[cfg_attr(miri, track_caller)] // Even without panics, this helps for Miri backtraces
82+
#[rustc_diagnostic_item = "ptr_write_volatile"]
83+
#[doc = "write_volatile.md"]
84+
pub unsafe fn write_volatile<T>($dst: *mut T, $src: T) {
85+
// SAFETY: the caller must uphold the safety contract for `volatile_write`.
86+
unsafe {
87+
crate::ub_checks::assert_unsafe_precondition!(
88+
check_language_ub,
89+
"ptr::write_volatile requires that the pointer argument is aligned and non-null",
90+
(
91+
addr: *mut () = $dst as *mut (),
92+
align: usize = crate::mem::align_of::<T>(),
93+
is_zst: bool = T::IS_ZST,
94+
) => crate::ub_checks::maybe_is_aligned_and_not_null(addr, align, is_zst)
95+
);
96+
$express
97+
}
98+
}
99+
}
100+
}
101+
102+
cfg_match! {
103+
_ => {
104+
write_volatile!(dst, src, intrinsics::volatile_store(dst, src));
105+
}
106+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Performs a volatile write of a memory location with the given value without
2+
reading or dropping the old value.
3+
Volatile operations are intended to act on I/O memory, and are guaranteed
4+
to not be elided or reordered by the compiler across other volatile
5+
operations.
6+
`write_volatile` does not drop the contents of `dst`. This is safe, but it
7+
could leak allocations or resources, so care should be taken not to overwrite
8+
an object that should be dropped.
9+
Additionally, it does not drop `src`. Semantically, `src` is moved into the
10+
location pointed to by `dst`.
11+
# Notes
12+
Rust does not currently have a rigorously and formally defined memory model,
13+
so the precise semantics of what "volatile" means here is subject to change
14+
over time. That being said, the semantics will almost always end up pretty
15+
similar to [C11's definition of volatile][c11].
16+
The compiler shouldn't change the relative order or number of volatile
17+
memory operations. However, volatile memory operations on zero-sized types
18+
(e.g., if a zero-sized type is passed to `write_volatile`) are noops
19+
and may be ignored.
20+
[c11]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
21+
# Safety
22+
Behavior is undefined if any of the following conditions are violated:
23+
* `dst` must be [valid] for writes.
24+
* `dst` must be properly aligned.
25+
Note that even if `T` has size `0`, the pointer must be properly aligned.
26+
[valid]: self#safety
27+
Just like in C, whether an operation is volatile has no bearing whatsoever
28+
on questions involving concurrent access from multiple threads. Volatile
29+
accesses behave exactly like non-atomic accesses in that regard. In particular,
30+
a race between a `write_volatile` and any other operation (reading or writing)
31+
on the same location is undefined behavior.
32+
# Examples
33+
Basic usage:
34+
```
35+
let mut x = 0;
36+
let y = &mut x as *mut i32;
37+
let z = 12;
38+
unsafe {
39+
std::ptr::write_volatile(y, z);
40+
assert_eq!(std::ptr::read_volatile(y), 12);
41+
}
42+
```

0 commit comments

Comments
 (0)