Commit 114ca41f authored by Benno Lossin's avatar Benno Lossin Committed by Miguel Ojeda
Browse files

rust: pin-init: move `InPlaceInit` and impls of `InPlaceWrite` into the kernel crate



In order to make pin-init a standalone crate, move kernel-specific code
directly into the kernel crate. This includes the `InPlaceInit<T>`
trait, its implementations and the implementations of `InPlaceWrite` for
`Arc` and `UniqueArc`. All of these use the kernel's error type which
will become unavailable in pin-init.

Signed-off-by: default avatarBenno Lossin <benno.lossin@proton.me>
Reviewed-by: default avatarFiona Behrens <me@kloenk.dev>
Tested-by: default avatarAndreas Hindborg <a.hindborg@kernel.org>
Link: https://lore.kernel.org/r/20250308110339.2997091-9-benno.lossin@proton.me


Signed-off-by: default avatarMiguel Ojeda <ojeda@kernel.org>
parent 578eb8b6
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -15,7 +15,8 @@
use core::ptr::NonNull;
use core::result::Result;

use crate::init::{InPlaceInit, InPlaceWrite, Init, PinInit};
use crate::init::{InPlaceWrite, Init, PinInit};
use crate::init_ext::InPlaceInit;
use crate::types::ForeignOwnable;

/// The kernel's [`Box`] type -- a heap allocation for a single value of type `T`.
+55 −0
Original line number Diff line number Diff line
@@ -134,6 +134,61 @@
//! }
//! ```

use crate::{
    alloc::{AllocError, Flags},
    error::{self, Error},
    init::{init_from_closure, pin_init_from_closure, Init, PinInit},
};

/// 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<Self::PinnedSelf, E>
    where
        E: From<AllocError>;

    /// 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 pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Self::PinnedSelf>
    where
        Error: From<E>,
    {
        // SAFETY: We delegate to `init` and only change the error type.
        let init = unsafe {
            pin_init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
        };
        Self::try_pin_init(init, flags)
    }

    /// Use the given initializer to in-place initialize a `T`.
    fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
    where
        E: From<AllocError>;

    /// Use the given initializer to in-place initialize a `T`.
    fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
    where
        Error: From<E>,
    {
        // SAFETY: We delegate to `init` and only change the error type.
        let init = unsafe {
            init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
        };
        Self::try_init(init, flags)
    }
}

/// Construct an in-place fallible initializer for `struct`s.
///
/// This macro defaults the error to [`Error`]. If you need [`Infallible`], then use
+2 −1
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@

pub use super::{str::CStr, ThisModule};

pub use super::init::{InPlaceInit, InPlaceWrite, Init, PinInit};
pub use super::init::{InPlaceWrite, Init, PinInit};
pub use super::init_ext::InPlaceInit;

pub use super::current;
+64 −1
Original line number Diff line number Diff line
@@ -19,7 +19,8 @@
use crate::{
    alloc::{AllocError, Flags, KBox},
    bindings,
    init::{self, InPlaceInit, Init, PinInit},
    init::{self, InPlaceWrite, Init, PinInit},
    init_ext::InPlaceInit,
    try_init,
    types::{ForeignOwnable, Opaque},
};
@@ -202,6 +203,26 @@ unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
// the reference count reaches zero and `T` is dropped.
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}

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> Arc<T> {
    /// Constructs a new reference counted instance of `T`.
    pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
@@ -659,6 +680,48 @@ pub struct UniqueArc<T: ?Sized> {
    inner: Arc<T>,
}

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<Self::PinnedSelf, E>
    where
        E: From<AllocError>,
    {
        UniqueArc::new_uninit(flags)?.write_pin_init(init)
    }

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

impl<T> InPlaceWrite<T> for UniqueArc<MaybeUninit<T>> {
    type Initialized = UniqueArc<T>;

    fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
        let slot = self.as_mut_ptr();
        // SAFETY: When init errors/panics, slot will get deallocated but not dropped,
        // slot is valid.
        unsafe { init.__init(slot)? };
        // SAFETY: All fields have been initialized.
        Ok(unsafe { self.assume_init() })
    }

    fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
        let slot = self.as_mut_ptr();
        // SAFETY: When init errors/panics, slot will get deallocated but not dropped,
        // slot is valid and will not be moved, because we pin it later.
        unsafe { init.__pinned_init(slot)? };
        // SAFETY: All fields have been initialized.
        Ok(unsafe { self.assume_init() }.into())
    }
}

