From: "Benno Lossin" <lossin@kernel.org>
To: "Boqun Feng" <boqun.feng@gmail.com>,
<linux-kernel@vger.kernel.org>, <rust-for-linux@vger.kernel.org>,
<lkmm@lists.linux.dev>, <linux-arch@vger.kernel.org>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Will Deacon" <will@kernel.org>,
"Peter Zijlstra" <peterz@infradead.org>,
"Mark Rutland" <mark.rutland@arm.com>,
"Wedson Almeida Filho" <wedsonaf@gmail.com>,
"Viresh Kumar" <viresh.kumar@linaro.org>,
"Lyude Paul" <lyude@redhat.com>, "Ingo Molnar" <mingo@kernel.org>,
"Mitchell Levy" <levymitchell0@gmail.com>,
"Paul E. McKenney" <paulmck@kernel.org>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Linus Torvalds" <torvalds@linux-foundation.org>,
"Thomas Gleixner" <tglx@linutronix.de>,
"Alan Stern" <stern@rowland.harvard.edu>
Subject: Re: [PATCH v6 5/9] rust: sync: atomic: Add atomic {cmp,}xchg operations
Date: Fri, 11 Jul 2025 10:42:14 +0200 [thread overview]
Message-ID: <DB93BZ5X63W4.2N48BXJEJOQ3F@kernel.org> (raw)
In-Reply-To: <20250710060052.11955-6-boqun.feng@gmail.com>
On Thu Jul 10, 2025 at 8:00 AM CEST, Boqun Feng wrote:
> xchg() and cmpxchg() are basic operations on atomic. Provide these based
> on C APIs.
>
> Note that cmpxchg() use the similar function signature as
> compare_exchange() in Rust std: returning a `Result`, `Ok(old)` means
> the operation succeeds and `Err(old)` means the operation fails.
>
> Reviewed-by: Alice Ryhl <aliceryhl@google.com>
> Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
> ---
> rust/kernel/sync/atomic/generic.rs | 170 +++++++++++++++++++++++++++++
> 1 file changed, 170 insertions(+)
>
> diff --git a/rust/kernel/sync/atomic/generic.rs b/rust/kernel/sync/atomic/generic.rs
> index e044fe21b128..1beb802843ee 100644
> --- a/rust/kernel/sync/atomic/generic.rs
> +++ b/rust/kernel/sync/atomic/generic.rs
> @@ -287,3 +287,173 @@ pub fn store<Ordering: ReleaseOrRelaxed>(&self, v: T, _: Ordering) {
> };
> }
> }
> +
> +impl<T: AllowAtomic> Atomic<T>
> +where
> + T::Repr: AtomicHasXchgOps,
> +{
> + /// Atomic exchange.
Please also give a longer sentence describing the operation.
> + ///
> + /// # Examples
> + ///
> + /// ```rust
> + /// use kernel::sync::atomic::{Atomic, Acquire, Relaxed};
> + ///
> + /// let x = Atomic::new(42);
> + ///
> + /// assert_eq!(42, x.xchg(52, Acquire));
> + /// assert_eq!(52, x.load(Relaxed));
> + /// ```
> + #[doc(alias("atomic_xchg", "atomic64_xchg", "swap"))]
> + #[inline(always)]
> + pub fn xchg<Ordering: Any>(&self, v: T, _: Ordering) -> T {
> + let v = into_repr(v);
> + // CAST: Per the safety requirement of `AllowAtomic`, a valid pointer of `T` is also a
> + // valid pointer of `T::Repr`.
Ditto as the last patch (I'm not going to mention the others).
> + let a = self.as_ptr().cast::<T::Repr>();
> +
> + // SAFETY:
> + // - For calling the atomic_xchg*() function:
> + // - `a` is a valid pointer for the function per the CAST justification above.
> + // - Per the type guarantees, the following atomic operation won't cause data races.
> + // - For extra safety requirement of usage on pointers returned by `self.as_ptr()`:
> + // - Atomic operations are used here.
> + // - For the bit validity of `Atomic<T>`:
> + // - `v` is a valid bit pattern of `T`, so it's sound to store it in an `Atomic<T>`.
> + let ret = unsafe {
> + match Ordering::TYPE {
> + OrderingType::Full => T::Repr::atomic_xchg(a, v),
> + OrderingType::Acquire => T::Repr::atomic_xchg_acquire(a, v),
> + OrderingType::Release => T::Repr::atomic_xchg_release(a, v),
> + OrderingType::Relaxed => T::Repr::atomic_xchg_relaxed(a, v),
> + }
> + };
> +
> + // SAFETY: The atomic variable holds a valid `T`, so `ret` is a valid bit pattern of `T`,
> + // therefore it's safe to call `from_repr()`.
> + unsafe { from_repr(ret) }
> + }
> +
> + /// Atomic compare and exchange.
Also longer description for this function.
> + ///
> + /// Compare: The comparison is done via the byte level comparison between the atomic variables
> + /// with the `old` value.
> + ///
> + /// Ordering: When succeeds, provides the corresponding ordering as the `Ordering` type
> + /// parameter indicates, and a failed one doesn't provide any ordering, the read part of a
> + /// failed cmpxchg should be treated as a relaxed read.
Why did you chose to say "should be treated" can't you say it is a
relaxed read? What would the difference be between those two be?
> + ///
> + /// Returns `Ok(value)` if cmpxchg succeeds, and `value` is guaranteed to be equal to `old`,
> + /// otherwise returns `Err(value)`, and `value` is the value of the atomic variable when
> + /// cmpxchg was happening.
s/cmpxchg was happening/`cmpxchg` was executed/
> + ///
> + /// # Examples
> + ///
> + /// ```rust
> + /// use kernel::sync::atomic::{Atomic, Full, Relaxed};
> + ///
> + /// let x = Atomic::new(42);
> + ///
> + /// // Checks whether cmpxchg succeeded.
> + /// let success = x.cmpxchg(52, 64, Relaxed).is_ok();
> + /// # assert!(!success);
> + ///
> + /// // Checks whether cmpxchg failed.
> + /// let failure = x.cmpxchg(52, 64, Relaxed).is_err();
> + /// # assert!(failure);
> + ///
> + /// // Uses the old value if failed, probably re-try cmpxchg.
> + /// match x.cmpxchg(52, 64, Relaxed) {
> + /// Ok(_) => { },
> + /// Err(old) => {
> + /// // do something with `old`.
> + /// # assert_eq!(old, 42);
> + /// }
> + /// }
> + ///
> + /// // Uses the latest value regardlessly, same as atomic_cmpxchg() in C.
> + /// let latest = x.cmpxchg(42, 64, Full).unwrap_or_else(|old| old);
> + /// # assert_eq!(42, latest);
> + /// assert_eq!(64, x.load(Relaxed));
> + /// ```
> + #[doc(alias(
> + "atomic_cmpxchg",
> + "atomic64_cmpxchg",
> + "atomic_try_cmpxchg",
> + "atomic64_try_cmpxchg",
> + "compare_exchange"
> + ))]
> + #[inline(always)]
> + pub fn cmpxchg<Ordering: Any>(&self, mut old: T, new: T, o: Ordering) -> Result<T, T> {
> + // Note on code generation:
> + //
> + // try_cmpxchg() is used to implement cmpxchg(), and if the helper functions are inlined,
> + // the compiler is able to figure out that branch is not needed if the users don't care
> + // about whether the operation succeeds or not. One exception is on x86, due to commit
> + // 44fe84459faf ("locking/atomic: Fix atomic_try_cmpxchg() semantics"), the
> + // atomic_try_cmpxchg() on x86 has a branch even if the caller doesn't care about the
> + // success of cmpxchg and only wants to use the old value. For example, for code like:
> + //
> + // let latest = x.cmpxchg(42, 64, Full).unwrap_or_else(|old| old);
> + //
> + // It will still generate code:
> + //
> + // movl $0x40, %ecx
> + // movl $0x34, %eax
> + // lock
> + // cmpxchgl %ecx, 0x4(%rsp)
> + // jne 1f
> + // 2:
> + // ...
> + // 1: movl %eax, %ecx
> + // jmp 2b
> + //
> + // This might be "fixed" by introducing a try_cmpxchg_exclusive() that knows the "*old"
> + // location in the C function is always safe to write.
Oh wow the mentioned commit was an interesting read...
---
Cheers,
Benno
> + if self.try_cmpxchg(&mut old, new, o) {
> + Ok(old)
> + } else {
> + Err(old)
> + }
> + }
next prev parent reply other threads:[~2025-07-11 8:42 UTC|newest]
Thread overview: 65+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-10 6:00 [PATCH v6 0/9] LKMM generic atomics in Rust Boqun Feng
2025-07-10 6:00 ` [PATCH v6 1/9] rust: Introduce atomic API helpers Boqun Feng
2025-07-10 6:00 ` [PATCH v6 2/9] rust: sync: Add basic atomic operation mapping framework Boqun Feng
2025-07-10 11:04 ` Benno Lossin
2025-07-10 15:12 ` Boqun Feng
2025-07-10 15:46 ` Benno Lossin
2025-07-10 16:16 ` Boqun Feng
2025-07-10 19:21 ` Benno Lossin
2025-07-10 20:29 ` Boqun Feng
2025-07-11 8:15 ` Benno Lossin
2025-07-10 6:00 ` [PATCH v6 3/9] rust: sync: atomic: Add ordering annotation types Boqun Feng
2025-07-10 11:08 ` Benno Lossin
2025-07-10 12:00 ` Andreas Hindborg
2025-07-10 14:42 ` Boqun Feng
2025-07-10 15:05 ` Benno Lossin
2025-07-10 15:57 ` Boqun Feng
2025-07-10 19:19 ` Benno Lossin
2025-07-10 18:32 ` Miguel Ojeda
2025-07-10 19:06 ` Miguel Ojeda
2025-07-10 6:00 ` [PATCH v6 4/9] rust: sync: atomic: Add generic atomics Boqun Feng
2025-07-11 8:03 ` Benno Lossin
2025-07-11 13:22 ` Boqun Feng
2025-07-11 13:34 ` Benno Lossin
2025-07-11 13:51 ` Boqun Feng
2025-07-11 18:34 ` Benno Lossin
2025-07-11 21:25 ` Boqun Feng
2025-07-11 13:58 ` Boqun Feng
2025-07-11 18:35 ` Benno Lossin
2025-07-14 7:08 ` Boqun Feng
2025-07-13 19:51 ` Boqun Feng
2025-07-10 6:00 ` [PATCH v6 5/9] rust: sync: atomic: Add atomic {cmp,}xchg operations Boqun Feng
2025-07-11 8:42 ` Benno Lossin [this message]
2025-07-10 6:00 ` [PATCH v6 6/9] rust: sync: atomic: Add the framework of arithmetic operations Boqun Feng
2025-07-11 8:53 ` Benno Lossin
2025-07-11 14:39 ` Boqun Feng
2025-07-11 17:41 ` Boqun Feng
2025-07-11 19:07 ` Benno Lossin
2025-07-11 18:55 ` Benno Lossin
2025-07-11 19:51 ` Boqun Feng
2025-07-11 21:03 ` Benno Lossin
2025-07-11 21:22 ` Boqun Feng
2025-07-14 4:20 ` Boqun Feng
2025-07-10 6:00 ` [PATCH v6 7/9] rust: sync: atomic: Add Atomic<u{32,64}> Boqun Feng
2025-07-11 8:54 ` Benno Lossin
2025-07-10 6:00 ` [PATCH v6 8/9] rust: sync: Add memory barriers Boqun Feng
2025-07-11 8:57 ` Benno Lossin
2025-07-11 13:32 ` Boqun Feng
2025-07-11 18:57 ` Benno Lossin
2025-07-11 19:26 ` Boqun Feng
2025-07-11 21:04 ` Benno Lossin
2025-07-11 21:34 ` Boqun Feng
2025-07-11 18:20 ` Boqun Feng
2025-07-14 15:42 ` Ralf Jung
2025-07-15 15:21 ` Boqun Feng
2025-07-15 15:35 ` Ralf Jung
2025-07-15 15:56 ` Boqun Feng
2025-07-16 19:42 ` Ralf Jung
2025-07-10 6:00 ` [PATCH v6 9/9] rust: sync: atomic: Add Atomic<{usize,isize}> Boqun Feng
2025-07-11 9:00 ` Benno Lossin
2025-07-11 13:45 ` Miguel Ojeda
2025-07-11 14:07 ` Boqun Feng
2025-07-11 14:40 ` Miguel Ojeda
2025-07-11 15:46 ` Boqun Feng
2025-07-11 18:35 ` Miguel Ojeda
2025-07-11 19:05 ` Benno Lossin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DB93BZ5X63W4.2N48BXJEJOQ3F@kernel.org \
--to=lossin@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dakr@kernel.org \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=levymitchell0@gmail.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lkmm@lists.linux.dev \
--cc=lyude@redhat.com \
--cc=mark.rutland@arm.com \
--cc=mingo@kernel.org \
--cc=ojeda@kernel.org \
--cc=paulmck@kernel.org \
--cc=peterz@infradead.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=stern@rowland.harvard.edu \
--cc=tglx@linutronix.de \
--cc=tmgross@umich.edu \
--cc=torvalds@linux-foundation.org \
--cc=viresh.kumar@linaro.org \
--cc=wedsonaf@gmail.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).