xref: /linux/rust/pin-init/README.md (revision 55a42f78ffd386e01a5404419f8c5ded7db70a21)
1[![Crates.io](https://img.shields.io/crates/v/pin-init.svg)](https://crates.io/crates/pin-init)
2[![Documentation](https://docs.rs/pin-init/badge.svg)](https://docs.rs/pin-init/)
3[![Dependency status](https://deps.rs/repo/github/Rust-for-Linux/pin-init/status.svg)](https://deps.rs/repo/github/Rust-for-Linux/pin-init)
4![License](https://img.shields.io/crates/l/pin-init)
5[![Toolchain](https://img.shields.io/badge/toolchain-nightly-red)](#nightly-only)
6![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/Rust-for-Linux/pin-init/test.yml)
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 `legcay` 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<!-- cargo-rdme start -->
22
23Library 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
27It also allows in-place initialization of big `struct`s that would otherwise produce a stack
28overflow.
29
30This library's main use-case is in [Rust-for-Linux]. Although this version can be used
31standalone.
32
33There are cases when you want to in-place initialize a struct. For example when it is very big
34and moving it from the stack is not an option, because it is bigger than the stack itself.
35Another reason would be that you need the address of the object to initialize it. This stands
36in direct conflict with Rust's normal process of first initializing an object and then moving
37it into it's final memory location. For more information, see
38<https://rust-for-linux.com/the-safe-pinned-initialization-problem>.
39
40This library allows you to do in-place initialization safely.
41
42### Nightly Needed for `alloc` feature
43
44This library requires the [`allocator_api` unstable feature] when the `alloc` feature is
45enabled 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
50The feature is enabled by default, thus by default `pin-init` will require a nightly compiler.
51However, using the crate on stable compilers is possible by disabling `alloc`. In practice this
52will require the `std` feature, because stable compilers have neither `Box` nor `Arc` in no-std
53mode.
54
55### Nightly needed for `unsafe-pinned` feature
56
57This feature enables the `Wrapper` implementation on the unstable `core::pin::UnsafePinned` type.
58This requires the [`unsafe_pinned` unstable feature](https://github.com/rust-lang/rust/issues/125735)
59and therefore a nightly compiler. Note that this feature is not enabled by default.
60
61## Overview
62
63To 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
68To 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
73Aside from pinned initialization, this library also supports in-place construction without
74pinning, the macros/types/functions are generally named like the pinned variants without the
75`pin_` prefix.
76
77## Examples
78
79Throughout 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
81the Linux kernel. It also uses a wait list and a basic spinlock. Importantly the wait list
82requires 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
86If 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
90that you need to write `<-` instead of `:` for fields that you want to initialize in-place.
91
92```rust
93use pin_init::{pin_data, pin_init, InPlaceInit};
94
95#[pin_data]
96struct Foo {
97    #[pin]
98    a: CMutex<usize>,
99    b: u32,
100}
101
102let 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
112let foo: Result<Pin<Box<Foo>>, AllocError> = Box::pin_init(foo);
113```
114
115For more information see the [`pin_init!`] macro.
116
117### Using a custom function/macro that returns an initializer
118
119Many types that use this library supply a function/macro that returns an initializer, because
120the above method only works for types where you can access the fields.
121
122```rust
123let mtx: Result<Pin<Arc<CMutex<usize>>>, _> = Arc::pin_init(CMutex::new(42));
124```
125
126To declare an init macro/function you just return an [`impl PinInit<T, E>`]:
127
128```rust
129#[pin_data]
130struct DriverData {
131    #[pin]
132    status: CMutex<i32>,
133    buffer: Box<[u8; 1_000_000]>,
134}
135
136impl DriverData {
137    fn new() -> impl PinInit<Self, Error> {
138        try_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
148Often 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
151actually 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
161use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
162use core::{
163    ptr::addr_of_mut,
164    marker::PhantomPinned,
165    cell::UnsafeCell,
166    pin::Pin,
167    mem::MaybeUninit,
168};
169mod bindings {
170    #[repr(C)]
171    pub struct foo {
172        /* fields from C ... */
173    }
174    extern "C" {
175        pub fn init_foo(ptr: *mut foo);
176        pub fn destroy_foo(ptr: *mut foo);
177        #[must_use = "you must check the error return code"]
178        pub fn enable_foo(ptr: *mut foo, flags: u32) -> i32;
179    }
180}
181
182/// # Invariants
183///
184/// `foo` is always initialized
185#[pin_data(PinnedDrop)]
186pub struct RawFoo {
187    #[pin]
188    _p: PhantomPinned,
189    #[pin]
190    foo: UnsafeCell<MaybeUninit<bindings::foo>>,
191}
192
193impl RawFoo {
194    pub fn new(flags: u32) -> impl PinInit<Self, i32> {
195        // SAFETY:
196        // - when the closure returns `Ok(())`, then it has successfully initialized and
197        //   enabled `foo`,
198        // - when it returns `Err(e)`, then it has cleaned up before
199        unsafe {
200            pin_init_from_closure(move |slot: *mut Self| {
201                // `slot` contains uninit memory, avoid creating a reference.
202                let foo = addr_of_mut!((*slot).foo);
203                let foo = UnsafeCell::raw_get(foo).cast::<bindings::foo>();
204
205                // Initialize the `foo`
206                bindings::init_foo(foo);
207
208                // Try to enable it.
209                let err = bindings::enable_foo(foo, flags);
210                if err != 0 {
211                    // Enabling has failed, first clean up the foo and then return the error.
212                    bindings::destroy_foo(foo);
213                    Err(err)
214                } else {
215                    // All fields of `RawFoo` have been initialized, since `_p` is a ZST.
216                    Ok(())
217                }
218            })
219        }
220    }
221}
222
223#[pinned_drop]
224impl PinnedDrop for RawFoo {
225    fn drop(self: Pin<&mut Self>) {
226        // SAFETY: Since `foo` is initialized, destroying is safe.
227        unsafe { bindings::destroy_foo(self.foo.get().cast::<bindings::foo>()) };
228    }
229}
230```
231
232For more information on how to use [`pin_init_from_closure()`], take a look at the uses inside
233the `kernel` crate. The [`sync`] module is a good starting point.
234
235[`sync`]: https://rust.docs.kernel.org/kernel/sync/index.html
236[pinning]: https://doc.rust-lang.org/std/pin/index.html
237[structurally pinned fields]: https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning
238[stack]: https://docs.rs/pin-init/latest/pin_init/macro.stack_pin_init.html
239[`impl PinInit<Foo>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
240[`impl PinInit<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
241[`impl Init<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.Init.html
242[Rust-for-Linux]: https://rust-for-linux.com/
243
244<!-- cargo-rdme end -->
245
246<!-- These links are not picked up by cargo-rdme, since they are behind cfgs... -->
247[`Arc<T>`]: https://doc.rust-lang.org/stable/alloc/sync/struct.Arc.html
248[`Box<T>`]: https://doc.rust-lang.org/stable/alloc/boxed/struct.Box.html
249