mirror of
https://github.com/torvalds/linux.git
synced 2025-04-12 06:49:52 +00:00
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: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Fiona Behrens <me@kloenk.dev> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250308110339.2997091-9-benno.lossin@proton.me Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
578eb8b6db
commit
114ca41fe7
@ -15,7 +15,8 @@ use core::pin::Pin;
|
||||
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`.
|
||||
|
@ -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
|
||||
|
@ -36,6 +36,7 @@ pub use super::error::{code::*, Error, Result};
|
||||
|
||||
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;
|
||||
|
@ -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> {
|
||||
|
@ -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 @@ where
|
||||
/// 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 impl<T, E> PinInit<T, E> for T {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user