Skip to content

Commit 1dd8818

Browse files
committed
AtomicT::fetch_update_infallible
1 parent 490b2cc commit 1dd8818

File tree

1 file changed

+186
-0
lines changed

1 file changed

+186
-0
lines changed

library/core/src/sync/atomic.rs

+186
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,66 @@ impl AtomicBool {
12031203
}
12041204
Err(prev)
12051205
}
1206+
1207+
/// Fetches the value, applies a function to it that it return a new value.
1208+
/// The new value is stored and the old value is returned.
1209+
///
1210+
/// Note: This may call the function multiple times if the value has been changed from other threads in
1211+
/// the meantime, but the function will have been applied only once to the stored value.
1212+
///
1213+
/// `fetch_update_infallible` takes two [`Ordering`] arguments to describe the memory
1214+
/// ordering of this operation. The first describes the required ordering for
1215+
/// when the operation finally succeeds while the second describes the
1216+
/// required ordering for loads. These correspond to the success and failure
1217+
/// orderings of [`AtomicBool::compare_exchange`] respectively.
1218+
///
1219+
/// Using [`Acquire`] as success ordering makes the store part
1220+
/// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
1221+
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
1222+
///
1223+
/// **Note:** This method is only available on platforms that support atomic operations on `u8`.
1224+
///
1225+
/// # Considerations
1226+
///
1227+
/// This method is not magic; it is not provided by the hardware.
1228+
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
1229+
/// In particular, this method will not circumvent the [ABA Problem].
1230+
///
1231+
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
1232+
///
1233+
/// # Examples
1234+
///
1235+
/// ```rust
1236+
/// #![feature(fetch_update_infallible)]
1237+
///
1238+
/// use std::sync::atomic::{AtomicBool, Ordering};
1239+
///
1240+
/// let x = AtomicBool::new(false);
1241+
/// assert_eq!(x.fetch_update_infallible(Ordering::SeqCst, Ordering::SeqCst, |x| !x), false);
1242+
/// assert_eq!(x.fetch_update_infallible(Ordering::SeqCst, Ordering::SeqCst, |x| !x), true);
1243+
/// assert_eq!(x.load(Ordering::SeqCst), false);
1244+
/// ```
1245+
#[inline]
1246+
#[unstable(feature = "fetch_update_infallible", issue = "none")]
1247+
#[cfg(target_has_atomic = "8")]
1248+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1249+
pub fn fetch_update_infallible<F>(
1250+
&self,
1251+
set_order: Ordering,
1252+
fetch_order: Ordering,
1253+
mut f: F,
1254+
) -> bool
1255+
where
1256+
F: FnMut(bool) -> bool,
1257+
{
1258+
let mut prev = self.load(fetch_order);
1259+
loop {
1260+
match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
1261+
Ok(x) => break x,
1262+
Err(next_prev) => prev = next_prev,
1263+
}
1264+
}
1265+
}
12061266
}
12071267

12081268
#[cfg(target_has_atomic_load_store = "ptr")]
@@ -1733,6 +1793,70 @@ impl<T> AtomicPtr<T> {
17331793
Err(prev)
17341794
}
17351795

