diff options
Diffstat (limited to 'rust/kernel/sync/arc.rs')
-rw-r--r-- | rust/kernel/sync/arc.rs | 108 |
1 files changed, 102 insertions, 6 deletions
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index f2f1c83d72ba..e6d206242465 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -17,17 +17,24 @@ use crate::{ bindings, - error::Result, + error::{self, Error}, + init::{self, InPlaceInit, Init, PinInit}, + try_init, types::{ForeignOwnable, Opaque}, }; use alloc::boxed::Box; use core::{ + alloc::AllocError, + fmt, marker::{PhantomData, Unsize}, mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, pin::Pin, ptr::NonNull, }; +use macros::pin_data; + +mod std_vendor; /// A reference-counted pointer to an instance of `T`. /// @@ -120,6 +127,7 @@ pub struct Arc<T: ?Sized> { _p: PhantomData<ArcInner<T>>, } +#[pin_data] #[repr(C)] struct ArcInner<T: ?Sized> { refcount: Opaque<bindings::refcount_t>, @@ -149,7 +157,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> { + pub fn try_new(contents: T) -> 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. @@ -163,6 +171,28 @@ impl<T> Arc<T> { // `Arc` object. Ok(unsafe { Self::from_inner(Box::leak(inner).into()) }) } + + /// Use the given initializer to in-place initialize a `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> + where + Error: From<E>, + { + UniqueArc::pin_init(init).map(|u| u.into()) + } + + /// Use the given initializer to in-place initialize a `T`. + /// + /// This is equivalent to [`pin_init`], since an [`Arc`] is always pinned. + #[inline] + pub fn init<E>(init: impl Init<T, E>) -> error::Result<Self> + where + Error: From<E>, + { + UniqueArc::init(init).map(|u| u.into()) + } } impl<T: ?Sized> Arc<T> { @@ -469,7 +499,7 @@ pub struct UniqueArc<T: ?Sized> { impl<T> UniqueArc<T> { /// Tries to allocate a new [`UniqueArc`] instance. - pub fn try_new(value: T) -> Result<Self> { + pub fn try_new(value: T) -> Result<Self, AllocError> { Ok(Self { // INVARIANT: The newly-created object has a ref-count of 1. inner: Arc::try_new(value)?, @@ -477,10 +507,17 @@ impl<T> UniqueArc<T> { } /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet. - pub fn try_new_uninit() -> Result<UniqueArc<MaybeUninit<T>>> { - Ok(UniqueArc::<MaybeUninit<T>> { + pub fn try_new_uninit() -> 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))?; + Ok(UniqueArc { // INVARIANT: The newly-created object has a ref-count of 1. - inner: Arc::try_new(MaybeUninit::uninit())?, + // SAFETY: The pointer from the `Box` is valid. + inner: unsafe { Arc::from_inner(Box::leak(inner).into()) }, }) } } @@ -489,6 +526,17 @@ impl<T> UniqueArc<MaybeUninit<T>> { /// Converts a `UniqueArc<MaybeUninit<T>>` into a `UniqueArc<T>` by writing a value into it. pub fn write(mut self, value: T) -> UniqueArc<T> { self.deref_mut().write(value); + // SAFETY: We just wrote the value to be initialized. + unsafe { self.assume_init() } + } + + /// Unsafely assume that `self` is initialized. + /// + /// # Safety + /// + /// The caller guarantees that the value behind this pointer has been initialized. It is + /// *immediate* UB to call this when the value is not initialized. + pub unsafe fn assume_init(self) -> UniqueArc<T> { let inner = ManuallyDrop::new(self).inner.ptr; UniqueArc { // SAFETY: The new `Arc` is taking over `ptr` from `self.inner` (which won't be @@ -496,6 +544,30 @@ impl<T> UniqueArc<MaybeUninit<T>> { inner: unsafe { Arc::from_inner(inner.cast()) }, } } + + /// Initialize `self` using the given initializer. + pub fn init_with<E>(mut self, init: impl Init<T, E>) -> core::result::Result<UniqueArc<T>, E> { + // SAFETY: The supplied pointer is valid for initialization. + match unsafe { init.__init(self.as_mut_ptr()) } { + // SAFETY: Initialization completed successfully. + Ok(()) => Ok(unsafe { self.assume_init() }), + Err(err) => Err(err), + } + } + + /// Pin-initialize `self` using the given pin-initializer. + pub fn pin_init_with<E>( + mut self, + init: impl PinInit<T, E>, + ) -> core::result::Result<Pin<UniqueArc<T>>, E> { + // SAFETY: The supplied pointer is valid for initialization and we will later pin the value + // to ensure it does not move. + match unsafe { init.__pinned_init(self.as_mut_ptr()) } { + // SAFETY: Initialization completed successfully. + Ok(()) => Ok(unsafe { self.assume_init() }.into()), + Err(err) => Err(err), + } + } } impl<T: ?Sized> From<UniqueArc<T>> for Pin<UniqueArc<T>> { @@ -522,3 +594,27 @@ impl<T: ?Sized> DerefMut for UniqueArc<T> { unsafe { &mut self.inner.ptr.as_mut().data } } } + +impl<T: fmt::Display + ?Sized> fmt::Display for UniqueArc<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.deref(), f) + } +} + +impl<T: fmt::Display + ?Sized> fmt::Display for Arc<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.deref(), f) + } +} + +impl<T: fmt::Debug + ?Sized> fmt::Debug for UniqueArc<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.deref(), f) + } +} + +impl<T: fmt::Debug + ?Sized> fmt::Debug for Arc<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.deref(), f) + } +} |