Skip to content

Commit 6841d45

Browse files
y86-devojeda
authored andcommitted
rust: init: add stack_pin_init! macro
The `stack_pin_init!` macro allows pin-initializing a value on the stack. It accepts a `impl PinInit<T, E>` to initialize a `T`. It allows propagating any errors via `?` or handling it normally via `match`. Signed-off-by: Benno Lossin <[email protected]> Reviewed-by: Alice Ryhl <[email protected]> Reviewed-by: Andreas Hindborg <[email protected]> Reviewed-by: Gary Guo <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent d0fdc39 commit 6841d45

File tree

2 files changed

+191
-6
lines changed

2 files changed

+191
-6
lines changed

rust/kernel/init.rs

Lines changed: 134 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
//!
1313
//! To initialize a `struct` with an in-place constructor you will need two things:
1414
//! - an in-place constructor,
15-
//! - a memory location that can hold your `struct`.
15+
//! - a memory location that can hold your `struct` (this can be the [stack], an [`Arc<T>`],
16+
//! [`UniqueArc<T>`], [`Box<T>`] or any other smart pointer that implements [`InPlaceInit`]).
1617
//!
1718
//! To get an in-place constructor there are generally three options:
1819
//! - directly creating an in-place constructor using the [`pin_init!`] macro,
@@ -180,6 +181,7 @@
180181
//! [pinning]: https://doc.rust-lang.org/std/pin/index.html
181182
//! [structurally pinned fields]:
182183
//! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field
184+
//! [stack]: crate::stack_pin_init
183185
//! [`Arc<T>`]: crate::sync::Arc
184186
//! [`impl PinInit<Foo>`]: PinInit
185187
//! [`impl PinInit<T, E>`]: PinInit
@@ -202,6 +204,132 @@ pub mod __internal;
202204
#[doc(hidden)]
203205
pub mod macros;
204206

207+
/// Initialize and pin a type directly on the stack.
208+
///
209+
/// # Examples
210+
///
211+
/// ```rust
212+
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
213+
/// # use kernel::{init, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex};
214+
/// # use macros::pin_data;
215+
/// # use core::pin::Pin;
216+
/// #[pin_data]
217+
/// struct Foo {
218+
/// #[pin]
219+
/// a: Mutex<usize>,
220+
/// b: Bar,
221+
/// }
222+
///
223+
/// #[pin_data]
224+
/// struct Bar {
225+
/// x: u32,
226+
/// }
227+
///
228+
/// stack_pin_init!(let foo = pin_init!(Foo {
229+
/// a <- new_mutex!(42),
230+
/// b: Bar {
231+
/// x: 64,
232+
/// },
233+
/// }));
234+
/// let foo: Pin<&mut Foo> = foo;
235+
/// pr_info!("a: {}", &*foo.a.lock());
236+
/// ```
237+
///
238+
/// # Syntax
239+
///
240+
/// A normal `let` binding with optional type annotation. The expression is expected to implement
241+
/// [`PinInit`]/[`Init`] with the error type [`Infallible`]. If you want to use a different error
242+
/// type, then use [`stack_try_pin_init!`].
243+
#[macro_export]
244+
macro_rules! stack_pin_init {
245+
(let $var:ident $(: $t:ty)? = $val:expr) => {
246+
let val = $val;
247+
let mut $var = ::core::pin::pin!($crate::init::__internal::StackInit$(::<$t>)?::uninit());
248+
let mut $var = match $crate::init::__internal::StackInit::init($var, val) {
249+
Ok(res) => res,
250+
Err(x) => {
251+
let x: ::core::convert::Infallible = x;
252+
match x {}
253+
}
254+
};
255+
};
256+
}
257+
258+
/// Initialize and pin a type directly on the stack.
259+
///
260+
/// # Examples
261+
///
262+
/// ```rust
263+
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
264+
/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex};
265+
/// # use macros::pin_data;
266+
/// # use core::{alloc::AllocError, pin::Pin};
267+
/// #[pin_data]
268+
/// struct Foo {
269+
/// #[pin]
270+
/// a: Mutex<usize>,
271+
/// b: Box<Bar>,
272+
/// }
273+
///
274+
/// struct Bar {
275+
/// x: u32,
276+
/// }
277+
///
278+
/// stack_try_pin_init!(let foo: Result<Pin<&mut Foo>, AllocError> = pin_init!(Foo {
279+
/// a <- new_mutex!(42),
280+
/// b: Box::try_new(Bar {
281+
/// x: 64,
282+
/// })?,
283+
/// }));
284+
/// let foo = foo.unwrap();
285+
/// pr_info!("a: {}", &*foo.a.lock());
286+
/// ```
287+
///
288+
/// ```rust
289+
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
290+
/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex};
291+
/// # use macros::pin_data;
292+
/// # use core::{alloc::AllocError, pin::Pin};
293+
/// #[pin_data]
294+
/// struct Foo {
295+
/// #[pin]
296+
/// a: Mutex<usize>,
297+
/// b: Box<Bar>,
298+
/// }
299+
///
300+
/// struct Bar {
301+
/// x: u32,
302+
/// }
303+
///
304+
/// stack_try_pin_init!(let foo: Pin<&mut Foo> =? pin_init!(Foo {
305+
/// a <- new_mutex!(42),
306+
/// b: Box::try_new(Bar {
307+
/// x: 64,
308+
/// })?,
309+
/// }));
310+
/// pr_info!("a: {}", &*foo.a.lock());
311+
/// # Ok::<_, AllocError>(())
312+
/// ```
313+
///
314+
/// # Syntax
315+
///
316+
/// A normal `let` binding with optional type annotation. The expression is expected to implement
317+
/// [`PinInit`]/[`Init`]. This macro assigns a result to the given variable, adding a `?` after the
318+
/// `=` will propagate this error.
319+
#[macro_export]
320+
macro_rules! stack_try_pin_init {
321+
(let $var:ident $(: $t:ty)? = $val:expr) => {
322+
let val = $val;
323+
let mut $var = ::core::pin::pin!($crate::init::__internal::StackInit$(::<$t>)?::uninit());
324+
let mut $var = $crate::init::__internal::StackInit::init($var, val);
325+
};
326+
(let $var:ident $(: $t:ty)? =? $val:expr) => {
327+
let val = $val;
328+
let mut $var = ::core::pin::pin!($crate::init::__internal::StackInit$(::<$t>)?::uninit());
329+
let mut $var = $crate::init::__internal::StackInit::init($var, val)?;
330+
};
331+
}
332+
205333
/// Construct an in-place, pinned initializer for `struct`s.
206334
///
207335
/// This macro defaults the error to [`Infallible`]. If you need [`Error`], then use
@@ -913,8 +1041,8 @@ macro_rules! try_init {
9131041
/// A pin-initializer for the type `T`.
9141042
///
9151043
/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
916-
/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Use the [`InPlaceInit::pin_init`] function of a
917-
/// smart pointer like [`Arc<T>`] on this.
1044+
/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use the
1045+
/// [`InPlaceInit::pin_init`] function of a smart pointer like [`Arc<T>`] on this.
9181046
///
9191047
/// Also see the [module description](self).
9201048
///
@@ -949,9 +1077,9 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
9491077
/// An initializer for `T`.
9501078
///
9511079
/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
952-
/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Use the [`InPlaceInit::init`] function of a smart
953-
/// pointer like [`Arc<T>`] on this. Because [`PinInit<T, E>`] is a super trait, you can
954-
/// use every function that takes it as well.
1080+
/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use the
1081+
/// [`InPlaceInit::init`] function of a smart pointer like [`Arc<T>`] on this. Because
1082+
/// [`PinInit<T, E>`] is a super trait, you can use every function that takes it as well.
9551083
///
9561084
/// Also see the [module description](self).
9571085
///

rust/kernel/init/__internal.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,63 @@ unsafe impl<T: ?Sized> HasInitData for T {
112112
}
113113
}
114114

