diff options
Diffstat (limited to 'rust/kernel/sync/arc.rs')
| -rw-r--r-- | rust/kernel/sync/arc.rs | 189 | 
1 files changed, 147 insertions, 42 deletions
| diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 7d4c4bf58388..3673496c2363 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -16,7 +16,7 @@  //! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html  use crate::{ -    bindings, +    alloc::{box_ext::BoxExt, AllocError, Flags},      error::{self, Error},      init::{self, InPlaceInit, Init, PinInit},      try_init, @@ -24,7 +24,7 @@ use crate::{  };  use alloc::boxed::Box;  use core::{ -    alloc::{AllocError, Layout}, +    alloc::Layout,      fmt,      marker::{PhantomData, Unsize},      mem::{ManuallyDrop, MaybeUninit}, @@ -57,7 +57,7 @@ mod std_vendor;  /// }  ///  /// // Create a refcounted instance of `Example`. -/// let obj = Arc::try_new(Example { a: 10, b: 20 })?; +/// let obj = Arc::new(Example { a: 10, b: 20 }, GFP_KERNEL)?;  ///  /// // Get a new pointer to `obj` and increment the refcount.  /// let cloned = obj.clone(); @@ -96,7 +96,7 @@ mod std_vendor;  ///     }  /// }  /// -/// let obj = Arc::try_new(Example { a: 10, b: 20 })?; +/// let obj = Arc::new(Example { a: 10, b: 20 }, GFP_KERNEL)?;  /// obj.use_reference();  /// obj.take_over();  /// # Ok::<(), Error>(()) @@ -119,7 +119,7 @@ mod std_vendor;  /// impl MyTrait for Example {}  ///  /// // `obj` has type `Arc<Example>`. -/// let obj: Arc<Example> = Arc::try_new(Example)?; +/// let obj: Arc<Example> = Arc::new(Example, GFP_KERNEL)?;  ///  /// // `coerced` has type `Arc<dyn MyTrait>`.  /// let coerced: Arc<dyn MyTrait> = obj; @@ -137,6 +137,39 @@ struct ArcInner<T: ?Sized> {      data: T,  } +impl<T: ?Sized> ArcInner<T> { +    /// Converts a pointer to the contents of an [`Arc`] into a pointer to the [`ArcInner`]. +    /// +    /// # Safety +    /// +    /// `ptr` must have been returned by a previous call to [`Arc::into_raw`], and the `Arc` must +    /// not yet have been destroyed. +    unsafe fn container_of(ptr: *const T) -> NonNull<ArcInner<T>> { +        let refcount_layout = Layout::new::<bindings::refcount_t>(); +        // SAFETY: The caller guarantees that the pointer is valid. +        let val_layout = Layout::for_value(unsafe { &*ptr }); +        // SAFETY: We're computing the layout of a real struct that existed when compiling this +        // binary, so its layout is not so large that it can trigger arithmetic overflow. +        let val_offset = unsafe { refcount_layout.extend(val_layout).unwrap_unchecked().1 }; + +        // Pointer casts leave the metadata unchanged. This is okay because the metadata of `T` and +        // `ArcInner<T>` is the same since `ArcInner` is a struct with `T` as its last field. +        // +        // This is documented at: +        // <https://doc.rust-lang.org/std/ptr/trait.Pointee.html>. +        let ptr = ptr as *const ArcInner<T>; + +        // SAFETY: The pointer is in-bounds of an allocation both before and after offsetting the +        // pointer, since it originates from a previous call to `Arc::into_raw` on an `Arc` that is +        // still valid. +        let ptr = unsafe { ptr.byte_sub(val_offset) }; + +        // SAFETY: The pointer can't be null since you can't have an `ArcInner<T>` value at the null +        // address. +        unsafe { NonNull::new_unchecked(ptr.cast_mut()) } +    } +} +  // This is to allow [`Arc`] (and variants) to be used as the type of `self`.  impl<T: ?Sized> core::ops::Receiver for Arc<T> {} @@ -162,7 +195,7 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}  impl<T> Arc<T> {      /// Constructs a new reference counted instance of `T`. -    pub fn try_new(contents: T) -> Result<Self, AllocError> { +    pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {          // INVARIANT: The refcount is initialised to a non-zero value.          let value = ArcInner {              // SAFETY: There are no safety requirements for this FFI call. @@ -170,7 +203,7 @@ impl<T> Arc<T> {              data: contents,          }; -        let inner = Box::try_new(value)?; +        let inner = <Box<_> as BoxExt<_>>::new(value, flags)?;          // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new          // `Arc` object. @@ -181,22 +214,22 @@ impl<T> Arc<T> {      ///      /// If `T: !Unpin` it will not be able to move afterwards.      #[inline] -    pub fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Self> +    pub fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Self>      where          Error: From<E>,      { -        UniqueArc::pin_init(init).map(|u| u.into()) +        UniqueArc::pin_init(init, flags).map(|u| u.into())      }      /// Use the given initializer to in-place initialize a `T`.      ///      /// This is equivalent to [`Arc<T>::pin_init`], since an [`Arc`] is always pinned.      #[inline] -    pub fn init<E>(init: impl Init<T, E>) -> error::Result<Self> +    pub fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>      where          Error: From<E>,      { -        UniqueArc::init(init).map(|u| u.into()) +        UniqueArc::init(init, flags).map(|u| u.into())      }  } @@ -232,27 +265,13 @@ impl<T: ?Sized> Arc<T> {      /// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it      /// must not be called more than once for each previous call to [`Arc::into_raw`].      pub unsafe fn from_raw(ptr: *const T) -> Self { -        let refcount_layout = Layout::new::<bindings::refcount_t>(); -        // SAFETY: The caller guarantees that the pointer is valid. -        let val_layout = Layout::for_value(unsafe { &*ptr }); -        // SAFETY: We're computing the layout of a real struct that existed when compiling this -        // binary, so its layout is not so large that it can trigger arithmetic overflow. -        let val_offset = unsafe { refcount_layout.extend(val_layout).unwrap_unchecked().1 }; - -        // Pointer casts leave the metadata unchanged. This is okay because the metadata of `T` and -        // `ArcInner<T>` is the same since `ArcInner` is a struct with `T` as its last field. -        // -        // This is documented at: -        // <https://doc.rust-lang.org/std/ptr/trait.Pointee.html>. -        let ptr = ptr as *const ArcInner<T>; - -        // SAFETY: The pointer is in-bounds of an allocation both before and after offsetting the -        // pointer, since it originates from a previous call to `Arc::into_raw` and is still valid. -        let ptr = unsafe { ptr.byte_sub(val_offset) }; +        // SAFETY: The caller promises that this pointer originates from a call to `into_raw` on an +        // `Arc` that is still valid. +        let ptr = unsafe { ArcInner::container_of(ptr) };          // SAFETY: By the safety requirements we know that `ptr` came from `Arc::into_raw`, so the          // reference count held then will be owned by the new `Arc` object. -        unsafe { Self::from_inner(NonNull::new_unchecked(ptr.cast_mut())) } +        unsafe { Self::from_inner(ptr) }      }      /// Returns an [`ArcBorrow`] from the given [`Arc`]. @@ -271,6 +290,68 @@ impl<T: ?Sized> Arc<T> {      pub fn ptr_eq(this: &Self, other: &Self) -> bool {          core::ptr::eq(this.ptr.as_ptr(), other.ptr.as_ptr())      } + +    /// Converts this [`Arc`] into a [`UniqueArc`], or destroys it if it is not unique. +    /// +    /// When this destroys the `Arc`, it does so while properly avoiding races. This means that +    /// this method will never call the destructor of the value. +    /// +    /// # Examples +    /// +    /// ``` +    /// use kernel::sync::{Arc, UniqueArc}; +    /// +    /// let arc = Arc::new(42, GFP_KERNEL)?; +    /// let unique_arc = arc.into_unique_or_drop(); +    /// +    /// // The above conversion should succeed since refcount of `arc` is 1. +    /// assert!(unique_arc.is_some()); +    /// +    /// assert_eq!(*(unique_arc.unwrap()), 42); +    /// +    /// # Ok::<(), Error>(()) +    /// ``` +    /// +    /// ``` +    /// use kernel::sync::{Arc, UniqueArc}; +    /// +    /// let arc = Arc::new(42, GFP_KERNEL)?; +    /// let another = arc.clone(); +    /// +    /// let unique_arc = arc.into_unique_or_drop(); +    /// +    /// // The above conversion should fail since refcount of `arc` is >1. +    /// assert!(unique_arc.is_none()); +    /// +    /// # Ok::<(), Error>(()) +    /// ``` +    pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> { +        // We will manually manage the refcount in this method, so we disable the destructor. +        let me = ManuallyDrop::new(self); +        // SAFETY: We own a refcount, so the pointer is still valid. +        let refcount = unsafe { me.ptr.as_ref() }.refcount.get(); + +        // If the refcount reaches a non-zero value, then we have destroyed this `Arc` and will +        // return without further touching the `Arc`. If the refcount reaches zero, then there are +        // no other arcs, and we can create a `UniqueArc`. +        // +        // SAFETY: We own a refcount, so the pointer is not dangling. +        let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) }; +        if is_zero { +            // SAFETY: We have exclusive access to the arc, so we can perform unsynchronized +            // accesses to the refcount. +            unsafe { core::ptr::write(refcount, bindings::REFCOUNT_INIT(1)) }; + +            // INVARIANT: We own the only refcount to this arc, so we may create a `UniqueArc`. We +            // must pin the `UniqueArc` because the values was previously in an `Arc`, and they pin +            // their values. +            Some(Pin::from(UniqueArc { +                inner: ManuallyDrop::into_inner(me), +            })) +        } else { +            None +        } +    }  }  impl<T: 'static> ForeignOwnable for Arc<T> { @@ -387,7 +468,7 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {  ///     e.into()  /// }  /// -/// let obj = Arc::try_new(Example)?; +/// let obj = Arc::new(Example, GFP_KERNEL)?;  /// let cloned = do_something(obj.as_arc_borrow());  ///  /// // Assert that both `obj` and `cloned` point to the same underlying object. @@ -411,7 +492,7 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {  ///     }  /// }  /// -/// let obj = Arc::try_new(Example { a: 10, b: 20 })?; +/// let obj = Arc::new(Example { a: 10, b: 20 }, GFP_KERNEL)?;  /// obj.as_arc_borrow().use_reference();  /// # Ok::<(), Error>(())  /// ``` @@ -453,6 +534,27 @@ impl<T: ?Sized> ArcBorrow<'_, T> {              _p: PhantomData,          }      } + +    /// Creates an [`ArcBorrow`] to an [`Arc`] that has previously been deconstructed with +    /// [`Arc::into_raw`]. +    /// +    /// # Safety +    /// +    /// * The provided pointer must originate from a call to [`Arc::into_raw`]. +    /// * For the duration of the lifetime annotated on this `ArcBorrow`, the reference count must +    ///   not hit zero. +    /// * For the duration of the lifetime annotated on this `ArcBorrow`, there must not be a +    ///   [`UniqueArc`] reference to this value. +    pub unsafe fn from_raw(ptr: *const T) -> Self { +        // SAFETY: The caller promises that this pointer originates from a call to `into_raw` on an +        // `Arc` that is still valid. +        let ptr = unsafe { ArcInner::container_of(ptr) }; + +        // SAFETY: The caller promises that the value remains valid since the reference count must +        // not hit zero, and no mutable reference will be created since that would involve a +        // `UniqueArc`. +        unsafe { Self::new(ptr) } +    }  }  impl<T: ?Sized> From<ArcBorrow<'_, T>> for Arc<T> { @@ -499,7 +601,7 @@ impl<T: ?Sized> Deref for ArcBorrow<'_, T> {  /// }  ///  /// fn test() -> Result<Arc<Example>> { -///     let mut x = UniqueArc::try_new(Example { a: 10, b: 20 })?; +///     let mut x = UniqueArc::new(Example { a: 10, b: 20 }, GFP_KERNEL)?;  ///     x.a += 1;  ///     x.b += 1;  ///     Ok(x.into()) @@ -522,7 +624,7 @@ impl<T: ?Sized> Deref for ArcBorrow<'_, T> {  /// }  ///  /// fn test() -> Result<Arc<Example>> { -///     let x = UniqueArc::try_new_uninit()?; +///     let x = UniqueArc::new_uninit(GFP_KERNEL)?;  ///     Ok(x.write(Example { a: 10, b: 20 }).into())  /// }  /// @@ -542,7 +644,7 @@ impl<T: ?Sized> Deref for ArcBorrow<'_, T> {  /// }  ///  /// fn test() -> Result<Arc<Example>> { -///     let mut pinned = Pin::from(UniqueArc::try_new(Example { a: 10, b: 20 })?); +///     let mut pinned = Pin::from(UniqueArc::new(Example { a: 10, b: 20 }, GFP_KERNEL)?);  ///     // We can modify `pinned` because it is `Unpin`.  ///     pinned.as_mut().a += 1;  ///     Ok(pinned.into()) @@ -556,21 +658,24 @@ pub struct UniqueArc<T: ?Sized> {  impl<T> UniqueArc<T> {      /// Tries to allocate a new [`UniqueArc`] instance. -    pub fn try_new(value: T) -> Result<Self, AllocError> { +    pub fn new(value: T, flags: Flags) -> Result<Self, AllocError> {          Ok(Self {              // INVARIANT: The newly-created object has a refcount of 1. -            inner: Arc::try_new(value)?, +            inner: Arc::new(value, flags)?,          })      }      /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet. -    pub fn try_new_uninit() -> Result<UniqueArc<MaybeUninit<T>>, AllocError> { +    pub fn new_uninit(flags: Flags) -> Result<UniqueArc<MaybeUninit<T>>, AllocError> {          // INVARIANT: The refcount is initialised to a non-zero value. -        let inner = Box::try_init::<AllocError>(try_init!(ArcInner { -            // SAFETY: There are no safety requirements for this FFI call. -            refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }), -            data <- init::uninit::<T, AllocError>(), -        }? AllocError))?; +        let inner = Box::try_init::<AllocError>( +            try_init!(ArcInner { +                // SAFETY: There are no safety requirements for this FFI call. +                refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }), +                data <- init::uninit::<T, AllocError>(), +            }? AllocError), +            flags, +        )?;          Ok(UniqueArc {              // INVARIANT: The newly-created object has a refcount of 1.              // SAFETY: The pointer from the `Box` is valid. |