Commit 08f983a5 authored by Alex Mantel's avatar Alex Mantel Committed by Miguel Ojeda
Browse files

rust: Implement the smart pointer `InPlaceInit` for `Arc`

For pinned and unpinned initialization of structs, a trait named
`InPlaceInit` exists for uniform access. `Arc` did not implement
`InPlaceInit` yet, although the functions already existed. The main
reason for that, was that the trait itself returned a `Pin<Self>`. The
`Arc` implementation of the kernel is already implicitly pinned.

To enable `Arc` to implement `InPlaceInit` and to have uniform access,
for in-place and pinned in-place initialization, an associated type is
introduced for `InPlaceInit`. The new implementation of `InPlaceInit`
for `Arc` sets `Arc` as the associated type. Older implementations use
an explicit `Pin<T>` as the associated type. The implemented methods for
`Arc` are mostly moved from a direct implementation on `Arc`. There
should be no user impact. The implementation for `ListArc` is omitted,
because it is not merged yet.

Link: https://github.com/Rust-for-Linux/linux/issues/1079


Signed-off-by: default avatarAlex Mantel <alexmantel93@mailbox.org>
Reviewed-by: default avatarAlice Ryhl <aliceryhl@google.com>
Reviewed-by: default avatarBenno Lossin <benno.lossin@proton.me>
Link: https://lore.kernel.org/r/20240727042442.682109-1-alexmantel93@mailbox.org


[ Removed "Rusts" (Benno). - Miguel ]
Signed-off-by: default avatarMiguel Ojeda <ojeda@kernel.org>
parent 47ac09b9
Loading
Loading
Loading
Loading
+35 −4
Original line number Diff line number Diff line
@@ -213,6 +213,7 @@
use crate::{
    alloc::{box_ext::BoxExt, AllocError, Flags},
    error::{self, Error},
    sync::Arc,
    sync::UniqueArc,
    types::{Opaque, ScopeGuard},
};
@@ -1107,11 +1108,17 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {

/// Smart pointer that can initialize memory in-place.
pub trait InPlaceInit<T>: Sized {
    /// Pinned version of `Self`.
    ///
    /// If a type already implicitly pins its pointee, `Pin<Self>` is unnecessary. In this case use
    /// `Self`, otherwise just use `Pin<Self>`.
    type PinnedSelf;

    /// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
    /// type.
    ///
    /// If `T: !Unpin` it will not be able to move afterwards.
    fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
    fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
    where
        E: From<AllocError>;

@@ -1119,7 +1126,7 @@ fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>,
    /// type.
    ///
    /// If `T: !Unpin` it will not be able to move afterwards.
    fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Pin<Self>>
    fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Self::PinnedSelf>
    where
        Error: From<E>,
    {
@@ -1148,9 +1155,31 @@ fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
    }
}

impl<T> InPlaceInit<T> for Arc<T> {
    type PinnedSelf = Self;

    #[inline]
    fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
    where
        E: From<AllocError>,
    {
        UniqueArc::try_pin_init(init, flags).map(|u| u.into())
    }

    #[inline]
    fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
    where
        E: From<AllocError>,
    {
        UniqueArc::try_init(init, flags).map(|u| u.into())
    }
}

impl<T> InPlaceInit<T> for Box<T> {
    type PinnedSelf = Pin<Self>;

    #[inline]
    fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
    fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
    where
        E: From<AllocError>,
    {
@@ -1179,8 +1208,10 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
}

impl<T> InPlaceInit<T> for UniqueArc<T> {
    type PinnedSelf = Pin<Self>;

    #[inline]
    fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, E>
    fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
    where
        E: From<AllocError>,
    {
+2 −23
Original line number Diff line number Diff line
@@ -12,12 +12,13 @@
//! 2. It does not support weak references, which allows it to be half the size.
//! 3. It saturates the reference count instead of aborting when it goes over a threshold.
//! 4. It does not provide a `get_mut` method, so the ref counted object is pinned.
//! 5. The object in [`Arc`] is pinned implicitly.
//!
//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html

use crate::{
    alloc::{box_ext::BoxExt, AllocError, Flags},
    error::{self, Error},
    bindings,
    init::{self, InPlaceInit, Init, PinInit},
    try_init,
    types::{ForeignOwnable, Opaque},
@@ -209,28 +210,6 @@ pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
        // `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>, flags: Flags) -> error::Result<Self>
    where
        Error: From<E>,
    {
        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>, flags: Flags) -> error::Result<Self>
    where
        Error: From<E>,
    {
        UniqueArc::init(init, flags).map(|u| u.into())
    }
}

impl<T: ?Sized> Arc<T> {