115+
/// Stack initializer helper type. Use [`stack_pin_init`] instead of this primitive.
116+
///
117+
/// # Invariants
118+
///
119+
/// If `self.is_init` is true, then `self.value` is initialized.
120+
///
121+
/// [`stack_pin_init`]: kernel::stack_pin_init
122+
pub struct StackInit<T> {
123+
value: MaybeUninit<T>,
124+
is_init: bool,
125+
}
126+
127+
impl<T> Drop for StackInit<T> {
128+
#[inline]
129+
fn drop(&mut self) {
130+
if self.is_init {
131+
// SAFETY: As we are being dropped, we only call this once. And since `self.is_init` is
132+
// true, `self.value` is initialized.
133+
unsafe { self.value.assume_init_drop() };
134+
}
135+
}
136+
}
137+
138+
impl<T> StackInit<T> {
139+
/// Creates a new [`StackInit<T>`] that is uninitialized. Use [`stack_pin_init`] instead of this
140+
/// primitive.
141+
///
142+
/// [`stack_pin_init`]: kernel::stack_pin_init
143+
#[inline]
144+
pub fn uninit() -> Self {
145+
Self {
146+
value: MaybeUninit::uninit(),
147+
is_init: false,
148+
}
149+
}
150+
151+
/// Initializes the contents and returns the result.
152+
#[inline]
153+
pub fn init<E>(self: Pin<&mut Self>, init: impl PinInit<T, E>) -> Result<Pin<&mut T>, E> {
154+
// SAFETY: We never move out of `this`.
155+
let this = unsafe { Pin::into_inner_unchecked(self) };
156+
// The value is currently initialized, so it needs to be dropped before we can reuse
157+
// the memory (this is a safety guarantee of `Pin`).
158+
if this.is_init {
159+
this.is_init = false;
160+
// SAFETY: `this.is_init` was true and therefore `this.value` is initialized.
161+
unsafe { this.value.assume_init_drop() };
162+
}
163+
// SAFETY: The memory slot is valid and this type ensures that it will stay pinned.
164+
unsafe { init.__pinned_init(this.value.as_mut_ptr())? };
165+
// INVARIANT: `this.value` is initialized above.
166+
this.is_init = true;
167+
// SAFETY: The slot is now pinned, since we will never give access to `&mut T`.
168+
Ok(unsafe { Pin::new_unchecked(this.value.assume_init_mut()) })
169+
}
170+
}
171+
115172
/// When a value of this type is dropped, it drops a `T`.
116173
///
117174
/// Can be forgotten to prevent the drop.

0 commit comments

Comments
 (0)