mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 16:41:58 +00:00
188 lines
7.3 KiB
Rust
188 lines
7.3 KiB
Rust
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||
|
|
||
|
//! API to safely and fallibly initialize pinned `struct`s using in-place constructors.
|
||
|
//!
|
||
|
//! It also allows in-place initialization of big `struct`s that would otherwise produce a stack
|
||
|
//! overflow.
|
||
|
//!
|
||
|
//! Most `struct`s from the [`sync`] module need to be pinned, because they contain self-referential
|
||
|
//! `struct`s from C. [Pinning][pinning] is Rust's way of ensuring data does not move.
|
||
|
//!
|
||
|
//! # Overview
|
||
|
//!
|
||
|
//! 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`.
|
||
|
//!
|
||
|
//! To get an in-place constructor there are generally two options:
|
||
|
//! - a custom function/macro returning an in-place constructor provided by someone else,
|
||
|
//! - using the unsafe function [`pin_init_from_closure()`] to manually create an initializer.
|
||
|
//!
|
||
|
//! Aside from pinned initialization, this API also supports in-place construction without pinning,
|
||
|
//! the macros/types/functions are generally named like the pinned variants without the `pin`
|
||
|
//! prefix.
|
||
|
//!
|
||
|
//! [`sync`]: kernel::sync
|
||
|
//! [pinning]: https://doc.rust-lang.org/std/pin/index.html
|
||
|
//! [structurally pinned fields]:
|
||
|
//! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field
|
||
|
//! [`Arc<T>`]: crate::sync::Arc
|
||
|
//! [`impl PinInit<Foo>`]: PinInit
|
||
|
//! [`impl PinInit<T, E>`]: PinInit
|
||
|
//! [`impl Init<T, E>`]: Init
|
||
|
//! [`Opaque`]: kernel::types::Opaque
|
||
|
//! [`pin_data`]: ::macros::pin_data
|
||
|
//! [`UniqueArc<T>`]: kernel::sync::UniqueArc
|
||
|
//! [`Box<T>`]: alloc::boxed::Box
|
||
|
|
||
|
use core::{convert::Infallible, marker::PhantomData, mem::MaybeUninit};
|
||
|
|
||
|
#[doc(hidden)]
|
||
|
pub mod __internal;
|
||
|
|
||
|
/// 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 [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`].
|
||
|
///
|
||
|
/// Also see the [module description](self).
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// When implementing this type you will need to take great care. Also there are probably very few
|
||
|
/// cases where a manual implementation is necessary. Use [`pin_init_from_closure`] where possible.
|
||
|
///
|
||
|
/// The [`PinInit::__pinned_init`] function
|
||
|
/// - returns `Ok(())` if it initialized every field of `slot`,
|
||
|
/// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means:
|
||
|
/// - `slot` can be deallocated without UB occurring,
|
||
|
/// - `slot` does not need to be dropped,
|
||
|
/// - `slot` is not partially initialized.
|
||
|
/// - 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
|
||
|
/// [`UniqueArc<T>`]: kernel::sync::UniqueArc
|
||
|
/// [`Box<T>`]: alloc::boxed::Box
|
||
|
#[must_use = "An initializer must be used in order to create its value."]
|
||
|
pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
|
||
|
/// Initializes `slot`.
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// - `slot` is a valid pointer to uninitialized memory.
|
||
|
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted to
|
||
|
/// deallocate.
|
||
|
/// - `slot` will not move until it is dropped, i.e. it will be pinned.
|
||
|
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 [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Because [`PinInit<T, E>`] is a super trait, you can
|
||
|
/// use every function that takes it as well.
|
||
|
///
|
||
|
/// Also see the [module description](self).
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// When implementing this type you will need to take great care. Also there are probably very few
|
||
|
/// cases where a manual implementation is necessary. Use [`init_from_closure`] where possible.
|
||
|
///
|
||
|
/// The [`Init::__init`] function
|
||
|
/// - returns `Ok(())` if it initialized every field of `slot`,
|
||
|
/// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means:
|
||
|
/// - `slot` can be deallocated without UB occurring,
|
||
|
/// - `slot` does not need to be dropped,
|
||
|
/// - `slot` is not partially initialized.
|
||
|
/// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`.
|
||
|
///
|
||
|
/// The `__pinned_init` function from the supertrait [`PinInit`] needs to execute the exact same
|
||
|
/// code as `__init`.
|
||
|
///
|
||
|
/// Contrary to its supertype [`PinInit<T, E>`] the caller is allowed to
|
||
|
/// move the pointee after initialization.
|
||
|
///
|
||
|
/// [`Arc<T>`]: crate::sync::Arc
|
||
|
/// [`UniqueArc<T>`]: kernel::sync::UniqueArc
|
||
|
/// [`Box<T>`]: alloc::boxed::Box
|
||
|
#[must_use = "An initializer must be used in order to create its value."]
|
||
|
pub unsafe trait Init<T: ?Sized, E = Infallible>: Sized {
|
||
|
/// Initializes `slot`.
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// - `slot` is a valid pointer to uninitialized memory.
|
||
|
/// - the caller does not touch `slot` when `Err` is returned, they are only permitted to
|
||
|
/// deallocate.
|
||
|
unsafe fn __init(self, slot: *mut T) -> Result<(), E>;
|
||
|
}
|
||
|
|
||
|
// SAFETY: Every in-place initializer can also be used as a pin-initializer.
|
||
|
unsafe impl<T: ?Sized, E, I> PinInit<T, E> for I
|
||
|
where
|
||
|
I: Init<T, E>,
|
||
|
{
|
||
|
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
|
||
|
// SAFETY: `__init` meets the same requirements as `__pinned_init`, except that it does not
|
||
|
// require `slot` to not move after init.
|
||
|
unsafe { self.__init(slot) }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Creates a new [`PinInit<T, E>`] from the given closure.
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// The closure:
|
||
|
/// - returns `Ok(())` if it initialized every field of `slot`,
|
||
|
/// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means:
|
||
|
/// - `slot` can be deallocated without UB occurring,
|
||
|
/// - `slot` does not need to be dropped,
|
||
|
/// - `slot` is not partially initialized.
|
||
|
/// - may assume that the `slot` does not move if `T: !Unpin`,
|
||
|
/// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`.
|
||
|
#[inline]
|
||
|
pub const unsafe fn pin_init_from_closure<T: ?Sized, E>(
|
||
|
f: impl FnOnce(*mut T) -> Result<(), E>,
|
||
|
) -> impl PinInit<T, E> {
|
||
|
__internal::InitClosure(f, PhantomData)
|
||
|
}
|
||
|
|
||
|
/// Creates a new [`Init<T, E>`] from the given closure.
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// The closure:
|
||
|
/// - returns `Ok(())` if it initialized every field of `slot`,
|
||
|
/// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means:
|
||
|
/// - `slot` can be deallocated without UB occurring,
|
||
|
/// - `slot` does not need to be dropped,
|
||
|
/// - `slot` is not partially initialized.
|
||
|
/// - the `slot` may move after initialization.
|
||
|
/// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`.
|
||
|
#[inline]
|
||
|
pub const unsafe fn init_from_closure<T: ?Sized, E>(
|
||
|
f: impl FnOnce(*mut T) -> Result<(), E>,
|
||
|
) -> impl Init<T, E> {
|
||
|
__internal::InitClosure(f, PhantomData)
|
||
|
}
|
||
|
|
||
|
/// An initializer that leaves the memory uninitialized.
|
||
|
///
|
||
|
/// The initializer is a no-op. The `slot` memory is not changed.
|
||
|
#[inline]
|
||
|
pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> {
|
||
|
// SAFETY: The memory is allowed to be uninitialized.
|
||
|
unsafe { init_from_closure(|_| Ok(())) }
|
||
|
}
|
||
|
|
||
|
// SAFETY: Every type can be initialized by-value.
|
||
|
unsafe impl<T> Init<T> for T {
|
||
|
unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> {
|
||
|
unsafe { slot.write(self) };
|
||
|
Ok(())
|
||
|
}
|
||
|
}
|