Skip to content

Commit 041f666

Browse files
authored
Rollup merge of #108540 - WaffleLapkin:atomic_thingy_from_thingy_pointer, r=m-ou-se
Add `Atomic*::from_ptr` This PR adds functions in the following form to all atomic types: ```rust impl AtomicT { pub const unsafe fn from_ptr<'a>(ptr: *mut T) -> &'a AtomicT; } ``` r? `@m-ou-se` (we've talked about it before) I'm not sure about docs & safety requirements, I'd appreciate some feedback on them.
2 parents 188ed14 + a2baba0 commit 041f666

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

Diff for: library/core/src/sync/atomic.rs

+135
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,50 @@ impl AtomicBool {
305305
AtomicBool { v: UnsafeCell::new(v as u8) }
306306
}
307307

308+
/// Creates a new `AtomicBool` from a pointer.
309+
///
310+
/// # Examples
311+
///
312+
/// ```
313+
/// #![feature(atomic_from_ptr, pointer_is_aligned)]
314+
/// use std::sync::atomic::{self, AtomicBool};
315+
/// use std::mem::align_of;
316+
///
317+
/// // Get a pointer to an allocated value
318+
/// let ptr: *mut bool = Box::into_raw(Box::new(false));
319+
///
320+
/// assert!(ptr.is_aligned_to(align_of::<AtomicBool>()));
321+
///
322+
/// {
323+
/// // Create an atomic view of the allocated value
324+
/// let atomic = unsafe { AtomicBool::from_ptr(ptr) };
325+
///
326+
/// // Use `atomic` for atomic operations, possibly share it with other threads
327+
/// atomic.store(true, atomic::Ordering::Relaxed);
328+
/// }
329+
///
330+
/// // It's ok to non-atomically access the value behind `ptr`,
331+
/// // since the reference to the atomic ended its lifetime in the block above
332+
/// assert_eq!(unsafe { *ptr }, true);
333+
///
334+
/// // Deallocate the value
335+
/// unsafe { drop(Box::from_raw(ptr)) }
336+
/// ```
337+
///
338+
/// # Safety
339+
///
340+
/// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can be bigger than `align_of::<bool>()`).
341+
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
342+
/// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`.
343+
///
344+
/// [valid]: crate::ptr#safety
345+
#[unstable(feature = "atomic_from_ptr", issue = "108652")]
346+
#[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")]
347+
pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
348+
// SAFETY: guaranteed by the caller
349+
unsafe { &*ptr.cast() }
350+
}
351+
308352
/// Returns a mutable reference to the underlying [`bool`].
309353
///
310354
/// This is safe because the mutable reference guarantees that no other threads are
@@ -1017,6 +1061,50 @@ impl<T> AtomicPtr<T> {
10171061
AtomicPtr { p: UnsafeCell::new(p) }
10181062
}
10191063