1796+
/// Fetches the value, applies a function to it that it return a new value.
1797+
/// The new value is stored and the old value is returned.
1798+
///
1799+
/// Note: This may call the function multiple times if the value has been changed from other threads in
1800+
/// the meantime, but the function will have been applied only once to the stored value.
1801+
///
1802+
/// `fetch_update_infallible` takes two [`Ordering`] arguments to describe the memory
1803+
/// ordering of this operation. The first describes the required ordering for
1804+
/// when the operation finally succeeds while the second describes the
1805+
/// required ordering for loads. These correspond to the success and failure
1806+
/// orderings of [`AtomicPtr::compare_exchange`] respectively.
1807+
///
1808+
/// Using [`Acquire`] as success ordering makes the store part
1809+
/// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
1810+
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
1811+
///
1812+
/// **Note:** This method is only available on platforms that support atomic
1813+
/// operations on pointers.
1814+
///
1815+
/// # Considerations
1816+
///
1817+
/// This method is not magic; it is not provided by the hardware.
1818+
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
1819+
/// In particular, this method will not circumvent the [ABA Problem].
1820+
///
1821+
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
1822+
///
1823+
/// # Examples
1824+
///
1825+
/// ```rust
1826+
/// #![feature(fetch_update_infallible)]
1827+
///
1828+
/// use std::sync::atomic::{AtomicPtr, Ordering};
1829+
///
1830+
/// let ptr: *mut _ = &mut 5;
1831+
/// let some_ptr = AtomicPtr::new(ptr);
1832+
///
1833+
/// let new: *mut _ = &mut 10;
1834+
/// let result = some_ptr.fetch_update_infallible(Ordering::SeqCst, Ordering::SeqCst, |_| new);
1835+
/// assert_eq!(result, ptr);
1836+
/// assert_eq!(some_ptr.load(Ordering::SeqCst), new);
1837+
/// ```
1838+
#[inline]
1839+
#[unstable(feature = "fetch_update_infallible", issue = "none")]
1840+
#[cfg(target_has_atomic = "8")]
1841+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
1842+
pub fn fetch_update_infallible<F>(
1843+
&self,
1844+
set_order: Ordering,
1845+
fetch_order: Ordering,
1846+
mut f: F,
1847+
) -> *mut T
1848+
where
1849+
F: FnMut(*mut T) -> *mut T,
1850+
{
1851+
let mut prev = self.load(fetch_order);
1852+
loop {
1853+
match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
1854+
Ok(x) => break x,
1855+
Err(next_prev) => prev = next_prev,
1856+
}
1857+
}
1858+
}
1859+
17361860
/// Offsets the pointer's address by adding `val` (in units of `T`),
17371861
/// returning the previous pointer.
17381862
///
@@ -2913,6 +3037,68 @@ macro_rules! atomic_int {
29133037
Err(prev)
29143038
}
29153039

3040+
/// Fetches the value, applies a function to it that it return a new value.
3041+
/// The new value is stored and the old value is returned.
3042+
///
3043+
/// Note: This may call the function multiple times if the value has been changed from other threads in
3044+
/// the meantime, but the function will have been applied only once to the stored value.
3045+
///
3046+
/// `fetch_update_infallible` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
3047+
/// The first describes the required ordering for when the operation finally succeeds while the second
3048+
/// describes the required ordering for loads. These correspond to the success and failure orderings of
3049+
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange`]")]
3050+
/// respectively.
3051+
///
3052+
/// Using [`Acquire`] as success ordering makes the store part
3053+
/// of this operation [`Relaxed`], and using [`Release`] makes the final successful load
3054+
/// [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`].
3055+
///
3056+
/// **Note**: This method is only available on platforms that support atomic operations on
3057+
#[doc = concat!("[`", $s_int_type, "`].")]
3058+
///
3059+
/// # Considerations
3060+
///
3061+
/// This method is not magic; it is not provided by the hardware.
3062+
/// It is implemented in terms of
3063+
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
3064+
/// and suffers from the same drawbacks.
3065+
/// In particular, this method will not circumvent the [ABA Problem].
3066+
///
3067+
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
3068+
///
3069+
/// # Examples
3070+
///
3071+
/// ```rust
3072+
/// #![feature(fetch_update_infallible)]
3073+
#[doc = concat!($extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};")]
3074+
///
3075+
#[doc = concat!("let x = ", stringify!($atomic_type), "::new(7);")]
3076+
/// assert_eq!(x.fetch_update_infallible(Ordering::SeqCst, Ordering::SeqCst, |x| x + 1), 7);
3077+
/// assert_eq!(x.fetch_update_infallible(Ordering::SeqCst, Ordering::SeqCst, |x| x + 1), 8);
3078+
/// assert_eq!(x.load(Ordering::SeqCst), 9);
3079+
/// ```
3080+
#[inline]
3081+
#[unstable(feature = "fetch_update_infallible", issue = "none")]
3082+
#[$cfg_cas]
3083+
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
3084+
pub fn fetch_update_infallible<F>(
3085+
&self,
3086+
set_order: Ordering,
3087+
fetch_order: Ordering,
3088+
mut f: F,
3089+
) -> $int_type
3090+
where
3091+
F: FnMut($int_type) -> $int_type,
3092+
{
3093+
let mut prev = self.load(fetch_order);
3094+
loop {
3095+
match self.compare_exchange_weak(prev, f(prev), set_order, fetch_order) {
3096+
Ok(x) => break x,
3097+
Err(next_prev) => prev = next_prev,
3098+
}
3099+
}
3100+
}
3101+
29163102
/// Maximum with the current value.
29173103
///
29183104
/// Finds the maximum of the current value and the argument `val`, and

0 commit comments

Comments
 (0)