| 1 | [](https://crates.io/crates/pin-init)
|
| 2 | [](https://docs.rs/pin-init/)
|
| 3 | [](https://deps.rs/repo/github/Rust-for-Linux/pin-init)
|
| 4 | 
|
| 5 | [](#nightly-only)
|
| 6 | 
|
| 7 | # `pin-init`
|
| 8 |
|
| 9 | > [!NOTE]
|
| 10 | >
|
| 11 | > This crate was originally named [`pinned-init`], but the migration to
|
| 12 | > `pin-init` is not yet complete. The `legacy` branch contains the current
|
| 13 | > version of the `pinned-init` crate & the `main` branch already incorporates
|
| 14 | > the rename to `pin-init`.
|
| 15 | >
|
| 16 | > There are still some changes needed on the kernel side before the migration
|
| 17 | > can be completed.
|
| 18 |
|
| 19 | [`pinned-init`]: https://crates.io/crates/pinned-init
|
| 20 |
|
| 21 |
|
| 22 |
|
| 23 | Library to safely and fallibly initialize pinned `struct`s using in-place constructors.
|
| 24 |
|
| 25 | [Pinning][pinning] is Rust's way of ensuring data does not move.
|
| 26 |
|
| 27 | It also allows in-place initialization of big `struct`s that would otherwise produce a stack
|
| 28 | overflow.
|
| 29 |
|
| 30 | This library's main use-case is in [Rust-for-Linux]. Although this version can be used
|
| 31 | standalone.
|
| 32 |
|
| 33 | There are cases when you want to in-place initialize a struct. For example when it is very big
|
| 34 | and moving it from the stack is not an option, because it is bigger than the stack itself.
|
| 35 | Another reason would be that you need the address of the object to initialize it. This stands
|
| 36 | in direct conflict with Rust's normal process of first initializing an object and then moving
|
| 37 | it into it's final memory location. For more information, see
|
| 38 | <https://rust-for-linux.com/the-safe-pinned-initialization-problem>.
|
| 39 |
|
| 40 | This library allows you to do in-place initialization safely.
|
| 41 |
|
| 42 | ### Nightly Needed for `alloc` feature
|
| 43 |
|
| 44 | This library requires the [`allocator_api` unstable feature] when the `alloc` feature is
|
| 45 | enabled and thus this feature can only be used with a nightly compiler. When enabling the
|
| 46 | `alloc` feature, the user will be required to activate `allocator_api` as well.
|
| 47 |
|
| 48 | [`allocator_api` unstable feature]: https://doc.rust-lang.org/nightly/unstable-book/library-features/allocator-api.html
|
| 49 |
|
| 50 | The feature is enabled by default, thus by default `pin-init` will require a nightly compiler.
|
| 51 | However, using the crate on stable compilers is possible by disabling `alloc`. In practice this
|
| 52 | will require the `std` feature, because stable compilers have neither `Box` nor `Arc` in no-std
|
| 53 | mode.
|
| 54 |
|
| 55 | ### Nightly needed for `unsafe-pinned` feature
|
| 56 |
|
| 57 | This feature enables the `Wrapper` implementation on the unstable `core::pin::UnsafePinned` type.
|
| 58 | This requires the [`unsafe_pinned` unstable feature](https://github.com/rust-lang/rust/issues/125735)
|
| 59 | and therefore a nightly compiler. Note that this feature is not enabled by default.
|
| 60 |
|
| 61 | ## Overview
|
| 62 |
|
| 63 | To initialize a `struct` with an in-place constructor you will need two things:
|
| 64 | - an in-place constructor,
|
| 65 | - a memory location that can hold your `struct` (this can be the [stack], an [`Arc<T>`],
|
| 66 | [`Box<T>`] or any other smart pointer that supports this library).
|
| 67 |
|
| 68 | To get an in-place constructor there are generally three options:
|
| 69 | - directly creating an in-place constructor using the [`pin_init!`] macro,
|
| 70 | - a custom function/macro returning an in-place constructor provided by someone else,
|
| 71 | - using the unsafe function [`pin_init_from_closure()`] to manually create an initializer.
|
| 72 |
|
| 73 | Aside from pinned initialization, this library also supports in-place construction without
|
| 74 | pinning, the macros/types/functions are generally named like the pinned variants without the
|
| 75 | `pin_` prefix.
|
| 76 |
|
| 77 | ## Examples
|
| 78 |
|
| 79 | Throughout the examples we will often make use of the `CMutex` type which can be found in
|
| 80 | `../examples/mutex.rs`. It is essentially a userland rebuild of the `struct mutex` type from
|
| 81 | the Linux kernel. It also uses a wait list and a basic spinlock. Importantly the wait list
|
| 82 | requires it to be pinned to be locked and thus is a prime candidate for using this library.
|
| 83 |
|
| 84 | ### Using the [`pin_init!`] macro
|
| 85 |
|
| 86 | If you want to use [`PinInit`], then you will have to annotate your `struct` with
|
| 87 | `#[`[`pin_data`]`]`. It is a macro that uses `#[pin]` as a marker for
|
| 88 | [structurally pinned fields]. After doing this, you can then create an in-place constructor via
|
| 89 | [`pin_init!`]. The syntax is almost the same as normal `struct` initializers. The difference is
|
| 90 | that you need to write `<-` instead of `:` for fields that you want to initialize in-place.
|
| 91 |
|
| 92 | ```rust
|
| 93 | use pin_init::{pin_data, pin_init, InPlaceInit};
|
| 94 |
|
| 95 | #[pin_data]
|
| 96 | struct Foo {
|
| 97 | #[pin]
|
| 98 | a: CMutex<usize>,
|
| 99 | b: u32,
|
| 100 | }
|
| 101 |
|
| 102 | let foo = pin_init!(Foo {
|
| 103 | a <- CMutex::new(42),
|
| 104 | b: 24,
|
| 105 | });
|
| 106 | ```
|
| 107 |
|
| 108 | `foo` now is of the type [`impl PinInit<Foo>`]. We can now use any smart pointer that we like
|
| 109 | (or just the stack) to actually initialize a `Foo`:
|
| 110 |
|
| 111 | ```rust
|
| 112 | let foo: Result<Pin<Box<Foo>>, AllocError> = Box::pin_init(foo);
|
| 113 | ```
|
| 114 |
|
| 115 | For more information see the [`pin_init!`] macro.
|
| 116 |
|
| 117 | ### Using a custom function/macro that returns an initializer
|
| 118 |
|
| 119 | Many types that use this library supply a function/macro that returns an initializer, because
|
| 120 | the above method only works for types where you can access the fields.
|
| 121 |
|
| 122 | ```rust
|
| 123 | let mtx: Result<Pin<Arc<CMutex<usize>>>, _> = Arc::pin_init(CMutex::new(42));
|
| 124 | ```
|
| 125 |
|
| 126 | To declare an init macro/function you just return an [`impl PinInit<T, E>`]:
|
| 127 |
|
| 128 | ```rust
|
| 129 | #[pin_data]
|
| 130 | struct DriverData {
|
| 131 | #[pin]
|
| 132 | status: CMutex<i32>,
|
| 133 | buffer: Box<[u8; 1_000_000]>,
|
| 134 | }
|
| 135 |
|
| 136 | impl DriverData {
|
| 137 | fn new() -> impl PinInit<Self, Error> {
|
| 138 | pin_init!(Self {
|
| 139 | status <- CMutex::new(0),
|
| 140 | buffer: Box::init(pin_init::init_zeroed())?,
|
| 141 | }? Error)
|
| 142 | }
|
| 143 | }
|
| 144 | ```
|
| 145 |
|
| 146 | ### Manual creation of an initializer
|
| 147 |
|
| 148 | Often when working with primitives the previous approaches are not sufficient. That is where
|
| 149 | [`pin_init_from_closure()`] comes in. This `unsafe` function allows you to create a
|
| 150 | [`impl PinInit<T, E>`] directly from a closure. Of course you have to ensure that the closure
|
| 151 | actually does the initialization in the correct way. Here are the things to look out for
|
| 152 | (we are calling the parameter to the closure `slot`):
|
| 153 | - when the closure returns `Ok(())`, then it has completed the initialization successfully, so
|
| 154 | `slot` now contains a valid bit pattern for the type `T`,
|
| 155 | - when the closure returns `Err(e)`, then the caller may deallocate the memory at `slot`, so
|
| 156 | you need to take care to clean up anything if your initialization fails mid-way,
|
| 157 | - you may assume that `slot` will stay pinned even after the closure returns until `drop` of
|
| 158 | `slot` gets called.
|
| 159 |
|
| 160 | ```rust
|
| 161 | use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
|
| 162 | use core::{
|
| 163 | marker::PhantomPinned,
|
| 164 | cell::UnsafeCell,
|
| 165 | pin::Pin,
|
| 166 | mem::MaybeUninit,
|
| 167 | };
|
| 168 | mod bindings {
|
| 169 | #[repr(C)]
|
| 170 | pub struct foo {
|
| 171 | /* fields from C ... */
|
| 172 | }
|
| 173 | extern "C" {
|
| 174 | pub fn init_foo(ptr: *mut foo);
|
| 175 | pub fn destroy_foo(ptr: *mut foo);
|
| 176 | #[must_use = "you must check the error return code"]
|
| 177 | pub fn enable_foo(ptr: *mut foo, flags: u32) -> i32;
|
| 178 | }
|
| 179 | }
|
| 180 |
|
| 181 | /// # Invariants
|
| 182 | ///
|
| 183 | /// `foo` is always initialized
|
| 184 | #[pin_data(PinnedDrop)]
|
| 185 | pub struct RawFoo {
|
| 186 | #[pin]
|
| 187 | _p: PhantomPinned,
|
| 188 | #[pin]
|
| 189 | foo: UnsafeCell<MaybeUninit<bindings::foo>>,
|
| 190 | }
|
| 191 |
|
| 192 | impl RawFoo {
|
| 193 | pub fn new(flags: u32) -> impl PinInit<Self, i32> {
|
| 194 | // SAFETY:
|
| 195 | // - when the closure returns `Ok(())`, then it has successfully initialized and
|
| 196 | // enabled `foo`,
|
| 197 | // - when it returns `Err(e)`, then it has cleaned up before
|
| 198 | unsafe {
|
| 199 | pin_init_from_closure(move |slot: *mut Self| {
|
| 200 | // `slot` contains uninit memory, avoid creating a reference.
|
| 201 | let foo = &raw mut (*slot).foo;
|
| 202 | let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
|
| 203 |
|
| 204 | // Initialize the `foo`
|
| 205 | bindings::init_foo(foo);
|
| 206 |
|
| 207 | // Try to enable it.
|
| 208 | let err = bindings::enable_foo(foo, flags);
|
| 209 | if err != 0 {
|
| 210 | // Enabling has failed, first clean up the foo and then return the error.
|
| 211 | bindings::destroy_foo(foo);
|
| 212 | Err(err)
|
| 213 | } else {
|
| 214 | // All fields of `RawFoo` have been initialized, since `_p` is a ZST.
|
| 215 | Ok(())
|
| 216 | }
|
| 217 | })
|
| 218 | }
|
| 219 | }
|
| 220 | }
|
| 221 |
|
| 222 | #[pinned_drop]
|
| 223 | impl PinnedDrop for RawFoo {
|
| 224 | fn drop(self: Pin<&mut Self>) {
|
| 225 | // SAFETY: Since `foo` is initialized, destroying is safe.
|
| 226 | unsafe { bindings::destroy_foo(self.foo.get().cast::<bindings::foo>()) };
|
| 227 | }
|
| 228 | }
|
| 229 | ```
|
| 230 |
|
| 231 | For more information on how to use [`pin_init_from_closure()`], take a look at the uses inside
|
| 232 | the `kernel` crate. The [`sync`] module is a good starting point.
|
| 233 |
|
| 234 | [`sync`]: https://rust.docs.kernel.org/kernel/sync/index.html
|
| 235 | [pinning]: https://doc.rust-lang.org/std/pin/index.html
|
| 236 | [structurally pinned fields]: https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning
|
| 237 | [stack]: https://docs.rs/pin-init/latest/pin_init/macro.stack_pin_init.html
|
| 238 | [`impl PinInit<Foo>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
|
| 239 | [`impl PinInit<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
|
| 240 | [`impl Init<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.Init.html
|
| 241 | [Rust-for-Linux]: https://rust-for-linux.com/
|
| 242 |
|
| 243 |
|
| 244 |
|
| 245 |
|
| 246 | [`Arc<T>`]: https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html
|
| 247 | [`Box<T>`]: https://doc.rust-lang.org/stable/alloc/boxed/struct.Box.html
|