Benno Lossin | 90e53c5e7 | 2023-04-08 12:25:45 +0000 | [diff] [blame] | 1 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
| 2 | |
| 3 | //! This module contains API-internal items for pin-init. |
| 4 | //! |
| 5 | //! These items must not be used outside of |
| 6 | //! - `kernel/init.rs` |
| 7 | //! - `macros/pin_data.rs` |
| 8 | //! - `macros/pinned_drop.rs` |
| 9 | |
| 10 | use super::*; |
| 11 | |
| 12 | /// See the [nomicon] for what subtyping is. See also [this table]. |
| 13 | /// |
| 14 | /// [nomicon]: https://doc.rust-lang.org/nomicon/subtyping.html |
| 15 | /// [this table]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns |
Benno Lossin | 7f8977a | 2023-08-14 08:47:48 +0000 | [diff] [blame] | 16 | pub(super) type Invariant<T> = PhantomData<fn(*mut T) -> *mut T>; |
Benno Lossin | 90e53c5e7 | 2023-04-08 12:25:45 +0000 | [diff] [blame] | 17 | |
| 18 | /// This is the module-internal type implementing `PinInit` and `Init`. It is unsafe to create this |
| 19 | /// type, since the closure needs to fulfill the same safety requirement as the |
| 20 | /// `__pinned_init`/`__init` functions. |
| 21 | pub(crate) struct InitClosure<F, T: ?Sized, E>(pub(crate) F, pub(crate) Invariant<(E, T)>); |
| 22 | |
| 23 | // SAFETY: While constructing the `InitClosure`, the user promised that it upholds the |
| 24 | // `__init` invariants. |
| 25 | unsafe impl<T: ?Sized, F, E> Init<T, E> for InitClosure<F, T, E> |
| 26 | where |
| 27 | F: FnOnce(*mut T) -> Result<(), E>, |
| 28 | { |
| 29 | #[inline] |
| 30 | unsafe fn __init(self, slot: *mut T) -> Result<(), E> { |
| 31 | (self.0)(slot) |
| 32 | } |
| 33 | } |
Benno Lossin | fc6c6ba | 2023-04-08 12:25:51 +0000 | [diff] [blame] | 34 | |
Benno Lossin | 1a8076a | 2023-08-14 08:47:40 +0000 | [diff] [blame] | 35 | // SAFETY: While constructing the `InitClosure`, the user promised that it upholds the |
| 36 | // `__pinned_init` invariants. |
| 37 | unsafe impl<T: ?Sized, F, E> PinInit<T, E> for InitClosure<F, T, E> |
| 38 | where |
| 39 | F: FnOnce(*mut T) -> Result<(), E>, |
| 40 | { |
| 41 | #[inline] |
| 42 | unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { |
| 43 | (self.0)(slot) |
| 44 | } |
| 45 | } |
| 46 | |
Benno Lossin | fc6c6ba | 2023-04-08 12:25:51 +0000 | [diff] [blame] | 47 | /// This trait is only implemented via the `#[pin_data]` proc-macro. It is used to facilitate |
| 48 | /// the pin projections within the initializers. |
| 49 | /// |
| 50 | /// # Safety |
| 51 | /// |
| 52 | /// Only the `init` module is allowed to use this trait. |
| 53 | pub unsafe trait HasPinData { |
| 54 | type PinData: PinData; |
| 55 | |
| 56 | unsafe fn __pin_data() -> Self::PinData; |
| 57 | } |
| 58 | |
| 59 | /// Marker trait for pinning data of structs. |
| 60 | /// |
| 61 | /// # Safety |
| 62 | /// |
| 63 | /// Only the `init` module is allowed to use this trait. |
| 64 | pub unsafe trait PinData: Copy { |
| 65 | type Datee: ?Sized + HasPinData; |
| 66 | |
| 67 | /// Type inference helper function. |
| 68 | fn make_closure<F, O, E>(self, f: F) -> F |
| 69 | where |
| 70 | F: FnOnce(*mut Self::Datee) -> Result<O, E>, |
| 71 | { |
| 72 | f |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | /// This trait is automatically implemented for every type. It aims to provide the same type |
| 77 | /// inference help as `HasPinData`. |
| 78 | /// |
| 79 | /// # Safety |
| 80 | /// |
| 81 | /// Only the `init` module is allowed to use this trait. |
| 82 | pub unsafe trait HasInitData { |
| 83 | type InitData: InitData; |
| 84 | |
| 85 | unsafe fn __init_data() -> Self::InitData; |
| 86 | } |
| 87 | |
| 88 | /// Same function as `PinData`, but for arbitrary data. |
| 89 | /// |
| 90 | /// # Safety |
| 91 | /// |
| 92 | /// Only the `init` module is allowed to use this trait. |
| 93 | pub unsafe trait InitData: Copy { |
| 94 | type Datee: ?Sized + HasInitData; |
| 95 | |
| 96 | /// Type inference helper function. |
| 97 | fn make_closure<F, O, E>(self, f: F) -> F |
| 98 | where |
| 99 | F: FnOnce(*mut Self::Datee) -> Result<O, E>, |
| 100 | { |
| 101 | f |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | pub struct AllData<T: ?Sized>(PhantomData<fn(Box<T>) -> Box<T>>); |
| 106 | |
| 107 | impl<T: ?Sized> Clone for AllData<T> { |
| 108 | fn clone(&self) -> Self { |
| 109 | *self |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | impl<T: ?Sized> Copy for AllData<T> {} |
| 114 | |
| 115 | unsafe impl<T: ?Sized> InitData for AllData<T> { |
| 116 | type Datee = T; |
| 117 | } |
| 118 | |
| 119 | unsafe impl<T: ?Sized> HasInitData for T { |
| 120 | type InitData = AllData<T>; |
| 121 | |
| 122 | unsafe fn __init_data() -> Self::InitData { |
| 123 | AllData(PhantomData) |
| 124 | } |
| 125 | } |
| 126 | |
Benno Lossin | 6841d45 | 2023-04-08 12:26:07 +0000 | [diff] [blame] | 127 | /// Stack initializer helper type. Use [`stack_pin_init`] instead of this primitive. |
| 128 | /// |
| 129 | /// # Invariants |
| 130 | /// |
| 131 | /// If `self.is_init` is true, then `self.value` is initialized. |
| 132 | /// |
| 133 | /// [`stack_pin_init`]: kernel::stack_pin_init |
| 134 | pub struct StackInit<T> { |
| 135 | value: MaybeUninit<T>, |
| 136 | is_init: bool, |
| 137 | } |
| 138 | |
| 139 | impl<T> Drop for StackInit<T> { |
| 140 | #[inline] |
| 141 | fn drop(&mut self) { |
| 142 | if self.is_init { |
| 143 | // SAFETY: As we are being dropped, we only call this once. And since `self.is_init` is |
| 144 | // true, `self.value` is initialized. |
| 145 | unsafe { self.value.assume_init_drop() }; |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | impl<T> StackInit<T> { |
| 151 | /// Creates a new [`StackInit<T>`] that is uninitialized. Use [`stack_pin_init`] instead of this |
| 152 | /// primitive. |
| 153 | /// |
| 154 | /// [`stack_pin_init`]: kernel::stack_pin_init |
| 155 | #[inline] |
| 156 | pub fn uninit() -> Self { |
| 157 | Self { |
| 158 | value: MaybeUninit::uninit(), |
| 159 | is_init: false, |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | /// Initializes the contents and returns the result. |
| 164 | #[inline] |
| 165 | pub fn init<E>(self: Pin<&mut Self>, init: impl PinInit<T, E>) -> Result<Pin<&mut T>, E> { |
| 166 | // SAFETY: We never move out of `this`. |
| 167 | let this = unsafe { Pin::into_inner_unchecked(self) }; |
| 168 | // The value is currently initialized, so it needs to be dropped before we can reuse |
| 169 | // the memory (this is a safety guarantee of `Pin`). |
| 170 | if this.is_init { |
| 171 | this.is_init = false; |
| 172 | // SAFETY: `this.is_init` was true and therefore `this.value` is initialized. |
| 173 | unsafe { this.value.assume_init_drop() }; |
| 174 | } |
| 175 | // SAFETY: The memory slot is valid and this type ensures that it will stay pinned. |
| 176 | unsafe { init.__pinned_init(this.value.as_mut_ptr())? }; |
| 177 | // INVARIANT: `this.value` is initialized above. |
| 178 | this.is_init = true; |
| 179 | // SAFETY: The slot is now pinned, since we will never give access to `&mut T`. |
| 180 | Ok(unsafe { Pin::new_unchecked(this.value.assume_init_mut()) }) |
| 181 | } |
| 182 | } |
| 183 | |
Benno Lossin | fc6c6ba | 2023-04-08 12:25:51 +0000 | [diff] [blame] | 184 | /// When a value of this type is dropped, it drops a `T`. |
| 185 | /// |
| 186 | /// Can be forgotten to prevent the drop. |
| 187 | pub struct DropGuard<T: ?Sized> { |
| 188 | ptr: *mut T, |
Benno Lossin | fc6c6ba | 2023-04-08 12:25:51 +0000 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | impl<T: ?Sized> DropGuard<T> { |
| 192 | /// Creates a new [`DropGuard<T>`]. It will [`ptr::drop_in_place`] `ptr` when it gets dropped. |
| 193 | /// |
| 194 | /// # Safety |
| 195 | /// |
| 196 | /// `ptr` must be a valid pointer. |
| 197 | /// |
| 198 | /// It is the callers responsibility that `self` will only get dropped if the pointee of `ptr`: |
| 199 | /// - has not been dropped, |
| 200 | /// - is not accessible by any other means, |
| 201 | /// - will not be dropped by any other means. |
| 202 | #[inline] |
| 203 | pub unsafe fn new(ptr: *mut T) -> Self { |
Benno Lossin | 97de919 | 2023-08-14 08:46:48 +0000 | [diff] [blame] | 204 | Self { ptr } |
Benno Lossin | fc6c6ba | 2023-04-08 12:25:51 +0000 | [diff] [blame] | 205 | } |
| 206 | } |
| 207 | |
| 208 | impl<T: ?Sized> Drop for DropGuard<T> { |
| 209 | #[inline] |
| 210 | fn drop(&mut self) { |
Benno Lossin | 97de919 | 2023-08-14 08:46:48 +0000 | [diff] [blame] | 211 | // SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function |
| 212 | // ensuring that this operation is safe. |
| 213 | unsafe { ptr::drop_in_place(self.ptr) } |
Benno Lossin | fc6c6ba | 2023-04-08 12:25:51 +0000 | [diff] [blame] | 214 | } |
| 215 | } |
Benno Lossin | d0fdc39 | 2023-04-08 12:26:01 +0000 | [diff] [blame] | 216 | |
| 217 | /// Token used by `PinnedDrop` to prevent calling the function without creating this unsafely |
| 218 | /// created struct. This is needed, because the `drop` function is safe, but should not be called |
| 219 | /// manually. |
| 220 | pub struct OnlyCallFromDrop(()); |
| 221 | |
| 222 | impl OnlyCallFromDrop { |
| 223 | /// # Safety |
| 224 | /// |
| 225 | /// This function should only be called from the [`Drop::drop`] function and only be used to |
| 226 | /// delegate the destruction to the pinned destructor [`PinnedDrop::drop`] of the same type. |
| 227 | pub unsafe fn new() -> Self { |
| 228 | Self(()) |
| 229 | } |
| 230 | } |