From: Andreas Hindborg <nmi@metaspace.dk>
To: y86-dev@protonmail.com
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Wedson Almeida Filho" <wedsonaf@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Alice Ryhl" <alice@ryhl.io>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
patches@lists.linux.dev,
"Andreas Hindborg" <a.hindborg@samsung.com>
Subject: Re: [PATCH v3 08/13] rust: init: add `stack_pin_init!` macro
Date: Fri, 31 Mar 2023 14:43:33 +0200 [thread overview]
Message-ID: <87fs9l2iqw.fsf@metaspace.dk> (raw)
In-Reply-To: <20230329223239.138757-9-y86-dev@protonmail.com>
y86-dev@protonmail.com writes:
> From: Benno Lossin <y86-dev@protonmail.com>
>
> 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 <y86-dev@protonmail.com>
> ---
Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com>
> rust/kernel/init.rs | 70 +++++++++++++++++++++++++++++++---
> rust/kernel/init/__internal.rs | 46 ++++++++++++++++++++++
> 2 files changed, 110 insertions(+), 6 deletions(-)
>
> diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
> index 428b5c2ac516..3358f14beffb 100644
> --- a/rust/kernel/init.rs
> +++ b/rust/kernel/init.rs
> @@ -12,7 +12,8 @@
> //!
> //! To initialize a `struct` with an in-place constructor you will need two things:
> //! - an in-place constructor,
> -//! - a memory location that can hold your `struct`.
> +//! - a memory location that can hold your `struct` (this can be the [stack], an [`Arc<T>`],
> +//! [`UniqueArc<T>`], [`Box<T>`] or any other smart pointer that implements [`InPlaceInit`]).
> //!
> //! To get an in-place constructor there are generally three options:
> //! - directly creating an in-place constructor using the [`pin_init!`] macro,
> @@ -180,6 +181,7 @@
> //! [pinning]: https://doc.rust-lang.org/std/pin/index.html
> //! [structurally pinned fields]:
> //! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field
> +//! [stack]: crate::stack_pin_init
> //! [`Arc<T>`]: crate::sync::Arc
> //! [`impl PinInit<Foo>`]: PinInit
> //! [`impl PinInit<T, E>`]: PinInit
> @@ -199,6 +201,62 @@ pub mod __internal;
> #[doc(hidden)]
> pub mod macros;
>
> +/// Initialize and pin a type directly on the stack.
> +///
> +/// # Examples
> +///
> +/// ```rust
> +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
> +/// # use kernel::{init, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex};
> +/// # use macros::pin_data;
> +/// # use core::pin::Pin;
> +/// #[pin_data]
> +/// struct Foo {
> +/// #[pin]
> +/// a: Mutex<usize>,
> +/// b: Bar,
> +/// }
> +///
> +/// #[pin_data]
> +/// struct Bar {
> +/// x: u32,
> +/// }
> +///
> +/// let a = new_mutex!(42, "Foo::a");
> +///
> +/// stack_pin_init!(let foo =? pin_init!(Foo {
> +/// a,
> +/// b: Bar {
> +/// x: 64,
> +/// },
> +/// }));
> +/// let foo: Pin<&mut Foo> = foo;
> +/// # Ok::<(), core::convert::Infallible>(())
> +/// ```
> +///
> +/// # Syntax
> +///
> +/// A normal `let` binding with optional type annotation. The expression is expected to implement
> +/// [`PinInit`]. Additionally a `?` can be put after the `=`, this will assign `Pin<&mut T>` to the
> +/// variable instead of `Result<Pin<&mut T>, E>`.
> +#[macro_export]
> +macro_rules! stack_pin_init {
> + (let $var:ident $(: $t:ty)? = $val:expr) => {
> + let mut $var = $crate::init::__internal::StackInit$(::<$t>)?::uninit();
> + let mut $var = {
> + let val = $val;
> + unsafe { $crate::init::__internal::StackInit::init(&mut $var, val) }
> + };
> + };
> + (let $var:ident $(: $t:ty)? =? $val:expr) => {
> + let mut $var = $crate::init::__internal::StackInit$(::<$t>)?::uninit();
> + let mut $var = {
> + let val = $val;
> + unsafe { $crate::init::__internal::StackInit::init(&mut $var, val)? }
> + };
> + };
> +}
> +
> /// Construct an in-place, pinned initializer for `struct`s.
> ///
> /// This macro defaults the error to [`Infallible`]. If you need [`Error`], then use
> @@ -916,8 +974,8 @@ macro_rules! try_init {
> /// A pinned initializer for `T`.
> ///
> /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
> -/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Use the [`InPlaceInit::pin_init`] function of a
> -/// smart pointer like [`Arc<T>`] on this.
> +/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use the
> +/// [`InPlaceInit::pin_init`] function of a smart pointer like [`Arc<T>`] on this.
> ///
> /// Also see the [module description](self).
> ///
> @@ -952,9 +1010,9 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
> /// An initializer for `T`.
> ///
> /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
> -/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Use the [`InPlaceInit::init`] function of a smart
> -/// pointer like [`Arc<T>`] on this. Because [`PinInit<T, E>`] is a super trait, you can
> -/// use every function that takes it as well.
> +/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use the
> +/// [`InPlaceInit::init`] function of a smart pointer like [`Arc<T>`] on this. Because
> +/// [`PinInit<T, E>`] is a super trait, you can use every function that takes it as well.
> ///
> /// Also see the [module description](self).
> ///
> diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs
> index 4a3c7bf27a06..bf33c8e96e6d 100644
> --- a/rust/kernel/init/__internal.rs
> +++ b/rust/kernel/init/__internal.rs
> @@ -89,6 +89,52 @@ unsafe impl<T: ?Sized> HasInitData for T {
> }
> }
>
> +/// Stack initializer helper type. Use [`stack_pin_init`] instead of this primitive.
> +///
> +/// # Invariants
> +///
> +/// If `self.1` is true, then `self.0` is initialized.
> +///
> +/// [`stack_pin_init`]: kernel::stack_pin_init
> +pub struct StackInit<T>(MaybeUninit<T>, bool);
> +
> +impl<T> Drop for StackInit<T> {
> + #[inline]
> + fn drop(&mut self) {
> + if self.1 {
> + // SAFETY: As we are being dropped, we only call this once. And since `self.1 == true`,
> + // `self.0` has to be initialized.
> + unsafe { self.0.assume_init_drop() };
> + }
> + }
> +}
> +
> +impl<T> StackInit<T> {
> + /// Creates a new [`StackInit<T>`] that is uninitialized. Use [`stack_pin_init`] instead of this
> + /// primitive.
> + ///
> + /// [`stack_pin_init`]: kernel::stack_pin_init
> + #[inline]
> + pub fn uninit() -> Self {
> + Self(MaybeUninit::uninit(), false)
> + }
> +
> + /// Initializes the contents and returns the result.
> + ///
> + /// # Safety
> + ///
> + /// The caller ensures that `self` is on the stack and not accessible in any other way, if this
> + /// function returns `Ok`.
> + #[inline]
> + pub unsafe fn init<E>(&mut self, init: impl PinInit<T, E>) -> Result<Pin<&mut T>, E> {
> + // SAFETY: The memory slot is valid and this type ensures that it will stay pinned.
> + unsafe { init.__pinned_init(self.0.as_mut_ptr())? };
> + self.1 = true;
> + // SAFETY: The slot is now pinned, since we will never give access to `&mut T`.
> + Ok(unsafe { Pin::new_unchecked(self.0.assume_init_mut()) })
> + }
> +}
> +
> /// When a value of this type is dropped, it drops a `T`.
> ///
> /// Can be forgotton to prevent the drop.
prev parent reply other threads:[~2023-03-31 12:44 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-29 22:32 [PATCH v3 00/13] Rust pin-init API for pinned initialization of structs y86-dev
2023-03-29 22:32 ` [PATCH v3 01/13] rust: macros: add `quote!` macro y86-dev
2023-03-30 11:42 ` Andreas Hindborg
2023-03-30 12:01 ` Andreas Hindborg
2023-03-30 13:11 ` Gary Guo
2023-03-30 13:33 ` Alice Ryhl
2023-03-31 10:43 ` Andreas Hindborg
2023-03-29 22:32 ` [PATCH v3 02/13] rust: sync: add `assume_init` to `UniqueArc` y86-dev
2023-03-30 4:13 ` Wedson Almeida Filho
2023-03-30 12:18 ` Andreas Hindborg
2023-03-30 13:33 ` Alice Ryhl
2023-03-29 22:33 ` [PATCH v3 03/13] rust: types: add `Opaque::raw_get` y86-dev
2023-03-30 10:49 ` Gary Guo
2023-03-30 12:32 ` Andreas Hindborg
2023-03-30 13:33 ` Alice Ryhl
2023-03-29 22:33 ` [PATCH v3 04/13] rust: add pin-init API core y86-dev
2023-03-30 13:05 ` Andreas Hindborg
2023-03-30 15:46 ` Benno Lossin
2023-03-31 8:16 ` Andreas Hindborg
2023-03-30 13:17 ` Alice Ryhl
2023-03-30 13:33 ` Alice Ryhl
2023-03-30 14:16 ` Andreas Hindborg
2023-03-30 15:37 ` Benno Lossin
2023-03-30 15:36 ` Benno Lossin
2023-03-31 12:00 ` Andreas Hindborg
2023-03-29 22:33 ` [PATCH v3 05/13] rust: init: add initialization macros y86-dev
2023-03-30 14:21 ` Alice Ryhl
2023-03-30 15:38 ` Benno Lossin
2023-03-31 12:02 ` Andreas Hindborg
2023-03-29 22:33 ` [PATCH v3 06/13] rust: init/sync: add `InPlaceInit` trait to pin-initialize smart pointers y86-dev
2023-03-30 10:58 ` Gary Guo
2023-03-30 13:39 ` Andreas Hindborg
2023-03-30 14:37 ` Alice Ryhl
2023-03-30 15:28 ` Benno Lossin
2023-03-30 20:24 ` Alice Ryhl
2023-03-29 22:33 ` [PATCH v3 07/13] rust: init: add `PinnedDrop` trait and macros y86-dev
2023-03-30 11:01 ` Gary Guo
2023-03-30 15:41 ` Benno Lossin
2023-03-30 14:45 ` Alice Ryhl
2023-03-31 12:31 ` Andreas Hindborg
2023-03-29 22:33 ` [PATCH v3 08/13] rust: init: add `stack_pin_init!` macro y86-dev
2023-03-30 11:06 ` Gary Guo
2023-03-30 15:07 ` Alice Ryhl
2023-03-30 15:00 ` Alice Ryhl
2023-03-30 15:19 ` Benno Lossin
2023-03-30 20:28 ` Alice Ryhl
2023-03-31 12:43 ` Andreas Hindborg [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87fs9l2iqw.fsf@metaspace.dk \
--to=nmi@metaspace.dk \
--cc=a.hindborg@samsung.com \
--cc=alex.gaynor@gmail.com \
--cc=alice@ryhl.io \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=ojeda@kernel.org \
--cc=patches@lists.linux.dev \
--cc=rust-for-linux@vger.kernel.org \
--cc=wedsonaf@gmail.com \
--cc=y86-dev@protonmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.