Skip to content

Commit

Permalink
Rollup merge of rust-lang#71843 - sfackler:cas-loop-cleanup, r=dtolnay
Browse files Browse the repository at this point in the history
Tweak and stabilize AtomicN::fetch_update

The fetch_update method implements a compare-and-swap loop to update the value in an atomic to an arbitrary value computed by a closure.

I've applied a few tweaks suggested by @mystor in this comment on the tracking issue: rust-lang#48655 (comment). Specifically, the load and store ordering arguments have been swapped to match with the orderings of `compare_exchange`, and the closure has been moved from the first to last argument.

Moving the closure to the last argument is a change away from other methods on the atomic types which place the ordering(s) last, but matches with the broad convention that closure arguments come last in functions. In particular, rustfmt style lays calls with multi-line closures out more cleanly when the closure comes last.
  • Loading branch information
JohnTitor committed May 28, 2020
2 parents 53bd7de + 31c8205 commit 65951ad
Showing 1 changed file with 11 additions and 15 deletions.
26 changes: 11 additions & 15 deletions src/libcore/sync/atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1807,13 +1807,12 @@ new value. Returns a `Result` of `Ok(previous_value)` if the function returned `
Note: This may call the function multiple times if the value has been changed from other threads in
the meantime, as long as the function returns `Some(_)`, but the function will have been applied
but once to the stored value.
only once to the stored value.
`fetch_update` takes two [`Ordering`] arguments to describe the memory
ordering of this operation. The first describes the required ordering for loads
and failed updates while the second describes the required ordering when the
operation finally succeeds. Beware that this is different from the two
modes in [`compare_exchange`]!
`fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
The first describes the required ordering for when the operation finally succeeds while the second
describes the required ordering for loads. These correspond to the success and failure orderings of
[`compare_exchange`] respectively.
Using [`Acquire`] as success ordering makes the store part
of this operation [`Relaxed`], and using [`Release`] makes the final successful load
Expand All @@ -1831,24 +1830,21 @@ and must be equivalent to or weaker than the success ordering.
# Examples
```rust
#![feature(no_more_cas)]
", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
let x = ", stringify!($atomic_type), "::new(7);
assert_eq!(x.fetch_update(|_| None, Ordering::SeqCst, Ordering::SeqCst), Err(7));
assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(7));
assert_eq!(x.fetch_update(|x| Some(x + 1), Ordering::SeqCst, Ordering::SeqCst), Ok(8));
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7));
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7));
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8));
assert_eq!(x.load(Ordering::SeqCst), 9);
```"),
#[inline]
#[unstable(feature = "no_more_cas",
reason = "no more CAS loops in user code",
issue = "48655")]
#[stable(feature = "no_more_cas", since = "1.45.0")]
#[$cfg_cas]
pub fn fetch_update<F>(&self,
mut f: F,
set_order: Ordering,
fetch_order: Ordering,
set_order: Ordering) -> Result<$int_type, $int_type>
mut f: F) -> Result<$int_type, $int_type>
where F: FnMut($int_type) -> Option<$int_type> {
let mut prev = self.load(fetch_order);
while let Some(next) = f(prev) {
Expand Down

0 comments on commit 65951ad

Please sign in to comment.