diff options
author | Andreas Hindborg <a.hindborg@samsung.com> | 2023-09-04 13:48:26 +0200 |
---|---|---|
committer | Danilo Krummrich <dakr@redhat.com> | 2023-11-22 22:01:11 +0100 |
commit | b8c8b3710e29339c735550c67615ee61bc4a22fe (patch) | |
tree | 4f722e3f722153ac2fde95d47c6aad1968746dc6 | |
parent | ba5544722b37a806c3c0266f56a26467d6e7e809 (diff) |
rust: add atomic optional
Based on
https://github.com/wedsonaf/linux/commit/02541e65a7e778c0049fed86ae49302bc07abed3
-rw-r--r-- | rust/kernel/types.rs | 51 |
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); + } +} |