|
| 1 | +// SPDX-License-Identifier: Apache-2.0 OR MIT |
| 2 | + |
| 3 | +//! API to safely and fallibly initialize pinned `struct`s using in-place constructors. |
| 4 | +//! |
| 5 | +//! It also allows in-place initialization of big `struct`s that would otherwise produce a stack |
| 6 | +//! overflow. |
| 7 | +//! |
| 8 | +//! Most `struct`s from the [`sync`] module need to be pinned, because they contain self-referential |
| 9 | +//! `struct`s from C. [Pinning][pinning] is Rust's way of ensuring data does not move. |
| 10 | +//! |
| 11 | +//! # Overview |
| 12 | +//! |
| 13 | +//! To initialize a `struct` with an in-place constructor you will need two things: |
| 14 | +//! - an in-place constructor, |
| 15 | +//! - a memory location that can hold your `struct`. |
| 16 | +//! |
| 17 | +//! To get an in-place constructor there are generally two options: |
| 18 | +//! - a custom function/macro returning an in-place constructor provided by someone else, |
| 19 | +//! - using the unsafe function [`pin_init_from_closure()`] to manually create an initializer. |
| 20 | +//! |
| 21 | +//! Aside from pinned initialization, this API also supports in-place construction without pinning, |
| 22 | +//! the macros/types/functions are generally named like the pinned variants without the `pin` |
| 23 | +//! prefix. |
| 24 | +//! |
| 25 | +//! [`sync`]: kernel::sync |
| 26 | +//! [pinning]: https://doc.rust-lang.org/std/pin/index.html |
| 27 | +//! [structurally pinned fields]: |
| 28 | +//! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field |
| 29 | +//! [`Arc<T>`]: crate::sync::Arc |
| 30 | +//! [`impl PinInit<Foo>`]: PinInit |
| 31 | +//! [`impl PinInit<T, E>`]: PinInit |
| 32 | +//! [`impl Init<T, E>`]: Init |
| 33 | +//! [`Opaque`]: kernel::types::Opaque |
| 34 | +//! [`pin_data`]: ::macros::pin_data |
| 35 | +//! [`UniqueArc<T>`]: kernel::sync::UniqueArc |
| 36 | +//! [`Box<T>`]: alloc::boxed::Box |
| 37 | +
|
| 38 | +use core::{convert::Infallible, marker::PhantomData, mem::MaybeUninit}; |
| 39 | + |
| 40 | +#[doc(hidden)] |
| 41 | +pub mod __internal; |
| 42 | + |
| 43 | +/// A pin-initializer for the type `T`. |
| 44 | +/// |
| 45 | +/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can |
| 46 | +/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. |
| 47 | +/// |
| 48 | +/// Also see the [module description](self). |
| 49 | +/// |
| 50 | +/// # Safety |
| 51 | +/// |
| 52 | +/// When implementing this type you will need to take great care. Also there are probably very few |
| 53 | +/// cases where a manual implementation is necessary. Use [`pin_init_from_closure`] where possible. |
| 54 | +/// |
| 55 | +/// The [`PinInit::__pinned_init`] function |
| 56 | +/// - returns `Ok(())` if it initialized every field of `slot`, |
| 57 | +/// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: |
| 58 | +/// - `slot` can be deallocated without UB occurring, |
| 59 | +/// - `slot` does not need to be dropped, |
| 60 | +/// - `slot` is not partially initialized. |
| 61 | +/// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. |
| 62 | +/// |
| 63 | +/// [`Arc<T>`]: crate::sync::Arc |
| 64 | +/// [`Arc::pin_init`]: crate::sync::Arc::pin_init |
| 65 | +/// [`UniqueArc<T>`]: kernel::sync::UniqueArc |
| 66 | +/// [`Box<T>`]: alloc::boxed::Box |
| 67 | +#[must_use = "An initializer must be used in order to create its value."] |
| 68 | +pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { |
| 69 | + /// Initializes `slot`. |
| 70 | + /// |
| 71 | + /// # Safety |
| 72 | + /// |
| 73 | + /// - `slot` is a valid pointer to uninitialized memory. |
| 74 | + /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to |
| 75 | + /// deallocate. |
| 76 | + /// - `slot` will not move until it is dropped, i.e. it will be pinned. |
| 77 | + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>; |
| 78 | +} |
| 79 | + |
| 80 | +/// An initializer for `T`. |
| 81 | +/// |
| 82 | +/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can |
| 83 | +/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Because [`PinInit<T, E>`] is a super trait, you can |
| 84 | +/// use every function that takes it as well. |
| 85 | +/// |
| 86 | +/// Also see the [module description](self). |
| 87 | +/// |
| 88 | +/// # Safety |
| 89 | +/// |
| 90 | +/// When implementing this type you will need to take great care. Also there are probably very few |
| 91 | +/// cases where a manual implementation is necessary. Use [`init_from_closure`] where possible. |
| 92 | +/// |
| 93 | +/// The [`Init::__init`] function |
| 94 | +/// - returns `Ok(())` if it initialized every field of `slot`, |
| 95 | +/// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: |
| 96 | +/// - `slot` can be deallocated without UB occurring, |
| 97 | +/// - `slot` does not need to be dropped, |
| 98 | +/// - `slot` is not partially initialized. |
| 99 | +/// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. |
| 100 | +/// |
| 101 | +/// The `__pinned_init` function from the supertrait [`PinInit`] needs to execute the exact same |
| 102 | +/// code as `__init`. |
| 103 | +/// |
| 104 | +/// Contrary to its supertype [`PinInit<T, E>`] the caller is allowed to |
| 105 | +/// move the pointee after initialization. |
| 106 | +/// |
| 107 | +/// [`Arc<T>`]: crate::sync::Arc |
| 108 | +/// [`UniqueArc<T>`]: kernel::sync::UniqueArc |
| 109 | +/// [`Box<T>`]: alloc::boxed::Box |
| 110 | +#[must_use = "An initializer must be used in order to create its value."] |
| 111 | +pub unsafe trait Init<T: ?Sized, E = Infallible>: Sized { |
| 112 | + /// Initializes `slot`. |
| 113 | + /// |
| 114 | + /// # Safety |
| 115 | + /// |
| 116 | + /// - `slot` is a valid pointer to uninitialized memory. |
| 117 | + /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to |
| 118 | + /// deallocate. |
| 119 | + unsafe fn __init(self, slot: *mut T) -> Result<(), E>; |
| 120 | +} |
| 121 | + |
| 122 | +// SAFETY: Every in-place initializer can also be used as a pin-initializer. |
| 123 | +unsafe impl<T: ?Sized, E, I> PinInit<T, E> for I |
| 124 | +where |
| 125 | + I: Init<T, E>, |
| 126 | +{ |
| 127 | + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { |
| 128 | + // SAFETY: `__init` meets the same requirements as `__pinned_init`, except that it does not |
| 129 | + // require `slot` to not move after init. |
| 130 | + unsafe { self.__init(slot) } |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +/// Creates a new [`PinInit<T, E>`] from the given closure. |
| 135 | +/// |
| 136 | +/// # Safety |
| 137 | +/// |
| 138 | +/// The closure: |
| 139 | +/// - returns `Ok(())` if it initialized every field of `slot`, |
| 140 | +/// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: |
| 141 | +/// - `slot` can be deallocated without UB occurring, |
| 142 | +/// - `slot` does not need to be dropped, |
| 143 | +/// - `slot` is not partially initialized. |
| 144 | +/// - may assume that the `slot` does not move if `T: !Unpin`, |
| 145 | +/// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. |
| 146 | +#[inline] |
| 147 | +pub const unsafe fn pin_init_from_closure<T: ?Sized, E>( |
| 148 | + f: impl FnOnce(*mut T) -> Result<(), E>, |
| 149 | +) -> impl PinInit<T, E> { |
| 150 | + __internal::InitClosure(f, PhantomData) |
| 151 | +} |
| 152 | + |
| 153 | +/// Creates a new [`Init<T, E>`] from the given closure. |
| 154 | +/// |
| 155 | +/// # Safety |
| 156 | +/// |
| 157 | +/// The closure: |
| 158 | +/// - returns `Ok(())` if it initialized every field of `slot`, |
| 159 | +/// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: |
| 160 | +/// - `slot` can be deallocated without UB occurring, |
| 161 | +/// - `slot` does not need to be dropped, |
| 162 | +/// - `slot` is not partially initialized. |
| 163 | +/// - the `slot` may move after initialization. |
| 164 | +/// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. |
| 165 | +#[inline] |
| 166 | +pub const unsafe fn init_from_closure<T: ?Sized, E>( |
| 167 | + f: impl FnOnce(*mut T) -> Result<(), E>, |
| 168 | +) -> impl Init<T, E> { |
| 169 | + __internal::InitClosure(f, PhantomData) |
| 170 | +} |
| 171 | + |
| 172 | +/// An initializer that leaves the memory uninitialized. |
| 173 | +/// |
| 174 | +/// The initializer is a no-op. The `slot` memory is not changed. |
| 175 | +#[inline] |
| 176 | +pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> { |
| 177 | + // SAFETY: The memory is allowed to be uninitialized. |
| 178 | + unsafe { init_from_closure(|_| Ok(())) } |
| 179 | +} |
| 180 | + |
| 181 | +// SAFETY: Every type can be initialized by-value. |
| 182 | +unsafe impl<T> Init<T> for T { |
| 183 | + unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> { |
| 184 | + unsafe { slot.write(self) }; |
| 185 | + Ok(()) |
| 186 | + } |
| 187 | +} |
0 commit comments