* [PATCH v2 0/2] rust: sync: Add AtomicFlag type
@ 2026-01-29 12:26 FUJITA Tomonori
2026-01-29 12:26 ` [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans FUJITA Tomonori
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: FUJITA Tomonori @ 2026-01-29 12:26 UTC (permalink / raw)
To: boqun, ojeda, peterz, will
Cc: a.hindborg, aliceryhl, bjorn3_gh, dakr, gary, lossin,
mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori
From: FUJITA Tomonori <fujita.tomonori@gmail.com>
This series adds AtomicFlag and switches the list atomic tracker to
use it.
Unlike the previous design, we avoid exposing Atomic<Flag> and always
use AtomicFlag.
v2:
- Drop Atomic<u8> alias; Define Flag on all architectures
- Place padding first on big endian archs
v1: https://lore.kernel.org/rust-for-linux/20260128115200.3820113-1-tomo@aliasing.net/
FUJITA Tomonori (2):
rust: sync: atomic: Add perfromance-optimal Flag type for atomic
booleans
rust: list: Use AtomicFlag in AtomicTracker
rust/kernel/list/arc.rs | 8 +-
rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++
rust/kernel/sync/atomic/predefine.rs | 17 ++++
3 files changed, 146 insertions(+), 4 deletions(-)
base-commit: 6583920e15fc567109e1c64ca58c917f52f40736
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans 2026-01-29 12:26 [PATCH v2 0/2] rust: sync: Add AtomicFlag type FUJITA Tomonori @ 2026-01-29 12:26 ` FUJITA Tomonori 2026-01-29 14:15 ` Gary Guo 2026-01-29 12:26 ` [PATCH v2 2/2] rust: list: Use AtomicFlag in AtomicTracker FUJITA Tomonori 2026-01-29 16:00 ` [PATCH v2 0/2] rust: sync: Add AtomicFlag type Boqun Feng 2 siblings, 1 reply; 7+ messages in thread From: FUJITA Tomonori @ 2026-01-29 12:26 UTC (permalink / raw) To: boqun, ojeda, peterz, will Cc: a.hindborg, aliceryhl, bjorn3_gh, dakr, gary, lossin, mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori From: FUJITA Tomonori <fujita.tomonori@gmail.com> Add AtomicFlag type for boolean flags. Document when AtomicFlag is generally preferable to Atomic<bool>: in particular, when RMW operations such as xchg()/cmpxchg() may be used and minimizing memory usage is not the top priority. On some architectures without byte-sized RMW instructions, Atomic<bool> can be slower for RMW operations. Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> --- rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++ rust/kernel/sync/atomic/predefine.rs | 17 ++++ 2 files changed, 142 insertions(+) diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs index 4aebeacb961a..bfc393d98aa9 100644 --- a/rust/kernel/sync/atomic.rs +++ b/rust/kernel/sync/atomic.rs @@ -560,3 +560,128 @@ pub fn fetch_add<Rhs, Ordering: ordering::Ordering>(&self, v: Rhs, _: Ordering) unsafe { from_repr(ret) } } } + +#[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))] +#[repr(C)] +#[derive(Clone, Copy)] +struct Flag { + bool_field: bool, +} + +/// # Invariants +/// +/// `padding` must be all zeroes. +#[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] +#[repr(C, align(4))] +#[derive(Clone, Copy)] +struct Flag { + #[cfg(target_endian = "big")] + padding: [u8; 3], + bool_field: bool, + #[cfg(target_endian = "little")] + padding: [u8; 3], +} + +impl Flag { + #[inline(always)] + const fn new(b: bool) -> Self { + // INVARIANT: `padding` is all zeroes. + Self { + bool_field: b, + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] + padding: [0; 3], + } + } +} + +// SAFETY: `Flag` and `Repr` have the same size and alignment, and `Flag` is round-trip +// transmutable to the selected representation (`i8` or `i32`). +unsafe impl AtomicType for Flag { + #[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))] + type Repr = i8; + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] + type Repr = i32; +} + +/// An atomic flag type intended to be backed by performance-optimal integer type. +/// +/// The backing integer type is an implementation detail; it may vary by architecture and change +/// in the future. +/// +/// [`AtomicFlag`] is generally preferable to [`Atomic<bool>`] when you need read-modify-write +/// (RMW) operations (e.g. [`Atomic::xchg()`]/[`Atomic::cmpxchg()`]) or when [`Atomic<bool>`] does +/// not save memory due to padding. On some architectures that do not support byte-sized atomic +/// RMW operations, RMW operations on [`Atomic<bool>`] are slower. +/// +/// If you only use [`Atomic::load()`]/[`Atomic::store()`], [`Atomic<bool>`] is fine. +/// +/// # Examples +/// +/// ``` +/// use kernel::sync::atomic::{AtomicFlag, Relaxed}; +/// +/// let flag = AtomicFlag::new(false); +/// assert_eq!(false, flag.load(Relaxed)); +/// flag.store(true, Relaxed); +/// assert_eq!(true, flag.load(Relaxed)); +/// ``` +pub struct AtomicFlag(Atomic<Flag>); + +impl AtomicFlag { + /// Creates a new atomic flag. + #[inline(always)] + pub const fn new(b: bool) -> Self { + Self(Atomic::new(Flag::new(b))) + } + + /// Returns a mutable reference to the underlying flag as a [`bool`]. + /// + /// This is safe because the mutable reference of the atomic flag guarantees exclusive access. + /// + /// # Examples + /// + /// ``` + /// use kernel::sync::atomic::{AtomicFlag, Relaxed}; + /// + /// let mut atomic_flag = AtomicFlag::new(false); + /// assert_eq!(false, atomic_flag.load(Relaxed)); + /// *atomic_flag.get_mut() = true; + /// assert_eq!(true, atomic_flag.load(Relaxed)); + /// ``` + #[inline(always)] + pub fn get_mut(&mut self) -> &mut bool { + &mut self.0.get_mut().bool_field + } + + /// Loads the value from the atomic flag. + #[inline(always)] + pub fn load<Ordering: ordering::AcquireOrRelaxed>(&self, o: Ordering) -> bool { + self.0.load(o).bool_field + } + + /// Stores a value to the atomic flag. + #[inline(always)] + pub fn store<Ordering: ordering::ReleaseOrRelaxed>(&self, v: bool, o: Ordering) { + self.0.store(Flag::new(v), o); + } + + /// Stores a value to the atomic flag and returns the previous value. + #[inline(always)] + pub fn xchg<Ordering: ordering::Ordering>(&self, new: bool, o: Ordering) -> bool { + self.0.xchg(Flag::new(new), o).bool_field + } + + /// Store a value to the atomic flag if the current value is equal to `old`. + #[inline(always)] + pub fn cmpxchg<Ordering: ordering::Ordering>( + &self, + old: bool, + new: bool, + o: Ordering, + ) -> Result<bool, bool> { + match self.0.cmpxchg(Flag::new(old), Flag::new(new), o) { + Ok(_) => Ok(old), + Err(f) => Err(f.bool_field), + } + } +} diff --git a/rust/kernel/sync/atomic/predefine.rs b/rust/kernel/sync/atomic/predefine.rs index 42067c6a266c..d14e10544dcf 100644 --- a/rust/kernel/sync/atomic/predefine.rs +++ b/rust/kernel/sync/atomic/predefine.rs @@ -215,4 +215,21 @@ fn atomic_bool_tests() { assert_eq!(false, x.load(Relaxed)); assert_eq!(Ok(false), x.cmpxchg(false, true, Full)); } + + #[test] + fn atomic_flag_tests() { + let mut flag = AtomicFlag::new(false); + + assert_eq!(false, flag.load(Relaxed)); + + *flag.get_mut() = true; + assert_eq!(true, flag.load(Relaxed)); + + assert_eq!(true, flag.xchg(false, Relaxed)); + assert_eq!(false, flag.load(Relaxed)); + + *flag.get_mut() = true; + assert_eq!(Ok(true), flag.cmpxchg(true, false, Full)); + assert_eq!(false, flag.load(Relaxed)); + } } -- 2.43.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans 2026-01-29 12:26 ` [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans FUJITA Tomonori @ 2026-01-29 14:15 ` Gary Guo 2026-01-29 15:33 ` Boqun Feng 0 siblings, 1 reply; 7+ messages in thread From: Gary Guo @ 2026-01-29 14:15 UTC (permalink / raw) To: FUJITA Tomonori, boqun, ojeda, peterz, will Cc: a.hindborg, aliceryhl, bjorn3_gh, dakr, gary, lossin, mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori On Thu Jan 29, 2026 at 12:26 PM GMT, FUJITA Tomonori wrote: > From: FUJITA Tomonori <fujita.tomonori@gmail.com> > > Add AtomicFlag type for boolean flags. > > Document when AtomicFlag is generally preferable to Atomic<bool>: in > particular, when RMW operations such as xchg()/cmpxchg() may be used > and minimizing memory usage is not the top priority. On some > architectures without byte-sized RMW instructions, Atomic<bool> can be > slower for RMW operations. > > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> Hi Fujita, Thanks for the patch. I think this looks nice, so from design point of view: Reviewed-by: Gary Guo <gary@garyguo.net> However, Boqun reported that the codegen of `.bool_field` may involve a bit masking instruction. Best, Gary > --- > rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++ > rust/kernel/sync/atomic/predefine.rs | 17 ++++ > 2 files changed, 142 insertions(+) > > diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs > index 4aebeacb961a..bfc393d98aa9 100644 > --- a/rust/kernel/sync/atomic.rs > +++ b/rust/kernel/sync/atomic.rs > @@ -560,3 +560,128 @@ pub fn fetch_add<Rhs, Ordering: ordering::Ordering>(&self, v: Rhs, _: Ordering) > unsafe { from_repr(ret) } > } > } > + > +#[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))] > +#[repr(C)] > +#[derive(Clone, Copy)] > +struct Flag { > + bool_field: bool, > +} > + > +/// # Invariants > +/// > +/// `padding` must be all zeroes. > +#[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] > +#[repr(C, align(4))] > +#[derive(Clone, Copy)] > +struct Flag { > + #[cfg(target_endian = "big")] > + padding: [u8; 3], > + bool_field: bool, > + #[cfg(target_endian = "little")] > + padding: [u8; 3], > +} > + > +impl Flag { > + #[inline(always)] > + const fn new(b: bool) -> Self { > + // INVARIANT: `padding` is all zeroes. > + Self { > + bool_field: b, > + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] > + padding: [0; 3], > + } > + } > +} > + > +// SAFETY: `Flag` and `Repr` have the same size and alignment, and `Flag` is round-trip > +// transmutable to the selected representation (`i8` or `i32`). > +unsafe impl AtomicType for Flag { > + #[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))] > + type Repr = i8; > + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] > + type Repr = i32; > +} > + > +/// An atomic flag type intended to be backed by performance-optimal integer type. > +/// > +/// The backing integer type is an implementation detail; it may vary by architecture and change > +/// in the future. > +/// > +/// [`AtomicFlag`] is generally preferable to [`Atomic<bool>`] when you need read-modify-write > +/// (RMW) operations (e.g. [`Atomic::xchg()`]/[`Atomic::cmpxchg()`]) or when [`Atomic<bool>`] does > +/// not save memory due to padding. On some architectures that do not support byte-sized atomic > +/// RMW operations, RMW operations on [`Atomic<bool>`] are slower. > +/// > +/// If you only use [`Atomic::load()`]/[`Atomic::store()`], [`Atomic<bool>`] is fine. > +/// > +/// # Examples > +/// > +/// ``` > +/// use kernel::sync::atomic::{AtomicFlag, Relaxed}; > +/// > +/// let flag = AtomicFlag::new(false); > +/// assert_eq!(false, flag.load(Relaxed)); > +/// flag.store(true, Relaxed); > +/// assert_eq!(true, flag.load(Relaxed)); > +/// ``` > +pub struct AtomicFlag(Atomic<Flag>); > + > +impl AtomicFlag { > + /// Creates a new atomic flag. > + #[inline(always)] > + pub const fn new(b: bool) -> Self { > + Self(Atomic::new(Flag::new(b))) > + } > + > + /// Returns a mutable reference to the underlying flag as a [`bool`]. > + /// > + /// This is safe because the mutable reference of the atomic flag guarantees exclusive access. > + /// > + /// # Examples > + /// > + /// ``` > + /// use kernel::sync::atomic::{AtomicFlag, Relaxed}; > + /// > + /// let mut atomic_flag = AtomicFlag::new(false); > + /// assert_eq!(false, atomic_flag.load(Relaxed)); > + /// *atomic_flag.get_mut() = true; > + /// assert_eq!(true, atomic_flag.load(Relaxed)); > + /// ``` > + #[inline(always)] > + pub fn get_mut(&mut self) -> &mut bool { > + &mut self.0.get_mut().bool_field > + } > + > + /// Loads the value from the atomic flag. > + #[inline(always)] > + pub fn load<Ordering: ordering::AcquireOrRelaxed>(&self, o: Ordering) -> bool { > + self.0.load(o).bool_field > + } > + > + /// Stores a value to the atomic flag. > + #[inline(always)] > + pub fn store<Ordering: ordering::ReleaseOrRelaxed>(&self, v: bool, o: Ordering) { > + self.0.store(Flag::new(v), o); > + } > + > + /// Stores a value to the atomic flag and returns the previous value. > + #[inline(always)] > + pub fn xchg<Ordering: ordering::Ordering>(&self, new: bool, o: Ordering) -> bool { > + self.0.xchg(Flag::new(new), o).bool_field > + } > + > + /// Store a value to the atomic flag if the current value is equal to `old`. > + #[inline(always)] > + pub fn cmpxchg<Ordering: ordering::Ordering>( > + &self, > + old: bool, > + new: bool, > + o: Ordering, > + ) -> Result<bool, bool> { > + match self.0.cmpxchg(Flag::new(old), Flag::new(new), o) { > + Ok(_) => Ok(old), > + Err(f) => Err(f.bool_field), > + } > + } > +} > diff --git a/rust/kernel/sync/atomic/predefine.rs b/rust/kernel/sync/atomic/predefine.rs > index 42067c6a266c..d14e10544dcf 100644 > --- a/rust/kernel/sync/atomic/predefine.rs > +++ b/rust/kernel/sync/atomic/predefine.rs > @@ -215,4 +215,21 @@ fn atomic_bool_tests() { > assert_eq!(false, x.load(Relaxed)); > assert_eq!(Ok(false), x.cmpxchg(false, true, Full)); > } > + > + #[test] > + fn atomic_flag_tests() { > + let mut flag = AtomicFlag::new(false); > + > + assert_eq!(false, flag.load(Relaxed)); > + > + *flag.get_mut() = true; > + assert_eq!(true, flag.load(Relaxed)); > + > + assert_eq!(true, flag.xchg(false, Relaxed)); > + assert_eq!(false, flag.load(Relaxed)); > + > + *flag.get_mut() = true; > + assert_eq!(Ok(true), flag.cmpxchg(true, false, Full)); > + assert_eq!(false, flag.load(Relaxed)); > + } > } ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans 2026-01-29 14:15 ` Gary Guo @ 2026-01-29 15:33 ` Boqun Feng 2026-01-29 15:45 ` Gary Guo 0 siblings, 1 reply; 7+ messages in thread From: Boqun Feng @ 2026-01-29 15:33 UTC (permalink / raw) To: Gary Guo Cc: FUJITA Tomonori, ojeda, peterz, will, a.hindborg, aliceryhl, bjorn3_gh, dakr, lossin, mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori On Thu, Jan 29, 2026 at 02:15:10PM +0000, Gary Guo wrote: > On Thu Jan 29, 2026 at 12:26 PM GMT, FUJITA Tomonori wrote: > > From: FUJITA Tomonori <fujita.tomonori@gmail.com> > > > > Add AtomicFlag type for boolean flags. > > > > Document when AtomicFlag is generally preferable to Atomic<bool>: in > > particular, when RMW operations such as xchg()/cmpxchg() may be used > > and minimizing memory usage is not the top priority. On some > > architectures without byte-sized RMW instructions, Atomic<bool> can be > > slower for RMW operations. > > > > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> > > Hi Fujita, > > Thanks for the patch. I think this looks nice, so from design point of view: > > Reviewed-by: Gary Guo <gary@garyguo.net> > > However, Boqun reported that the codegen of `.bool_field` may involve a bit > masking instruction. > Yeah, but at the moment, I haven't found any elegant way to reduce that see [1], plus I've tried to transmute the 32-bit Flag struct into a 32-bit enum, but for example on riscv64 an `sext.w` instruction is still generated [2]. That's a sign to me that the micro-optimization here may not bring actual performance gain. But of course, open to any improvement, let's ship what we have now and improve the codegen later. [1]: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/A.20.60AlwaysZero.60.20type.20for.20padding.3F/near/570631532 [2]: https://godbolt.org/z/3PMK3EK1r Regards, Boqun > Best, > Gary > > > --- > > rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++ > > rust/kernel/sync/atomic/predefine.rs | 17 ++++ > > 2 files changed, 142 insertions(+) > > > > diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs > > index 4aebeacb961a..bfc393d98aa9 100644 > > --- a/rust/kernel/sync/atomic.rs > > +++ b/rust/kernel/sync/atomic.rs > > @@ -560,3 +560,128 @@ pub fn fetch_add<Rhs, Ordering: ordering::Ordering>(&self, v: Rhs, _: Ordering) > > unsafe { from_repr(ret) } > > } > > } > > + > > +#[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))] > > +#[repr(C)] > > +#[derive(Clone, Copy)] > > +struct Flag { > > + bool_field: bool, > > +} > > + > > +/// # Invariants > > +/// > > +/// `padding` must be all zeroes. > > +#[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] > > +#[repr(C, align(4))] > > +#[derive(Clone, Copy)] > > +struct Flag { > > + #[cfg(target_endian = "big")] > > + padding: [u8; 3], > > + bool_field: bool, > > + #[cfg(target_endian = "little")] > > + padding: [u8; 3], > > +} > > + > > +impl Flag { > > + #[inline(always)] > > + const fn new(b: bool) -> Self { > > + // INVARIANT: `padding` is all zeroes. > > + Self { > > + bool_field: b, > > + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] > > + padding: [0; 3], > > + } > > + } > > +} > > + > > +// SAFETY: `Flag` and `Repr` have the same size and alignment, and `Flag` is round-trip > > +// transmutable to the selected representation (`i8` or `i32`). > > +unsafe impl AtomicType for Flag { > > + #[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))] > > + type Repr = i8; > > + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] > > + type Repr = i32; > > +} > > + > > +/// An atomic flag type intended to be backed by performance-optimal integer type. > > +/// > > +/// The backing integer type is an implementation detail; it may vary by architecture and change > > +/// in the future. > > +/// > > +/// [`AtomicFlag`] is generally preferable to [`Atomic<bool>`] when you need read-modify-write > > +/// (RMW) operations (e.g. [`Atomic::xchg()`]/[`Atomic::cmpxchg()`]) or when [`Atomic<bool>`] does > > +/// not save memory due to padding. On some architectures that do not support byte-sized atomic > > +/// RMW operations, RMW operations on [`Atomic<bool>`] are slower. > > +/// > > +/// If you only use [`Atomic::load()`]/[`Atomic::store()`], [`Atomic<bool>`] is fine. > > +/// > > +/// # Examples > > +/// > > +/// ``` > > +/// use kernel::sync::atomic::{AtomicFlag, Relaxed}; > > +/// > > +/// let flag = AtomicFlag::new(false); > > +/// assert_eq!(false, flag.load(Relaxed)); > > +/// flag.store(true, Relaxed); > > +/// assert_eq!(true, flag.load(Relaxed)); > > +/// ``` > > +pub struct AtomicFlag(Atomic<Flag>); > > + > > +impl AtomicFlag { > > + /// Creates a new atomic flag. > > + #[inline(always)] > > + pub const fn new(b: bool) -> Self { > > + Self(Atomic::new(Flag::new(b))) > > + } > > + > > + /// Returns a mutable reference to the underlying flag as a [`bool`]. > > + /// > > + /// This is safe because the mutable reference of the atomic flag guarantees exclusive access. > > + /// > > + /// # Examples > > + /// > > + /// ``` > > + /// use kernel::sync::atomic::{AtomicFlag, Relaxed}; > > + /// > > + /// let mut atomic_flag = AtomicFlag::new(false); > > + /// assert_eq!(false, atomic_flag.load(Relaxed)); > > + /// *atomic_flag.get_mut() = true; > > + /// assert_eq!(true, atomic_flag.load(Relaxed)); > > + /// ``` > > + #[inline(always)] > > + pub fn get_mut(&mut self) -> &mut bool { > > + &mut self.0.get_mut().bool_field > > + } > > + > > + /// Loads the value from the atomic flag. > > + #[inline(always)] > > + pub fn load<Ordering: ordering::AcquireOrRelaxed>(&self, o: Ordering) -> bool { > > + self.0.load(o).bool_field > > + } > > + > > + /// Stores a value to the atomic flag. > > + #[inline(always)] > > + pub fn store<Ordering: ordering::ReleaseOrRelaxed>(&self, v: bool, o: Ordering) { > > + self.0.store(Flag::new(v), o); > > + } > > + > > + /// Stores a value to the atomic flag and returns the previous value. > > + #[inline(always)] > > + pub fn xchg<Ordering: ordering::Ordering>(&self, new: bool, o: Ordering) -> bool { > > + self.0.xchg(Flag::new(new), o).bool_field > > + } > > + > > + /// Store a value to the atomic flag if the current value is equal to `old`. > > + #[inline(always)] > > + pub fn cmpxchg<Ordering: ordering::Ordering>( > > + &self, > > + old: bool, > > + new: bool, > > + o: Ordering, > > + ) -> Result<bool, bool> { > > + match self.0.cmpxchg(Flag::new(old), Flag::new(new), o) { > > + Ok(_) => Ok(old), > > + Err(f) => Err(f.bool_field), > > + } > > + } > > +} > > diff --git a/rust/kernel/sync/atomic/predefine.rs b/rust/kernel/sync/atomic/predefine.rs > > index 42067c6a266c..d14e10544dcf 100644 > > --- a/rust/kernel/sync/atomic/predefine.rs > > +++ b/rust/kernel/sync/atomic/predefine.rs > > @@ -215,4 +215,21 @@ fn atomic_bool_tests() { > > assert_eq!(false, x.load(Relaxed)); > > assert_eq!(Ok(false), x.cmpxchg(false, true, Full)); > > } > > + > > + #[test] > > + fn atomic_flag_tests() { > > + let mut flag = AtomicFlag::new(false); > > + > > + assert_eq!(false, flag.load(Relaxed)); > > + > > + *flag.get_mut() = true; > > + assert_eq!(true, flag.load(Relaxed)); > > + > > + assert_eq!(true, flag.xchg(false, Relaxed)); > > + assert_eq!(false, flag.load(Relaxed)); > > + > > + *flag.get_mut() = true; > > + assert_eq!(Ok(true), flag.cmpxchg(true, false, Full)); > > + assert_eq!(false, flag.load(Relaxed)); > > + } > > } > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans 2026-01-29 15:33 ` Boqun Feng @ 2026-01-29 15:45 ` Gary Guo 0 siblings, 0 replies; 7+ messages in thread From: Gary Guo @ 2026-01-29 15:45 UTC (permalink / raw) To: Boqun Feng, Gary Guo Cc: FUJITA Tomonori, ojeda, peterz, will, a.hindborg, aliceryhl, bjorn3_gh, dakr, lossin, mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori On Thu Jan 29, 2026 at 3:33 PM GMT, Boqun Feng wrote: > On Thu, Jan 29, 2026 at 02:15:10PM +0000, Gary Guo wrote: >> On Thu Jan 29, 2026 at 12:26 PM GMT, FUJITA Tomonori wrote: >> > From: FUJITA Tomonori <fujita.tomonori@gmail.com> >> > >> > Add AtomicFlag type for boolean flags. >> > >> > Document when AtomicFlag is generally preferable to Atomic<bool>: in >> > particular, when RMW operations such as xchg()/cmpxchg() may be used >> > and minimizing memory usage is not the top priority. On some >> > architectures without byte-sized RMW instructions, Atomic<bool> can be >> > slower for RMW operations. >> > >> > Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> >> >> Hi Fujita, >> >> Thanks for the patch. I think this looks nice, so from design point of view: >> >> Reviewed-by: Gary Guo <gary@garyguo.net> >> >> However, Boqun reported that the codegen of `.bool_field` may involve a bit >> masking instruction. >> > > Yeah, but at the moment, I haven't found any elegant way to reduce that > see [1], plus I've tried to transmute the 32-bit Flag struct into a > 32-bit enum, but for example on riscv64 an `sext.w` instruction is still > generated [2]. That's a sign to me that the micro-optimization here may > not bring actual performance gain. But of course, open to any > improvement, let's ship what we have now and improve the codegen later. > > [1]: https://rust-for-linux.zulipchat.com/#narrow/channel/288089-General/topic/A.20.60AlwaysZero.60.20type.20for.20padding.3F/near/570631532 > [2]: https://godbolt.org/z/3PMK3EK1r Interesting! In this case, disabling MIR optimization generates better code for test2 (-Zmir-opt-level=0). Although, it still has an `andi a0, a0, 1` remaining. Testing with `-Cno-prepopulate-passes --emit=llvm-ir` it looks like Rust is not telling LLVM about the fact that `v` can only be 0 or 1... Although, I recall that previously seeing LLVM codegen issues when Rust does give LLVM additional unreachable paths.. So the fix isn't going to be straightforward. With this background I agree we should ship this as is. It's much better than a LL/SC loop anyway. Best, Gary > >> >> > --- >> > rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++ >> > rust/kernel/sync/atomic/predefine.rs | 17 ++++ >> > 2 files changed, 142 insertions(+) >> > >> > diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs >> > index 4aebeacb961a..bfc393d98aa9 100644 >> > --- a/rust/kernel/sync/atomic.rs >> > +++ b/rust/kernel/sync/atomic.rs >> > @@ -560,3 +560,128 @@ pub fn fetch_add<Rhs, Ordering: ordering::Ordering>(&self, v: Rhs, _: Ordering) >> > unsafe { from_repr(ret) } >> > } >> > } >> > + >> > +#[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))] >> > +#[repr(C)] >> > +#[derive(Clone, Copy)] >> > +struct Flag { >> > + bool_field: bool, >> > +} >> > + >> > +/// # Invariants >> > +/// >> > +/// `padding` must be all zeroes. >> > +#[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] >> > +#[repr(C, align(4))] >> > +#[derive(Clone, Copy)] >> > +struct Flag { >> > + #[cfg(target_endian = "big")] >> > + padding: [u8; 3], >> > + bool_field: bool, >> > + #[cfg(target_endian = "little")] >> > + padding: [u8; 3], >> > +} >> > + >> > +impl Flag { >> > + #[inline(always)] >> > + const fn new(b: bool) -> Self { >> > + // INVARIANT: `padding` is all zeroes. >> > + Self { >> > + bool_field: b, >> > + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] >> > + padding: [0; 3], >> > + } >> > + } >> > +} >> > + >> > +// SAFETY: `Flag` and `Repr` have the same size and alignment, and `Flag` is round-trip >> > +// transmutable to the selected representation (`i8` or `i32`). >> > +unsafe impl AtomicType for Flag { >> > + #[cfg(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64))] >> > + type Repr = i8; >> > + #[cfg(not(any(CONFIG_X86_64, CONFIG_UML, CONFIG_ARM, CONFIG_ARM64)))] >> > + type Repr = i32; >> > +} >> > + >> > +/// An atomic flag type intended to be backed by performance-optimal integer type. >> > +/// >> > +/// The backing integer type is an implementation detail; it may vary by architecture and change >> > +/// in the future. >> > +/// >> > +/// [`AtomicFlag`] is generally preferable to [`Atomic<bool>`] when you need read-modify-write >> > +/// (RMW) operations (e.g. [`Atomic::xchg()`]/[`Atomic::cmpxchg()`]) or when [`Atomic<bool>`] does >> > +/// not save memory due to padding. On some architectures that do not support byte-sized atomic >> > +/// RMW operations, RMW operations on [`Atomic<bool>`] are slower. >> > +/// >> > +/// If you only use [`Atomic::load()`]/[`Atomic::store()`], [`Atomic<bool>`] is fine. >> > +/// >> > +/// # Examples >> > +/// >> > +/// ``` >> > +/// use kernel::sync::atomic::{AtomicFlag, Relaxed}; >> > +/// >> > +/// let flag = AtomicFlag::new(false); >> > +/// assert_eq!(false, flag.load(Relaxed)); >> > +/// flag.store(true, Relaxed); >> > +/// assert_eq!(true, flag.load(Relaxed)); >> > +/// ``` >> > +pub struct AtomicFlag(Atomic<Flag>); >> > + >> > +impl AtomicFlag { >> > + /// Creates a new atomic flag. >> > + #[inline(always)] >> > + pub const fn new(b: bool) -> Self { >> > + Self(Atomic::new(Flag::new(b))) >> > + } >> > + >> > + /// Returns a mutable reference to the underlying flag as a [`bool`]. >> > + /// >> > + /// This is safe because the mutable reference of the atomic flag guarantees exclusive access. >> > + /// >> > + /// # Examples >> > + /// >> > + /// ``` >> > + /// use kernel::sync::atomic::{AtomicFlag, Relaxed}; >> > + /// >> > + /// let mut atomic_flag = AtomicFlag::new(false); >> > + /// assert_eq!(false, atomic_flag.load(Relaxed)); >> > + /// *atomic_flag.get_mut() = true; >> > + /// assert_eq!(true, atomic_flag.load(Relaxed)); >> > + /// ``` >> > + #[inline(always)] >> > + pub fn get_mut(&mut self) -> &mut bool { >> > + &mut self.0.get_mut().bool_field >> > + } >> > + >> > + /// Loads the value from the atomic flag. >> > + #[inline(always)] >> > + pub fn load<Ordering: ordering::AcquireOrRelaxed>(&self, o: Ordering) -> bool { >> > + self.0.load(o).bool_field >> > + } >> > + >> > + /// Stores a value to the atomic flag. >> > + #[inline(always)] >> > + pub fn store<Ordering: ordering::ReleaseOrRelaxed>(&self, v: bool, o: Ordering) { >> > + self.0.store(Flag::new(v), o); >> > + } >> > + >> > + /// Stores a value to the atomic flag and returns the previous value. >> > + #[inline(always)] >> > + pub fn xchg<Ordering: ordering::Ordering>(&self, new: bool, o: Ordering) -> bool { >> > + self.0.xchg(Flag::new(new), o).bool_field >> > + } >> > + >> > + /// Store a value to the atomic flag if the current value is equal to `old`. >> > + #[inline(always)] >> > + pub fn cmpxchg<Ordering: ordering::Ordering>( >> > + &self, >> > + old: bool, >> > + new: bool, >> > + o: Ordering, >> > + ) -> Result<bool, bool> { >> > + match self.0.cmpxchg(Flag::new(old), Flag::new(new), o) { >> > + Ok(_) => Ok(old), >> > + Err(f) => Err(f.bool_field), >> > + } >> > + } >> > +} >> > diff --git a/rust/kernel/sync/atomic/predefine.rs b/rust/kernel/sync/atomic/predefine.rs >> > index 42067c6a266c..d14e10544dcf 100644 >> > --- a/rust/kernel/sync/atomic/predefine.rs >> > +++ b/rust/kernel/sync/atomic/predefine.rs >> > @@ -215,4 +215,21 @@ fn atomic_bool_tests() { >> > assert_eq!(false, x.load(Relaxed)); >> > assert_eq!(Ok(false), x.cmpxchg(false, true, Full)); >> > } >> > + >> > + #[test] >> > + fn atomic_flag_tests() { >> > + let mut flag = AtomicFlag::new(false); >> > + >> > + assert_eq!(false, flag.load(Relaxed)); >> > + >> > + *flag.get_mut() = true; >> > + assert_eq!(true, flag.load(Relaxed)); >> > + >> > + assert_eq!(true, flag.xchg(false, Relaxed)); >> > + assert_eq!(false, flag.load(Relaxed)); >> > + >> > + *flag.get_mut() = true; >> > + assert_eq!(Ok(true), flag.cmpxchg(true, false, Full)); >> > + assert_eq!(false, flag.load(Relaxed)); >> > + } >> > } >> ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 2/2] rust: list: Use AtomicFlag in AtomicTracker 2026-01-29 12:26 [PATCH v2 0/2] rust: sync: Add AtomicFlag type FUJITA Tomonori 2026-01-29 12:26 ` [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans FUJITA Tomonori @ 2026-01-29 12:26 ` FUJITA Tomonori 2026-01-29 16:00 ` [PATCH v2 0/2] rust: sync: Add AtomicFlag type Boqun Feng 2 siblings, 0 replies; 7+ messages in thread From: FUJITA Tomonori @ 2026-01-29 12:26 UTC (permalink / raw) To: boqun, ojeda, peterz, will Cc: a.hindborg, aliceryhl, bjorn3_gh, dakr, gary, lossin, mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori From: FUJITA Tomonori <fujita.tomonori@gmail.com> Make AtomicTracker use AtomicFlag instead of Atomic<bool> to avoid slow byte-sized RMWs on architectures that don't support them. Reviewed-by: Gary Guo <gary@garyguo.net> Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com> --- rust/kernel/list/arc.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/kernel/list/arc.rs b/rust/kernel/list/arc.rs index 2282f33913ee..5e84f500a3fe 100644 --- a/rust/kernel/list/arc.rs +++ b/rust/kernel/list/arc.rs @@ -6,7 +6,7 @@ use crate::alloc::{AllocError, Flags}; use crate::prelude::*; -use crate::sync::atomic::{ordering, Atomic}; +use crate::sync::atomic::{ordering, AtomicFlag}; use crate::sync::{Arc, ArcBorrow, UniqueArc}; use core::marker::PhantomPinned; use core::ops::Deref; @@ -469,7 +469,7 @@ impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc /// If the boolean is `false`, then there is no [`ListArc`] for this value. #[repr(transparent)] pub struct AtomicTracker<const ID: u64 = 0> { - inner: Atomic<bool>, + inner: AtomicFlag, // This value needs to be pinned to justify the INVARIANT: comment in `AtomicTracker::new`. _pin: PhantomPinned, } @@ -480,12 +480,12 @@ pub fn new() -> impl PinInit<Self> { // INVARIANT: Pin-init initializers can't be used on an existing `Arc`, so this value will // not be constructed in an `Arc` that already has a `ListArc`. Self { - inner: Atomic::new(false), + inner: AtomicFlag::new(false), _pin: PhantomPinned, } } - fn project_inner(self: Pin<&mut Self>) -> &mut Atomic<bool> { + fn project_inner(self: Pin<&mut Self>) -> &mut AtomicFlag { // SAFETY: The `inner` field is not structurally pinned, so we may obtain a mutable // reference to it even if we only have a pinned reference to `self`. unsafe { &mut Pin::into_inner_unchecked(self).inner } -- 2.43.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2 0/2] rust: sync: Add AtomicFlag type 2026-01-29 12:26 [PATCH v2 0/2] rust: sync: Add AtomicFlag type FUJITA Tomonori 2026-01-29 12:26 ` [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans FUJITA Tomonori 2026-01-29 12:26 ` [PATCH v2 2/2] rust: list: Use AtomicFlag in AtomicTracker FUJITA Tomonori @ 2026-01-29 16:00 ` Boqun Feng 2 siblings, 0 replies; 7+ messages in thread From: Boqun Feng @ 2026-01-29 16:00 UTC (permalink / raw) To: FUJITA Tomonori Cc: ojeda, peterz, will, a.hindborg, aliceryhl, bjorn3_gh, dakr, gary, lossin, mark.rutland, tmgross, rust-for-linux, FUJITA Tomonori On Thu, Jan 29, 2026 at 09:26:20PM +0900, FUJITA Tomonori wrote: > From: FUJITA Tomonori <fujita.tomonori@gmail.com> > > This series adds AtomicFlag and switches the list atomic tracker to > use it. > > Unlike the previous design, we avoid exposing Atomic<Flag> and always > use AtomicFlag. > > v2: > - Drop Atomic<u8> alias; Define Flag on all architectures > - Place padding first on big endian archs > v1: https://lore.kernel.org/rust-for-linux/20260128115200.3820113-1-tomo@aliasing.net/ > Queued in rust-sync for more tests and reviews, thank you! Regards, Boqun > > FUJITA Tomonori (2): > rust: sync: atomic: Add perfromance-optimal Flag type for atomic > booleans > rust: list: Use AtomicFlag in AtomicTracker > > rust/kernel/list/arc.rs | 8 +- > rust/kernel/sync/atomic.rs | 125 +++++++++++++++++++++++++++ > rust/kernel/sync/atomic/predefine.rs | 17 ++++ > 3 files changed, 146 insertions(+), 4 deletions(-) > > > base-commit: 6583920e15fc567109e1c64ca58c917f52f40736 > -- > 2.43.0 > ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-01-29 16:01 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-01-29 12:26 [PATCH v2 0/2] rust: sync: Add AtomicFlag type FUJITA Tomonori 2026-01-29 12:26 ` [PATCH v2 1/2] rust: sync: atomic: Add perfromance-optimal Flag type for atomic booleans FUJITA Tomonori 2026-01-29 14:15 ` Gary Guo 2026-01-29 15:33 ` Boqun Feng 2026-01-29 15:45 ` Gary Guo 2026-01-29 12:26 ` [PATCH v2 2/2] rust: list: Use AtomicFlag in AtomicTracker FUJITA Tomonori 2026-01-29 16:00 ` [PATCH v2 0/2] rust: sync: Add AtomicFlag type Boqun Feng
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox