Skip to content

Commit 50d7716

Browse files
authored
Rollup merge of #78637 - mystor:atomic_ptr_bool, r=m-ou-se
Add fetch_update methods to AtomicBool and AtomicPtr These methods were stabilized for the integer atomics in #71843, but the methods were not added for the non-integer atomics `AtomicBool` and `AtomicPtr`.
2 parents fb7948e + 00f32e6 commit 50d7716

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

library/core/src/sync/atomic.rs

+125
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,64 @@ impl AtomicBool {
801801
pub fn as_mut_ptr(&self) -> *mut bool {
802802
self.v.get() as *mut bool
803803
}
804+
805+
/// Fetches the value, and applies a function to it that returns an optional
806+
/// new value. Returns a `Result` of `Ok(previous_value)` if the function
807+
/// returned `Some(_)`, else `Err(previous_value)`.
808+
///
809+
/// Note: This may call the function multiple times if the value has been
810+
/// changed from other threads in the meantime, as long as the function
811+
/// returns `Some(_)`, but the function will have been applied only once to
812+
/// the stored value.
813+
///
814+
/// `fetch_update` takes two [`Ordering`] arguments to describe the memory
815+
/// ordering of this operation. The first describes the required ordering for
816+
/// when the operation finally succeeds while the second describes the
817+
/// required ordering for loads. These correspond to the success and failure
818+
/// orderings of [`AtomicBool::compare_exchange`] respectively.
819+
///
820+
/// Using [`Acquire`] as success ordering makes the store part of this
821+
/// operation [`Relaxed`], and using [`Release`] makes the final successful
822+
/// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
823+
/// [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the
824+
/// success ordering.
825+
///
826+
/// **Note:** This method is only available on platforms that support atomic
827+
/// operations on `u8`.
828+
///
829+
/// # Examples
830+
///
831+
/// ```rust
832+
/// #![feature(atomic_fetch_update)]
833+
/// use std::sync::atomic::{AtomicBool, Ordering};
834+
///
835+
/// let x = AtomicBool::new(false);
836+
/// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(false));
837+
/// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(false));
838+
/// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(!x)), Ok(true));
839+
/// assert_eq!(x.load(Ordering::SeqCst), false);
840+
/// ```
841+
#[inline]
842+
#[unstable(feature = "atomic_fetch_update", reason = "recently added", issue = "78639")]
843+
#[cfg(target_has_atomic = "8")]
844+
pub fn fetch_update<F>(
845+
&self,
846+
set_order: Ordering,
847+
fetch_order: Ordering,
848+
mut f: F,
849+
) -> Result<bool, bool>
850+
where
851+
F: FnMut(bool) -> Option<bool>,
852+
{
853+
let mut prev = self.load(fetch_order);
854+
while let Some(next) = f(prev) {
855+
match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
856+
x @ Ok(_) => return x,
857+
Err(next_prev) => prev = next_prev,
858+
}
859+
}
860+
Err(prev)
861+
}
804862
}
805863

806864
#[cfg(target_has_atomic_load_store = "ptr")]
@@ -1123,6 +1181,73 @@ impl<T> AtomicPtr<T> {
11231181
}
11241182
}
11251183
}
1184+
1185+
/// Fetches the value, and applies a function to it that returns an optional
1186+
/// new value. Returns a `Result` of `Ok(previous_value)` if the function
1187+
/// returned `Some(_)`, else `Err(previous_value)`.
1188+
///
1189+
/// Note: This may call the function multiple times if the value has been
1190+
/// changed from other threads in the meantime, as long as the function
1191+
/// returns `Some(_)`, but the function will have been applied only once to
1192+
/// the stored value.
1193+
///
1194+
/// `fetch_update` takes two [`Ordering`] arguments to describe the memory
1195+
/// ordering of this operation. The first describes the required ordering for
1196+
/// when the operation finally succeeds while the second describes the
1197+
/// required ordering for loads. These correspond to the success and failure
1198+
/// orderings of [`AtomicPtr::compare_exchange`] respectively.
1199+
///
1200+
/// Using [`Acquire`] as success ordering makes the store part of this
1201+
/// operation [`Relaxed`], and using [`Release`] makes the final successful
1202+
/// load [`Relaxed`]. The (failed) load ordering can only be [`SeqCst`],
1203+
/// [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the
1204+
/// success ordering.
1205+
///
1206+
/// **Note:** This method is only available on platforms that support atomic
1207+
/// operations on pointers.
1208+
///
1209+
/// # Examples
1210+
///
1211+
/// ```rust
1212+
/// #![feature(atomic_fetch_update)]
1213+
/// use std::sync::atomic::{AtomicPtr, Ordering};
1214+
///
1215+
/// let ptr: *mut _ = &mut 5;
1216+
/// let some_ptr = AtomicPtr::new(ptr);
1217+
///
1218+
/// let new: *mut _ = &mut 10;
1219+
/// assert_eq!(some_ptr.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(ptr));
1220+
/// let result = some_ptr.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| {
1221+
/// if x == ptr {
1222+
/// Some(new)
1223+
/// } else {
1224+
/// None
1225+
/// }
1226+
/// });
1227+
/// assert_eq!(result, Ok(ptr));
1228+
/// assert_eq!(some_ptr.load(Ordering::SeqCst), new);
1229+
/// ```
1230+
#[inline]
1231+
#[unstable(feature = "atomic_fetch_update", reason = "recently added", issue = "78639")]
1232+
#[cfg(target_has_atomic = "ptr")]
1233+
pub fn fetch_update<F>(
1234+
&self,
1235+
set_order: Ordering,
1236+
fetch_order: Ordering,
1237+
mut f: F,
1238+
) -> Result<*mut T, *mut T>
1239+
where
1240+
F: FnMut(*mut T) -> Option<*mut T>,
1241+
{
1242+
let mut prev = self.load(fetch_order);
1243+
while let Some(next) = f(prev) {
1244+
match self.compare_exchange_weak(prev, next, set_order, fetch_order) {
1245+
x @ Ok(_) => return x,
1246+
Err(next_prev) => prev = next_prev,
1247+
}
1248+
}
1249+
Err(prev)
1250+
}
11261251
}
11271252

11281253
#[cfg(target_has_atomic_load_store = "8")]

0 commit comments

Comments
 (0)