impl<T> UniqueArc<T> {
    /// Tries to allocate a new [`UniqueArc`] instance.
    pub fn new(value: T, flags: Flags) -> Result<Self, AllocError> {
+4 −121
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@
//! To initialize a `struct` with an in-place constructor you will need two things:
//! - an in-place constructor,
//! - a memory location that can hold your `struct` (this can be the [stack], an [`Arc<T>`],
//!   [`UniqueArc<T>`], [`KBox<T>`] or any other smart pointer that implements [`InPlaceInit`]).
//!   [`KBox<T>`] or any other smart pointer that supports this library).
//!
//! To get an in-place constructor there are generally three options:
//! - directly creating an in-place constructor using the [`pin_init!`] macro,
@@ -212,10 +212,7 @@
//! [`pin_init!`]: crate::pin_init!

use crate::{
    alloc::{AllocError, Flags, KBox},
    error::{self, Error},
    sync::Arc,
    sync::UniqueArc,
    alloc::KBox,
    types::{Opaque, ScopeGuard},
};
use core::{
@@ -891,8 +888,7 @@ macro_rules! assert_pinned {
/// A pin-initializer for the type `T`.
///
/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
/// be [`KBox<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use
/// the [`InPlaceInit::pin_init`] function of a smart pointer like [`Arc<T>`] on this.
/// be [`KBox<T>`], [`Arc<T>`] or even the stack (see [`stack_pin_init!`]).
///
/// Also see the [module description](self).
///
@@ -910,7 +906,6 @@ macro_rules! assert_pinned {
/// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`.
///
/// [`Arc<T>`]: crate::sync::Arc
/// [`Arc::pin_init`]: crate::sync::Arc::pin_init
#[must_use = "An initializer must be used in order to create its value."]
pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
    /// Initializes `slot`.
@@ -976,8 +971,7 @@ unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
/// An initializer for `T`.
///
/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
/// be [`KBox<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use
/// the [`InPlaceInit::init`] function of a smart pointer like [`Arc<T>`] on this. Because
/// be [`KBox<T>`], [`Arc<T>`] or even the stack (see [`stack_pin_init!`]). Because
/// [`PinInit<T, E>`] is a super trait, you can use every function that takes it as well.
///
/// Also see the [module description](self).
@@ -1238,95 +1232,6 @@ 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<Self::PinnedSelf, E>
    where
        E: From<AllocError>;

    /// 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 pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Self::PinnedSelf>
    where
        Error: From<E>,
    {
        // SAFETY: We delegate to `init` and only change the error type.
        let init = unsafe {
            pin_init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
        };
        Self::try_pin_init(init, flags)
    }

    /// Use the given initializer to in-place initialize a `T`.
    fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
    where
        E: From<AllocError>;

    /// Use the given initializer to in-place initialize a `T`.
    fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
    where
        Error: From<E>,
    {
        // SAFETY: We delegate to `init` and only change the error type.
        let init = unsafe {
            init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
        };
        Self::try_init(init, flags)
    }
}

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 UniqueArc<T> {
    type PinnedSelf = Pin<Self>;

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

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

/// Smart pointer containing uninitialized memory and that can write a value.
pub trait InPlaceWrite<T> {
    /// The type `Self` turns into when the contents are initialized.
@@ -1343,28 +1248,6 @@ pub trait InPlaceWrite<T> {
    fn write_pin_init<E>(self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E>;
}

impl<T> InPlaceWrite<T> for UniqueArc<MaybeUninit<T>> {
    type Initialized = UniqueArc<T>;

    fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
        let slot = self.as_mut_ptr();
        // SAFETY: When init errors/panics, slot will get deallocated but not dropped,
        // slot is valid.
        unsafe { init.__init(slot)? };
        // SAFETY: All fields have been initialized.
        Ok(unsafe { self.assume_init() })
    }

    fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
        let slot = self.as_mut_ptr();
        // SAFETY: When init errors/panics, slot will get deallocated but not dropped,
        // slot is valid and will not be moved, because we pin it later.
        unsafe { init.__pinned_init(slot)? };
        // SAFETY: All fields have been initialized.
        Ok(unsafe { self.assume_init() }.into())
    }
}

/// Trait facilitating pinned destruction.
///
/// Use [`pinned_drop`] to implement this trait safely: