summaryrefslogtreecommitdiff
path: root/rust/kernel/sync/atomic
diff options
context:
space:
mode:
authorBoqun Feng <boqun.feng@gmail.com>2026-03-03 12:16:58 -0800
committerPeter Zijlstra <peterz@infradead.org>2026-03-08 11:06:50 +0100
commite2f9c86f33abb89d3e52436018f58e5fb951cc04 (patch)
tree2618504e95a241ab81e4fddd1ae25a1afb638d40 /rust/kernel/sync/atomic
parent282866207020b15c2afc4d43b1ca0c5d96c9032d (diff)
rust: sync: atomic: Add atomic operation helpers over raw pointers
In order to synchronize with C or external memory, atomic operations over raw pointers are need. Although there is already an `Atomic::from_ptr()` to provide a `&Atomic<T>`, it's more convenient to have helpers that directly perform atomic operations on raw pointers. Hence a few are added, which are basically an `Atomic::from_ptr().op()` wrapper. Note: for naming, since `atomic_xchg()` and `atomic_cmpxchg()` have a conflict naming to 32bit C atomic xchg/cmpxchg, hence the helpers are just named as `xchg()` and `cmpxchg()`. For `atomic_load()` and `atomic_store()`, their 32bit C counterparts are `atomic_read()` and `atomic_set()`, so keep the `atomic_` prefix. [boqun: Fix typo spotted by Alice and fix broken sentence spotted by Gary] Signed-off-by: Boqun Feng <boqun.feng@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260120115207.55318-3-boqun.feng@gmail.com Link: https://patch.msgid.link/20260303201701.12204-11-boqun@kernel.org
Diffstat (limited to 'rust/kernel/sync/atomic')
-rw-r--r--rust/kernel/sync/atomic/predefine.rs46
1 files changed, 46 insertions, 0 deletions
diff --git a/rust/kernel/sync/atomic/predefine.rs b/rust/kernel/sync/atomic/predefine.rs
index ceb3caed9784..1d53834fcb12 100644
--- a/rust/kernel/sync/atomic/predefine.rs
+++ b/rust/kernel/sync/atomic/predefine.rs
@@ -178,6 +178,14 @@ mod tests {
assert_eq!(v, x.load(Relaxed));
});
+
+ for_each_type!(42 in [i8, i16, i32, i64, u32, u64, isize, usize] |v| {
+ let x = Atomic::new(v);
+ let ptr = x.as_ptr();
+
+ // SAFETY: `ptr` is a valid pointer and no concurrent access.
+ assert_eq!(v, unsafe { atomic_load(ptr, Relaxed) });
+ });
}
#[test]
@@ -188,6 +196,17 @@ mod tests {
x.store(v, Release);
assert_eq!(v, x.load(Acquire));
});
+
+ for_each_type!(42 in [i8, i16, i32, i64, u32, u64, isize, usize] |v| {
+ let x = Atomic::new(0);
+ let ptr = x.as_ptr();
+
+ // SAFETY: `ptr` is a valid pointer and no concurrent access.
+ unsafe { atomic_store(ptr, v, Release) };
+
+ // SAFETY: `ptr` is a valid pointer and no concurrent access.
+ assert_eq!(v, unsafe { atomic_load(ptr, Acquire) });
+ });
}
#[test]
@@ -201,6 +220,18 @@ mod tests {
assert_eq!(old, x.xchg(new, Full));
assert_eq!(new, x.load(Relaxed));
});
+
+ for_each_type!(42 in [i8, i16, i32, i64, u32, u64, isize, usize] |v| {
+ let x = Atomic::new(v);
+ let ptr = x.as_ptr();
+
+ let old = v;
+ let new = v + 1;
+
+ // SAFETY: `ptr` is a valid pointer and no concurrent access.
+ assert_eq!(old, unsafe { xchg(ptr, new, Full) });
+ assert_eq!(new, x.load(Relaxed));
+ });
}
#[test]
@@ -216,6 +247,21 @@ mod tests {
assert_eq!(Ok(old), x.cmpxchg(old, new, Relaxed));
assert_eq!(new, x.load(Relaxed));
});
+
+ for_each_type!(42 in [i8, i16, i32, i64, u32, u64, isize, usize] |v| {
+ let x = Atomic::new(v);
+ let ptr = x.as_ptr();
+
+ let old = v;
+ let new = v + 1;
+
+ // SAFETY: `ptr` is a valid pointer and no concurrent access.
+ assert_eq!(Err(old), unsafe { cmpxchg(ptr, new, new, Full) });
+ assert_eq!(old, x.load(Relaxed));
+ // SAFETY: `ptr` is a valid pointer and no concurrent access.
+ assert_eq!(Ok(old), unsafe { cmpxchg(ptr, old, new, Relaxed) });
+ assert_eq!(new, x.load(Relaxed));
+ });
}
#[test]