summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Hindborg <a.hindborg@samsung.com>2023-09-04 13:48:26 +0200
committerDanilo Krummrich <dakr@redhat.com>2023-11-22 22:01:11 +0100
commitb8c8b3710e29339c735550c67615ee61bc4a22fe (patch)
tree4f722e3f722153ac2fde95d47c6aad1968746dc6
parentba5544722b37a806c3c0266f56a26467d6e7e809 (diff)
rust: add atomic optional
Based on https://github.com/wedsonaf/linux/commit/02541e65a7e778c0049fed86ae49302bc07abed3
-rw-r--r--rust/kernel/types.rs51
1 files changed, 51 insertions, 0 deletions
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index fdb778e65d79..0836b975dc08 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -10,6 +10,7 @@ use core::{
mem::MaybeUninit,
ops::{Deref, DerefMut},
ptr::NonNull,
+ sync::atomic::{AtomicPtr, Ordering},
};
/// Used to transfer ownership to and from foreign (non-Rust) languages.
@@ -387,3 +388,53 @@ pub enum Either<L, R> {
/// Constructs an instance of [`Either`] containing a value of type `R`.
Right(R),
}
+
+/// An optional atomic boxed value.
+pub struct AtomicOptionalBoxedPtr<T> {
+ ptr: AtomicPtr<T>,
+}
+
+impl<T> AtomicOptionalBoxedPtr<T> {
+ /// Creates a new instance with the given value.
+ pub fn new(value: Option<Box<T>>) -> Self {
+ Self {
+ ptr: AtomicPtr::new(Self::to_ptr(value)),
+ }
+ }
+
+ fn to_ptr(value: Option<Box<T>>) -> *mut T {
+ if let Some(v) = value {
+ Box::into_raw(v)
+ } else {
+ core::ptr::null_mut()
+ }
+ }
+
+ /// Swaps the existing boxed value with the given one.
+ pub fn swap(&self, value: Option<Box<T>>, order: Ordering) -> Option<Box<T>> {
+ let ptr = self.ptr.swap(Self::to_ptr(value), order);
+ if ptr.is_null() {
+ return None;
+ }
+ // SAFETY: All non-null values that are stored come from `Box::into_raw`. Additionally,
+ // they are always swapped by something else when read.
+ Some(unsafe { Box::from_raw(ptr) })
+ }
+
+ /// Stores a new value. The previous value is dropped.
+ pub fn store(&self, value: Option<Box<T>>, order: Ordering) {
+ self.swap(value, order);
+ }
+
+ /// Stores a new value and returns the old one.
+ pub fn take(&self, order: Ordering) -> Option<Box<T>> {
+ self.swap(None, order)
+ }
+}
+
+impl<T> Drop for AtomicOptionalBoxedPtr<T> {
+ fn drop(&mut self) {
+ // Noone else has a reference to this object.
+ self.take(Ordering::Relaxed);
+ }
+}