1064+
/// Creates a new `AtomicPtr` from a pointer.
1065+
///
1066+
/// # Examples
1067+
///
1068+
/// ```
1069+
/// #![feature(atomic_from_ptr, pointer_is_aligned)]
1070+
/// use std::sync::atomic::{self, AtomicPtr};
1071+
/// use std::mem::align_of;
1072+
///
1073+
/// // Get a pointer to an allocated value
1074+
/// let ptr: *mut *mut u8 = Box::into_raw(Box::new(std::ptr::null_mut()));
1075+
///
1076+
/// assert!(ptr.is_aligned_to(align_of::<AtomicPtr<u8>>()));
1077+
///
1078+
/// {
1079+
/// // Create an atomic view of the allocated value
1080+
/// let atomic = unsafe { AtomicPtr::from_ptr(ptr) };
1081+
///
1082+
/// // Use `atomic` for atomic operations, possibly share it with other threads
1083+
/// atomic.store(std::ptr::NonNull::dangling().as_ptr(), atomic::Ordering::Relaxed);
1084+
/// }
1085+
///
1086+
/// // It's ok to non-atomically access the value behind `ptr`,
1087+
/// // since the reference to the atomic ended its lifetime in the block above
1088+
/// assert!(!unsafe { *ptr }.is_null());
1089+
///
1090+
/// // Deallocate the value
1091+
/// unsafe { drop(Box::from_raw(ptr)) }
1092+
/// ```
1093+
///
1094+
/// # Safety
1095+
///
1096+
/// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this can be bigger than `align_of::<*mut T>()`).
1097+
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
1098+
/// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`.
1099+
///
1100+
/// [valid]: crate::ptr#safety
1101+
#[unstable(feature = "atomic_from_ptr", issue = "108652")]
1102+
#[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")]
1103+
pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
1104+
// SAFETY: guaranteed by the caller
1105+
unsafe { &*ptr.cast() }
1106+
}
1107+
10201108
/// Returns a mutable reference to the underlying pointer.
10211109
///
10221110
/// This is safe because the mutable reference guarantees that no other threads are
@@ -1958,6 +2046,53 @@ macro_rules! atomic_int {
19582046
Self {v: UnsafeCell::new(v)}
19592047
}
19602048

2049+
/// Creates a new reference to an atomic integer from a pointer.
2050+
///
2051+
/// # Examples
2052+
///
2053+
/// ```
2054+
/// #![feature(atomic_from_ptr, pointer_is_aligned)]
2055+
#[doc = concat!($extra_feature, "use std::sync::atomic::{self, ", stringify!($atomic_type), "};")]
2056+
/// use std::mem::align_of;
2057+
///
2058+
/// // Get a pointer to an allocated value
2059+
#[doc = concat!("let ptr: *mut ", stringify!($int_type), " = Box::into_raw(Box::new(0));")]
2060+
///
2061+
#[doc = concat!("assert!(ptr.is_aligned_to(align_of::<", stringify!($atomic_type), ">()));")]
2062+
///
2063+
/// {
2064+
/// // Create an atomic view of the allocated value
2065+
// SAFETY: this is a doc comment, tidy, it can't hurt you (also guaranteed by the construction of `ptr` and the assert above)
2066+
#[doc = concat!(" let atomic = unsafe {", stringify!($atomic_type), "::from_ptr(ptr) };")]
2067+
///
2068+
/// // Use `atomic` for atomic operations, possibly share it with other threads
2069+
/// atomic.store(1, atomic::Ordering::Relaxed);
2070+
/// }
2071+
///
2072+
/// // It's ok to non-atomically access the value behind `ptr`,
2073+
/// // since the reference to the atomic ended its lifetime in the block above
2074+
/// assert_eq!(unsafe { *ptr }, 1);
2075+
///
2076+
/// // Deallocate the value
2077+
/// unsafe { drop(Box::from_raw(ptr)) }
2078+
/// ```
2079+
///
2080+
/// # Safety
2081+
///
2082+
/// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can be bigger than `align_of::<bool>()`).
2083+
#[doc = concat!(" * `ptr` must be aligned to `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this can be bigger than `align_of::<", stringify!($int_type), ">()`).")]
2084+
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
2085+
/// * The value behind `ptr` must not be accessed through non-atomic operations for the whole lifetime `'a`.
2086+
///
2087+
/// [valid]: crate::ptr#safety
2088+
#[unstable(feature = "atomic_from_ptr", issue = "108652")]
2089+
#[rustc_const_unstable(feature = "atomic_from_ptr", issue = "108652")]
2090+
pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {
2091+
// SAFETY: guaranteed by the caller
2092+
unsafe { &*ptr.cast() }
2093+
}
2094+
2095+
19612096
/// Returns a mutable reference to the underlying integer.
19622097
///
19632098
/// This is safe because the mutable reference guarantees that no other threads are

0 commit comments

Comments
 (0)