summaryrefslogtreecommitdiff
path: root/rust/kernel/sync/atomic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/kernel/sync/atomic.rs')
-rw-r--r--rust/kernel/sync/atomic.rs104
1 files changed, 104 insertions, 0 deletions
diff --git a/rust/kernel/sync/atomic.rs b/rust/kernel/sync/atomic.rs
index f80cebce5bc1..1bb1fc2be177 100644
--- a/rust/kernel/sync/atomic.rs
+++ b/rust/kernel/sync/atomic.rs
@@ -703,3 +703,107 @@ impl AtomicFlag {
}
}
}
+
+/// Atomic load over raw pointers.
+///
+/// This function provides a short-cut of `Atomic::from_ptr().load(..)`, and can be used to work
+/// with C side on synchronizations:
+///
+/// - `atomic_load(.., Relaxed)` maps to `READ_ONCE()` when used for inter-thread communication.
+/// - `atomic_load(.., Acquire)` maps to `smp_load_acquire()`.
+///
+/// # Safety
+///
+/// - `ptr` is a valid pointer to `T` and aligned to `align_of::<T>()`.
+/// - If there is a concurrent store from kernel (C or Rust), it has to be atomic.
+#[doc(alias("READ_ONCE", "smp_load_acquire"))]
+#[inline(always)]
+pub unsafe fn atomic_load<T: AtomicType, Ordering: ordering::AcquireOrRelaxed>(
+ ptr: *mut T,
+ o: Ordering,
+) -> T
+where
+ T::Repr: AtomicBasicOps,
+{
+ // SAFETY: Per the function safety requirement, `ptr` is valid and aligned to
+ // `align_of::<T>()`, and all concurrent stores from kernel are atomic, hence no data race per
+ // LKMM.
+ unsafe { Atomic::from_ptr(ptr) }.load(o)
+}
+
+/// Atomic store over raw pointers.
+///
+/// This function provides a short-cut of `Atomic::from_ptr().load(..)`, and can be used to work
+/// with C side on synchronizations:
+///
+/// - `atomic_store(.., Relaxed)` maps to `WRITE_ONCE()` when used for inter-thread communication.
+/// - `atomic_load(.., Release)` maps to `smp_store_release()`.
+///
+/// # Safety
+///
+/// - `ptr` is a valid pointer to `T` and aligned to `align_of::<T>()`.
+/// - If there is a concurrent access from kernel (C or Rust), it has to be atomic.
+#[doc(alias("WRITE_ONCE", "smp_store_release"))]
+#[inline(always)]
+pub unsafe fn atomic_store<T: AtomicType, Ordering: ordering::ReleaseOrRelaxed>(
+ ptr: *mut T,
+ v: T,
+ o: Ordering,
+) where
+ T::Repr: AtomicBasicOps,
+{
+ // SAFETY: Per the function safety requirement, `ptr` is valid and aligned to
+ // `align_of::<T>()`, and all concurrent accesses from kernel are atomic, hence no data race
+ // per LKMM.
+ unsafe { Atomic::from_ptr(ptr) }.store(v, o);
+}
+
+/// Atomic exchange over raw pointers.
+///
+/// This function provides a short-cut of `Atomic::from_ptr().xchg(..)`, and can be used to work
+/// with C side on synchronizations.
+///
+/// # Safety
+///
+/// - `ptr` is a valid pointer to `T` and aligned to `align_of::<T>()`.
+/// - If there is a concurrent access from kernel (C or Rust), it has to be atomic.
+#[inline(always)]
+pub unsafe fn xchg<T: AtomicType, Ordering: ordering::Ordering>(
+ ptr: *mut T,
+ new: T,
+ o: Ordering,
+) -> T
+where
+ T::Repr: AtomicExchangeOps,
+{
+ // SAFETY: Per the function safety requirement, `ptr` is valid and aligned to
+ // `align_of::<T>()`, and all concurrent accesses from kernel are atomic, hence no data race
+ // per LKMM.
+ unsafe { Atomic::from_ptr(ptr) }.xchg(new, o)
+}
+
+/// Atomic compare and exchange over raw pointers.
+///
+/// This function provides a short-cut of `Atomic::from_ptr().cmpxchg(..)`, and can be used to work
+/// with C side on synchronizations.
+///
+/// # Safety
+///
+/// - `ptr` is a valid pointer to `T` and aligned to `align_of::<T>()`.
+/// - If there is a concurrent access from kernel (C or Rust), it has to be atomic.
+#[doc(alias("try_cmpxchg"))]
+#[inline(always)]
+pub unsafe fn cmpxchg<T: AtomicType, Ordering: ordering::Ordering>(
+ ptr: *mut T,
+ old: T,
+ new: T,
+ o: Ordering,
+) -> Result<T, T>
+where
+ T::Repr: AtomicExchangeOps,
+{
+ // SAFETY: Per the function safety requirement, `ptr` is valid and aligned to
+ // `align_of::<T>()`, and all concurrent accesses from kernel are atomic, hence no data race
+ // per LKMM.
+ unsafe { Atomic::from_ptr(ptr) }.cmpxchg(old, new, o)
+}