From abdbfd5d20021c744c4c2ebfb3174760d4bec0ab Mon Sep 17 00:00:00 2001 From: y86-dev Date: Thu, 6 Oct 2022 18:54:56 +0200 Subject: [PATCH 01/11] rust: sync: Added `try_new_uninit` to UniqueArc Also added `assume_init` to `UniqueArc>`. It assumes that its contents have been initialized and returns `UniqueArc`. `try_new_uninit` is needed, because `try_new(MaybeUninit::uninit())` actually allocates memory on the stack and may result in a stack overflow if `T` is large in size. `try_new_uninit` has been implemented in such a way that this cannot happen. Signed-off-by: Benno Lossin --- rust/kernel/sync/arc.rs | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 7f152a1f40fb4d..bf7fe671e31dab 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -27,7 +27,7 @@ use core::{ mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, pin::Pin, - ptr::{self, NonNull}, + ptr::{self, addr_of_mut, NonNull}, }; /// A reference-counted pointer to an instance of `T`. @@ -464,9 +464,33 @@ impl UniqueArc { /// Tries to allocate a new [`UniqueArc`] instance whose contents are not initialised yet. pub fn try_new_uninit() -> Result>> { + let layout = Layout::new::>>(); + // SAFETY: The layout size is guaranteed to be non-zero because `ArcInner` contains the + // reference count. + let inner = NonNull::new(unsafe { alloc(layout) }) + .ok_or(ENOMEM)? + .cast::>>(); + // TODO do this using `pinned-init` + + // INVARIANT: The refcount is initialised to a non-zero value. + let refcount = Opaque::new(new_refcount()); + // SAFETY: `inner` is writable and properly aligned. + unsafe { addr_of_mut!((*inner.as_ptr()).refcount).write(refcount) }; + // assert that there are only two fields: refcount and data (done in a closure to avoid + // overflowing the stack in debug mode with a big `T`) + #[allow(unreachable_code, clippy::diverging_sub_expression)] + let _check = || { + let _check: ArcInner> = ArcInner { + refcount: todo!(), + data: todo!(), + }; + }; + + // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new + // `Arc` object. Ok(UniqueArc::> { // INVARIANT: The newly-created object has a ref-count of 1. - inner: Arc::try_new(MaybeUninit::uninit())?, + inner: unsafe { Arc::from_inner(inner) }, }) } } @@ -475,6 +499,17 @@ impl UniqueArc> { /// Converts a `UniqueArc>` into a `UniqueArc` by writing a value into it. pub fn write(mut self, value: T) -> UniqueArc { self.deref_mut().write(value); + // SAFETY: we just initialized `self` + unsafe { self.assume_init() } + } + + /// Unsafely assume that `self` is initialized. + /// + /// # Safety + /// + /// The caller guarantees that the value behind this pointer has been initialized. It is + /// *immediate* UB to call this when the value is not initialized. + pub unsafe fn assume_init(self) -> UniqueArc { let inner = ManuallyDrop::new(self).inner.ptr; UniqueArc { // SAFETY: The new `Arc` is taking over `ptr` from `self.inner` (which won't be From f475a1ec78a66611fd62db84c3b749aeb5643acf Mon Sep 17 00:00:00 2001 From: y86-dev Date: Thu, 6 Oct 2022 20:45:41 +0200 Subject: [PATCH 02/11] rust: Added `Opaque::raw_get` This function does exactly the same thing as `UnsafeCell::raw_get` [1]. It exists to avoid creating intermediate references. Link: https://doc.rust-lang.org/core/cell/struct.UnsafeCell.html#method.raw_get [1] Signed-off-by: Benno Lossin --- rust/kernel/types.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index fbf2766a95717a..5451dbbf4b4177 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -15,7 +15,7 @@ use core::{ mem::MaybeUninit, ops::{self, Deref, DerefMut}, pin::Pin, - ptr::NonNull, + ptr::{addr_of, NonNull}, }; /// Permissions. @@ -316,6 +316,18 @@ impl Opaque { pub fn get(&self) -> *mut T { UnsafeCell::raw_get(self.0.as_ptr()) } + + /// Gets the value behind `this`. + /// + /// This function is useful to get access to the value without creating intermeditate + /// references. + /// + /// # Safety + /// + /// The pointer supplied is valid. + pub unsafe fn raw_get(this: *const Self) -> *mut T { + UnsafeCell::raw_get(addr_of!((*this).0).cast::>()) + } } /// A bitmask. From 2415d84ec8236ae44fce8c723aa4e1a444192bf1 Mon Sep 17 00:00:00 2001 From: y86-dev Date: Thu, 6 Oct 2022 21:00:04 +0200 Subject: [PATCH 03/11] rust: added `extern crate self as kernel` This allows proc macros to refer to `::kernel`. This syntax is needed in order to ensure that we refer to the true kernel crate instead of a local module. Signed-off-by: Benno Lossin --- rust/kernel/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 596119bfe5ab89..7f09072733efba 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -31,6 +31,9 @@ #[cfg(not(CONFIG_RUST))] compile_error!("Missing kernel configuration for conditional compilation"); +// allow proc-macros to refer to `::kernel`. +extern crate self as kernel; + #[cfg(not(test))] #[cfg(not(testlib))] mod allocator; From a3ce901a8ea055702a7c42ce82937e51708654d0 Mon Sep 17 00:00:00 2001 From: y86-dev Date: Thu, 6 Oct 2022 19:20:36 +0200 Subject: [PATCH 04/11] rust: Added pinned-init API This API is used to initialize pinned structs. Before we had to use `unsafe` to first call `Mutex::new` with the promise that we would call `Mutex::init` later (which also requires `unsafe`, because it first needs a pin-projection). This API merges those two functions into one such that it is now a safe operation for the user. It is implemented using a combination of things: - declarative macros used to create initializers (`pin_init!`/`init!`), - declarative macro used to inform about the pinned fields (`pin_project!`), - proc macro shim delegating to the previously mentioned declarative macro (the proc macro does a bit of generics parsing, it is `#[pin_project]`), - traits and a couple of functions to create basic initializers. For details, please read the documentation at [1]. Link: https://rust-for-linux.github.io/docs/kernel/init/index.html [1] Signed-off-by: Benno Lossin --- rust/kernel/init.rs | 863 ++++++++++++++++++++++++++++++++ rust/kernel/init/__private.rs | 145 ++++++ rust/kernel/init/pin_project.rs | 325 ++++++++++++ rust/kernel/init/pinned_drop.rs | 29 ++ rust/kernel/lib.rs | 2 + rust/kernel/prelude.rs | 3 +- rust/kernel/sync/arc.rs | 15 +- rust/macros/lib.rs | 45 ++ rust/macros/pin_project.rs | 111 ++++ rust/macros/pinned_drop.rs | 80 +++ 10 files changed, 1616 insertions(+), 2 deletions(-) create mode 100644 rust/kernel/init.rs create mode 100644 rust/kernel/init/__private.rs create mode 100644 rust/kernel/init/pin_project.rs create mode 100644 rust/kernel/init/pinned_drop.rs create mode 100644 rust/macros/pin_project.rs create mode 100644 rust/macros/pinned_drop.rs diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs new file mode 100644 index 00000000000000..7b5467baf5f89f --- /dev/null +++ b/rust/kernel/init.rs @@ -0,0 +1,863 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! API to safely and fallibly initialize pinned structs using in-place constructors. +//! +//! It also allows in-place initialization of big structs that would otherwise produce a stack overflow. +//! +//! Most structs from the [sync] module need to be pinned, because they contain self referential +//! structs from C. [Pinning][pinning] is Rust's way of ensuring data does not move. +//! +//! # Overview +//! +//! 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 (this can be the [stack], an [`Arc`], +//! [`UniqueArc`], [`Box`] or any other smart pointer [^1]). +//! +//! To get an in-place constructor there are generally two options: +//! - directly creating an in-place constructor, +//! - a function/macro returning an in-place constructor. +//! +//! # Examples +//! +//! ## Directly creating an in-place constructor +//! +//! If you want to use [`PinInit`], then you will have to annotate your struct with [`#[pin_project]`]. +//! It is a macro that uses `#[pin]` as a marker for [structurally pinned fields]. +//! +//! ```rust +//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +//! use kernel::{prelude::*, sync::Mutex, new_mutex}; +//! # use core::pin::Pin; +//! #[pin_project] +//! struct Foo { +//! #[pin] +//! a: Mutex, +//! b: u32, +//! } +//! +//! let foo = pin_init!(Foo { +//! a: new_mutex!(42, "Foo::a"), +//! b: 24, +//! }); +//! # let foo: Result>> = Box::pin_init::(foo); +//! ``` +//! +//! `foo` now is of the type `impl`[`PinInit`]. We can now use any smart pointer that we like +//! (or just the stack) to actually initialize a `Foo`: +//! +//! ```rust +//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +//! # use kernel::{prelude::*, sync::Mutex, new_mutex}; +//! # use core::pin::Pin; +//! # #[pin_project] +//! # struct Foo { +//! # #[pin] +//! # a: Mutex, +//! # b: u32, +//! # } +//! # let foo = pin_init!(Foo { +//! # a: new_mutex!(42, "Foo::a"), +//! # b: 24, +//! # }); +//! let foo: Result>> = Box::pin_init::(foo); +//! ``` +//! +//! ## Using a function/macro that returns an initializer +//! +//! Many types from the kernel supply a function/macro that returns an initializer, because the +//! above method only works for types where you can access the fields. +//! +//! ```rust +//! # use kernel::{new_mutex, sync::{Arc, Mutex}}; +//! let mtx: Result>> = Arc::pin_init(new_mutex!(42, "example::mtx")); +//! ``` +//! +//! To declare an init macro/function you just return an `impl`[`PinInit`]: +//! ```rust +//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +//! # use kernel::{sync::Mutex, prelude::*, new_mutex, init::PinInit}; +//! #[pin_project] +//! struct DriverData { +//! #[pin] +//! status: Mutex, +//! buffer: Box<[u8; 1_000_000]>, +//! } +//! +//! impl DriverData { +//! fn new() -> impl PinInit { +//! pin_init!(Self { +//! status: new_mutex!(0, "DriverData::status"), +//! buffer: Box::init(kernel::init::zeroed())?, +//! }) +//! } +//! } +//! ``` +//! +//! +//! [^1]: That is not entirely true, only smart pointers that implement [`InPlaceInit`]. +//! +//! [sync]: ../sync/index.html +//! [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_init +//! [`Arc`]: crate::sync::Arc + +use crate::{ + error::{self, Error}, + sync::UniqueArc, +}; +use alloc::boxed::Box; +use core::{ + convert::Infallible, + marker::{PhantomData, Unpin}, + mem::MaybeUninit, + pin::Pin, + ptr, +}; + +#[doc(hidden)] +pub mod __private; +mod pin_project; +mod pinned_drop; + +/// Initialize a type directly on the stack. +/// +/// # Examples +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, stack_init, init::*, macros::pin_project, sync::Mutex, new_mutex}; +/// # use core::pin::Pin; +/// #[pin_project] +/// struct Foo { +/// #[pin] +/// a: Mutex, +/// b: Bar, +/// } +/// +/// #[pin_project] +/// struct Bar { +/// x: u32, +/// } +/// +/// let a = new_mutex!(42, "Foo::a"); +/// +/// stack_init!(let foo = pin_init!(Foo { +/// a, +/// b: Bar { +/// x: 64, +/// }, +/// })); +/// let foo: Result> = foo; +/// ``` +#[macro_export] +macro_rules! stack_init { + (let $var:ident = $val:expr) => { + let mut $var = $crate::init::__private::StackInit::uninit(); + let val = $val; + let mut $var = unsafe { $crate::init::__private::StackInit::init(&mut $var, val) }; + }; + (let $var:ident $(: $t:ty)? =? $val:expr) => { + let mut $var = $crate::init::__private::StackInit$(::<$t>)?::uninit(); + let val = $val; + let mut $var = unsafe { $crate::init::__private::StackInit::init(&mut $var, val)? }; + }; +} + +/// Construct an in-place initializer for structs. +/// +/// The syntax is identical to a normal struct initializer: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use core::pin::Pin; +/// #[pin_project] +/// struct Foo { +/// a: usize, +/// b: Bar, +/// } +/// +/// #[pin_project] +/// struct Bar { +/// x: u32, +/// } +/// +/// # fn demo() -> impl PinInit { +/// let a = 42; +/// +/// let initializer = pin_init!(Foo { +/// a, +/// b: Bar { +/// x: 64, +/// }, +/// }); +/// # initializer } +/// # Box::pin_init(demo()).unwrap(); +/// ``` +/// Arbitrary rust expressions can be used to set the value of a variable. +/// +/// # Init-functions +/// +/// When working with this library it is often desired to let others construct your types without +/// giving access to all fields. This is where you would normally write a plain function `new` +/// that would return a new instance of your type. With this library that is also possible, however +/// there are a few extra things to keep in mind. +/// +/// To create an initializer function, simple declare it like this: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, prelude::*, init::*}; +/// # use core::pin::Pin; +/// # #[pin_project] +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # #[pin_project] +/// # struct Bar { +/// # x: u32, +/// # } +/// +/// impl Foo { +/// fn new() -> impl PinInit { +/// pin_init!(Self { +/// a: 42, +/// b: Bar { +/// x: 64, +/// }, +/// }) +/// } +/// } +/// ``` +/// +/// Users of `Foo` can now create it like this: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use core::pin::Pin; +/// # #[pin_project] +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # #[pin_project] +/// # struct Bar { +/// # x: u32, +/// # } +/// # impl Foo { +/// # fn new() -> impl PinInit { +/// # pin_init!(Self { +/// # a: 42, +/// # b: Bar { +/// # x: 64, +/// # }, +/// # }) +/// # } +/// # } +/// let foo = Box::pin_init(Foo::new()); +/// ``` +/// +/// They can also easily embed it into their own `struct`s: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use core::pin::Pin; +/// # #[pin_project] +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # #[pin_project] +/// # struct Bar { +/// # x: u32, +/// # } +/// # impl Foo { +/// # fn new() -> impl PinInit { +/// # pin_init!(Self { +/// # a: 42, +/// # b: Bar { +/// # x: 64, +/// # }, +/// # }) +/// # } +/// # } +/// #[pin_project] +/// struct FooContainer { +/// #[pin] +/// foo1: Foo, +/// #[pin] +/// foo2: Foo, +/// other: u32, +/// } +/// +/// impl FooContainer { +/// fn new(other: u32) -> impl PinInit { +/// pin_init!(Self { +/// foo1: Foo::new(), +/// foo2: Foo::new(), +/// other, +/// }) +/// } +/// } +/// ``` +#[macro_export] +macro_rules! pin_init { + ($(&$this:ident in)? $t:ident $(<$($generics:ty),* $(,)?>)? { + $($field:ident $(: $val:expr)?),* + $(,)? + }) => { + $crate::pin_init!(@this($($this)?), @type_name($t $(<$($generics),*>)?), @typ($t $(<$($generics),*>)?), @fields($($field $(: $val)?),*)) + }; + (@this($($this:ident)?), @type_name($t:ident $(<$($generics:ty),*>)?), @typ($ty:ty), @fields($($field:ident $(: $val:expr)?),*)) => {{ + // we do not want to allow arbitrary returns + struct __InitOk; + let init = move |slot: *mut $ty| -> ::core::result::Result<__InitOk, _> { + { + // shadow the structure so it cannot be used to return early + struct __InitOk; + $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? + $( + $(let $field = $val;)? + // call the initializer + // SAFETY: slot is valid, because we are inside of an initializer closure, we return + // when an error/panic occurs. + unsafe { + <$ty as $crate::init::__private::__PinData>::__PinData::$field( + ::core::ptr::addr_of_mut!((*slot).$field), + $field, + )?; + } + // create the drop guard + // SAFETY: we forget the guard later when initialization has succeeded. + let $field = unsafe { $crate::init::__private::DropGuard::new(::core::ptr::addr_of_mut!((*slot).$field)) }; + // only give access to &DropGuard, so it cannot be accidentally forgotten + let $field = &$field; + )* + #[allow(unreachable_code, clippy::diverging_sub_expression)] + if false { + let _: $t $(<$($generics),*>)? = $t { + $($field: ::core::todo!()),* + }; + } + $( + // forget each guard + unsafe { $crate::init::__private::DropGuard::forget($field) }; + )* + } + Ok(__InitOk) + }; + let init = move |slot: *mut $ty| -> ::core::result::Result<(), _> { + init(slot).map(|__InitOk| ()) + }; + let init = unsafe { $crate::init::pin_init_from_closure::<$t $(<$($generics),*>)?, _>(init) }; + init + }} +} + +/// Construct an in-place initializer for structs. +/// +/// The syntax is identical to a normal struct initializer: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, init::*}; +/// # use core::pin::Pin; +/// struct Foo { +/// a: usize, +/// b: Bar, +/// } +/// +/// struct Bar { +/// x: u32, +/// } +/// +/// # fn demo() -> impl Init { +/// let a = 42; +/// +/// let initializer = init!(Foo { +/// a, +/// b: Bar { +/// x: 64, +/// }, +/// }); +/// # initializer } +/// # Box::init(demo()).unwrap(); +/// ``` +/// +/// Arbitrary rust expressions can be used to set the value of a variable. +/// +/// # Init-functions +/// +/// When working with this library it is often desired to let others construct your types without +/// giving access to all fields. This is where you would normally write a plain function `new` +/// that would return a new instance of your type. With this library that is also possible, however +/// there are a few extra things to keep in mind. +/// +/// To create an initializer function, simple declare it like this: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, init::*}; +/// # use core::pin::Pin; +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # struct Bar { +/// # x: u32, +/// # } +/// +/// impl Foo { +/// fn new() -> impl Init { +/// init!(Self { +/// a: 42, +/// b: Bar { +/// x: 64, +/// }, +/// }) +/// } +/// } +/// ``` +/// +/// Users of `Foo` can now create it like this: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, init::*}; +/// # use core::pin::Pin; +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # struct Bar { +/// # x: u32, +/// # } +/// # impl Foo { +/// # fn new() -> impl Init { +/// # init!(Self { +/// # a: 42, +/// # b: Bar { +/// # x: 64, +/// # }, +/// # }) +/// # } +/// # } +/// let foo = Box::init(Foo::new()); +/// ``` +/// +/// They can also easily embed it into their own `struct`s: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, init::*}; +/// # use core::pin::Pin; +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # struct Bar { +/// # x: u32, +/// # } +/// # impl Foo { +/// # fn new() -> impl Init { +/// # init!(Self { +/// # a: 42, +/// # b: Bar { +/// # x: 64, +/// # }, +/// # }) +/// # } +/// # } +/// struct FooContainer { +/// foo1: Foo, +/// foo2: Foo, +/// other: u32, +/// } +/// +/// impl FooContainer { +/// fn new(other: u32) -> impl Init { +/// init!(Self { +/// foo1: Foo::new(), +/// foo2: Foo::new(), +/// other, +/// }) +/// } +/// } +/// ``` +#[macro_export] +macro_rules! init { + ($t:ident $(<$($generics:ty),* $(,)?>)? { + $($field:ident $(: $val:expr)?),* + $(,)? + }) => {{ + // we do not want to allow arbitrary returns + struct __InitOk; + let init = move |slot: *mut $t $(<$($generics),*>)?| -> ::core::result::Result<__InitOk, _> { + { + // shadow the structure so it cannot be used to return early + struct __InitOk; + $( + $(let $field = $val;)? + // call the initializer + // SAFETY: slot is valid, because we are inside of an initializer closure, we return + // when an error/panic occurs. + unsafe { $crate::init::__private::__InitImpl::__init($field, ::core::ptr::addr_of_mut!((*slot).$field))? }; + // create the drop guard + // SAFETY: we forget the guard later when initialization has succeeded. + let $field = unsafe { $crate::init::__private::DropGuard::new(::core::ptr::addr_of_mut!((*slot).$field)) }; + // only give access to &DropGuard, so it cannot be accidentally forgotten + let $field = &$field; + )* + #[allow(unreachable_code, clippy::diverging_sub_expression)] + if false { + let _: $t $(<$($generics),*>)? = $t { + $($field: ::core::todo!()),* + }; + } + $( + // forget each guard + unsafe { $crate::init::__private::DropGuard::forget($field) }; + )* + } + Ok(__InitOk) + }; + let init = move |slot: *mut $t $(<$($generics),*>)?| -> ::core::result::Result<(), _> { + init(slot).map(|__InitOk| ()) + }; + let init = unsafe { $crate::init::init_from_closure::<$t $(<$($generics),*>)?, _>(init) }; + 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`], [`Arc`], [`UniqueArc`], or even the stack (see [`stack_init!`]). Use the +/// `pin_init` function of a smart pointer like [`Arc::pin_init`] on this. +/// +/// Also see the [module description](self). +/// +/// # Safety +/// +/// When implementing this type you will need to take great care. Also there are probably very few +/// cases where a manual implementation is necessary. Use [`from_value`] and +/// [`pin_init_from_closure`] where possible. +/// +/// The [`PinInit::__pinned_init`] function +/// - returns `Ok(())` iff it initialized every field of slot, +/// - returns `Err(err)` iff it encountered an error and then cleaned slot, this means: +/// - slot can be deallocated without UB ocurring, +/// - slot does not need to be dropped, +/// - slot is not partially initialized. +/// +/// [`Arc`]: crate::sync::Arc +/// [`Arc::pin_init`]: crate::sync::Arc::pin_init +#[must_use = "An initializer must be used in order to create its value."] +pub unsafe trait PinInit: Sized { + /// Initializes `slot`. + /// + /// # Safety + /// + /// `slot` is a valid pointer to uninitialized memory. + /// The caller does not touch `slot` when `Err` is returned, they are only permitted to + /// deallocate. + /// The slot will not move, i.e. it will be pinned. + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>; +} + +/// An initializer for `T`. +/// +/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can +/// be [`Box`], [`Arc`], [`UniqueArc`], or even the stack (see [`stack_init!`]). Use the +/// `init` function of a smart pointer like [`Box::init`] on this. Because [`PinInit`] is a +/// super trait, you can use every function that takes it as well. +/// +/// Also see the [module description](self). +/// +/// # Safety +/// +/// When implementing this type you will need to take great care. Also there are probably very few +/// cases where a manual implementation is necessary. Use [`from_value`] and +/// [`init_from_closure`] where possible. +/// +/// The [`Init::__init`] function +/// - returns `Ok(())` iff it initialized every field of slot, +/// - returns `Err(err)` iff it encountered an error and then cleaned slot, this means: +/// - slot can be deallocated without UB ocurring, +/// - slot does not need to be dropped, +/// - slot is not partially initialized. +/// +/// The `__pinned_init` function from the supertrait [`PinInit`] needs to exectute the exact same +/// code as `__init`. +/// +/// Contrary to its supertype [`PinInit`] the caller is allowed to +/// move the pointee after initialization. +/// +/// [`Arc`]: crate::sync::Arc +#[must_use = "An initializer must be used in order to create its value."] +pub unsafe trait Init: PinInit { + /// Initializes `slot`. + /// + /// # Safety + /// + /// `slot` is a valid pointer to uninitialized memory. + /// The caller does not touch `slot` when `Err` is returned, they are only permitted to + /// deallocate. + unsafe fn __init(self, slot: *mut T) -> Result<(), E>; +} + +type Invariant = PhantomData T>; + +struct InitClosure(F, Invariant<(T, E)>); + +unsafe impl PinInit for InitClosure +where + F: FnOnce(*mut T) -> Result<(), E>, +{ + #[inline] + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + (self.0)(slot) + } +} + +unsafe impl Init for InitClosure +where + F: FnOnce(*mut T) -> Result<(), E>, +{ + #[inline] + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + (self.0)(slot) + } +} + +/// Creates a new [`Init`] from the given closure. +/// +/// # Safety +/// +/// The closure +/// - returns `Ok(())` iff it initialized every field of slot, +/// - returns `Err(err)` iff it encountered an error and then cleaned slot, this means: +/// - slot can be deallocated without UB ocurring, +/// - slot does not need to be dropped, +/// - slot is not partially initialized. +/// - slot may move after initialization +#[inline] +pub const unsafe fn init_from_closure( + f: impl FnOnce(*mut T) -> Result<(), E>, +) -> impl Init { + InitClosure(f, PhantomData) +} + +/// Creates a new [`PinInit`] from the given closure. +/// +/// # Safety +/// +/// The closure +/// - returns `Ok(())` iff it initialized every field of slot, +/// - returns `Err(err)` iff it encountered an error and then cleaned slot, this means: +/// - slot can be deallocated without UB ocurring, +/// - slot does not need to be dropped, +/// - slot is not partially initialized. +/// - may assume that the slot does not move if `T: !Unpin` +#[inline] +pub const unsafe fn pin_init_from_closure( + f: impl FnOnce(*mut T) -> Result<(), E>, +) -> impl PinInit { + InitClosure(f, PhantomData) +} + +/// Trait facilitating pinned destruction. +/// +/// Use [`pinned_drop`] to implement this trait safely: +/// ```rust +/// # use kernel::sync::Mutex; +/// use kernel::macros::pinned_drop; +/// #[pin_project(PinnedDrop)] +/// struct Foo { +/// #[pin] +/// mtx: Mutex, +/// } +/// +/// #[pinned_drop] +/// impl PinnedDrop for Foo { +/// fn drop(self: Pin<&mut Self>) { +/// pr_info!("Foo is being dropped!"); +/// } +/// } +/// ``` +/// +/// # Safety +/// +/// This trait must be implemented with [`pinned_drop`]. +/// +/// [`pinned_drop`]: kernel::macros::pinned_drop +pub unsafe trait PinnedDrop { + /// Executes the pinned destructor of this type. + /// + /// # Safety + /// + /// Only call this from `::drop`. + unsafe fn drop(self: Pin<&mut Self>); + + // used by `pinned_drop` to ensure that only safe operations are used in `drop`. + #[doc(hidden)] + fn __ensure_no_unsafe_op_in_drop(self: Pin<&mut Self>); +} + +/// Smart pointer that can initialize memory in-place. +pub trait InPlaceInit: Sized { + /// Use the given initializer to in-place initialize a `T`. + /// + /// If `T: !Unpin` it will not be able to move afterwards. + fn pin_init(init: impl PinInit) -> error::Result> + where + Error: From; + + /// Use the given initializer to in-place initialize a `T`. + fn init(init: impl Init) -> error::Result + where + Error: From; +} + +impl InPlaceInit for Box { + #[inline] + fn pin_init(init: impl PinInit) -> error::Result> + where + Error: From, + { + let mut this = Box::try_new_uninit()?; + let slot = this.as_mut_ptr(); + // SAFETY: when init errors/panics, slot will get deallocated but not dropped, + // slot is valid and will not be moved because of the `Pin::new_unchecked` + unsafe { init.__pinned_init(slot)? }; + // SAFETY: all fields have been initialized + Ok(unsafe { Pin::new_unchecked(this.assume_init()) }) + } + + #[inline] + fn init(init: impl Init) -> error::Result + where + Error: From, + { + let mut this = Box::try_new_uninit()?; + let slot = this.as_mut_ptr(); + // SAFETY: when init errors/panics, slot will get deallocated but not dropped, + // slot is valid + unsafe { init.__init(slot)? }; + // SAFETY: all fields have been initialized + Ok(unsafe { this.assume_init() }) + } +} + +impl InPlaceInit for UniqueArc { + #[inline] + fn pin_init(init: impl PinInit) -> error::Result> + where + Error: From, + { + let mut this = UniqueArc::try_new_uninit()?; + let slot = this.as_mut_ptr(); + // SAFETY: when init errors/panics, slot will get deallocated but not dropped, + // slot is valid and will not be moved because of the `Pin::new_unchecked` + unsafe { init.__pinned_init(slot)? }; + // SAFETY: all fields have been initialized + Ok(unsafe { Pin::new_unchecked(this.assume_init()) }) + } + + #[inline] + fn init(init: impl Init) -> error::Result + where + Error: From, + { + let mut this = UniqueArc::try_new_uninit()?; + let slot = this.as_mut_ptr(); + // SAFETY: when init errors/panics, slot will get deallocated but not dropped, + // slot is valid + unsafe { init.__init(slot)? }; + // SAFETY: all fields have been initialized + Ok(unsafe { this.assume_init() }) + } +} + +/// Marker trait for types that can be initialized by writing just zeroes. +/// +/// # Safety +/// +/// The bit pattern consisting of only zeroes must be a valid bit pattern for the type. +pub unsafe trait Zeroable {} + +/// Create a new zeroed T. +/// +/// The returned initializer will write `0x00` to every byte of the given slot. +#[inline] +pub fn zeroed() -> impl Init { + // SAFETY: because `T: Zeroable`, all bytes zero is a valid bit pattern for `T` + // and because we write all zeroes, the memory is initialized. + unsafe { + init_from_closure(|slot: *mut T| { + slot.write_bytes(0, 1); + Ok(()) + }) + } +} + +/// An initializer that leaves the memory uninitialized. +/// +/// The initializer is a no-op. The slot memory is not changed. +#[inline] +pub fn uninit() -> impl Init> { + // SAFETY: The memory is allowed to be uninitialized. + unsafe { init_from_closure(|_| Ok(())) } +} + +/// Convert a value into an initializer. +/// +/// Directly moves the value into the given slot. +#[inline] +pub fn from_value(value: T) -> impl Init { + // SAFETY: we use the value to initialize the slot. + unsafe { + init_from_closure(move |slot: *mut T| { + slot.write(value); + Ok(()) + }) + } +} + +macro_rules! impl_zeroable { + ($($t:ty),*) => { + $(unsafe impl Zeroable for $t {})* + }; +} +// All primitives that are allowed to be zero. +impl_zeroable!( + bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64 +); +// There is nothing to zero. +impl_zeroable!(core::marker::PhantomPinned, Infallible, ()); + +// We are allowed to zero padding bytes. +unsafe impl Zeroable for [T; N] {} + +// There is nothing to zero. +unsafe impl Zeroable for PhantomData {} + +// `null` pointer is valid. +unsafe impl Zeroable for *mut T {} +unsafe impl Zeroable for *const T {} + +macro_rules! impl_tuple_zeroable { + ($(,)?) => {}; + ($first:ident, $($t:ident),* $(,)?) => { + // all elements are zeroable and padding can be zero + unsafe impl<$first: Zeroable, $($t: Zeroable),*> Zeroable for ($first, $($t),*) {} + impl_tuple_zeroable!($($t),* ,); + } +} + +impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J); diff --git a/rust/kernel/init/__private.rs b/rust/kernel/init/__private.rs new file mode 100644 index 00000000000000..2f1f8cb412f47c --- /dev/null +++ b/rust/kernel/init/__private.rs @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Workaround for specialization + +use super::*; +use core::cell::Cell; + +mod sealed { + use super::*; + pub trait Sealed {} + + impl Sealed for Direct {} + impl Sealed for Closure {} +} + +pub trait InitWay: sealed::Sealed {} + +impl InitWay for Direct {} +impl InitWay for Closure {} + +pub struct Direct; +pub struct Closure; + +/// # Safety +/// Same as [`PinInit`] +pub unsafe trait __PinInitImpl { + /// # Safety + /// Same as [`PinInit::__pinned_init`] + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>; +} + +/// # Safety +/// Same as [`Init`] +pub unsafe trait __InitImpl: __PinInitImpl { + /// # Safety + /// Same as [`Init::__init`] + unsafe fn __init(self, slot: *mut T) -> Result<(), E>; +} + +/// # Safety +/// Only implemented by pin_data! +pub unsafe trait __PinData { + type __PinData; +} + +unsafe impl __PinInitImpl for T { + #[inline] + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), Infallible> { + // SAFETY: pointer valid as per function contract + unsafe { slot.write(self) }; + Ok(()) + } +} + +unsafe impl __InitImpl for T { + #[inline] + unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> { + // SAFETY: pointer valid as per function contract + unsafe { slot.write(self) }; + Ok(()) + } +} + +unsafe impl __InitImpl for I +where + I: Init, +{ + #[inline] + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + unsafe { Init::__init(self, slot) } + } +} + +unsafe impl __PinInitImpl for I +where + I: PinInit, +{ + #[inline] + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + unsafe { PinInit::__pinned_init(self, slot) } + } +} + +/// When a value of this type is dropped, it drops something else. +pub struct DropGuard(*mut T, Cell); + +impl DropGuard { + /// Creates a new [`DropGuard`]. It will [`ptr::drop_in_place`] `ptr` when it gets dropped. + /// + /// # Safety + /// `ptr` must be a valid poiner. + /// + /// It is the callers responsibility that `self` will only get dropped if the pointee of `ptr`: + /// - has not been dropped, + /// - is not accesible by any other means, + /// - will not be dropped by any other means. + #[inline] + pub unsafe fn new(ptr: *mut T) -> Self { + Self(ptr, Cell::new(true)) + } + + #[inline] + pub unsafe fn forget(&self) { + self.1.set(false); + } +} + +impl Drop for DropGuard { + #[inline] + fn drop(&mut self) { + if self.1.get() { + // SAFETY: safe as a `DropGuard` can only be constructed using the unsafe new function. + unsafe { ptr::drop_in_place(self.0) } + } + } +} + +/// Stack initializer helper type. See [`stack_init`]. +/// +/// [`stack_init`]: kernel::stack_init +pub struct StackInit(MaybeUninit, bool); + +impl Drop for StackInit { + #[inline] + fn drop(&mut self) { + if self.1 { + unsafe { self.0.assume_init_drop() }; + } + } +} +impl StackInit { + #[inline] + pub fn uninit() -> Self { + Self(MaybeUninit::uninit(), false) + } + + /// # Safety + /// The caller ensures that `self` is on the stack and not accesible to **any** other code. + #[inline] + pub unsafe fn init(&mut self, init: impl PinInit) -> Result, E> { + unsafe { init.__pinned_init(self.0.as_mut_ptr()) }?; + self.1 = true; + Ok(unsafe { Pin::new_unchecked(self.0.assume_init_mut()) }) + } +} diff --git a/rust/kernel/init/pin_project.rs b/rust/kernel/init/pin_project.rs new file mode 100644 index 00000000000000..7365de1fae92ee --- /dev/null +++ b/rust/kernel/init/pin_project.rs @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0 + +// use the proc macro instead +#[doc(hidden)] +#[macro_export] +macro_rules! pin_project { + (parse_input: + @args($($pinned_drop:ident)?), + @sig( + $(#[$($struct_attr:tt)*])* + $vis:vis struct $name:ident + $(where $($whr:tt)*)? + ), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @body({ $($fields:tt)* }), + ) => { + $crate::pin_project!(find_pinned_fields: + @struct_attrs($(#[$($struct_attr)*])*), + @vis($vis), + @name($name), + @impl_generics($($impl_generics)*), + @ty_generics($($ty_generics)*), + @where($($($whr)*)?), + @fields_munch($($fields)*), + @pinned(), + @not_pinned(), + @fields(), + @accum(), + @is_pinned(), + @pinned_drop($($pinned_drop)?), + ); + }; + (find_pinned_fields: + @struct_attrs($($struct_attrs:tt)*), + @vis($vis:vis), + @name($name:ident), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @where($($whr:tt)*), + @fields_munch($field:ident : $type:ty, $($rest:tt)*), + @pinned($($pinned:tt)*), + @not_pinned($($not_pinned:tt)*), + @fields($($fields:tt)*), + @accum($($accum:tt)*), + @is_pinned(yes), + @pinned_drop($($pinned_drop:ident)?), + ) => { + $crate::pin_project!(find_pinned_fields: + @struct_attrs($($struct_attrs)*), + @vis($vis), + @name($name), + @impl_generics($($impl_generics)*), + @ty_generics($($ty_generics)*), + @where($($whr)*), + @fields_munch($($rest)*), + @pinned($($pinned)* $($accum)* $field: $type,), + @not_pinned($($not_pinned)*), + @fields($($fields)* $($accum)* $field: $type,), + @accum(), + @is_pinned(), + @pinned_drop($($pinned_drop)?), + ); + }; + (find_pinned_fields: + @struct_attrs($($struct_attrs:tt)*), + @vis($vis:vis), + @name($name:ident), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @where($($whr:tt)*), + @fields_munch($field:ident : $type:ty, $($rest:tt)*), + @pinned($($pinned:tt)*), + @not_pinned($($not_pinned:tt)*), + @fields($($fields:tt)*), + @accum($($accum:tt)*), + @is_pinned(), + @pinned_drop($($pinned_drop:ident)?), + ) => { + $crate::pin_project!(find_pinned_fields: + @struct_attrs($($struct_attrs)*), + @vis($vis), + @name($name), + @impl_generics($($impl_generics)*), + @ty_generics($($ty_generics)*), + @where($($whr)*), + @fields_munch($($rest)*), + @pinned($($pinned)*), + @not_pinned($($not_pinned)* $($accum)* $field: $type,), + @fields($($fields)* $($accum)* $field: $type,), + @accum(), + @is_pinned(), + @pinned_drop($($pinned_drop)?), + ); + }; + (find_pinned_fields: + @struct_attrs($($struct_attrs:tt)*), + @vis($vis:vis), + @name($name:ident), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @where($($whr:tt)*), + @fields_munch(#[pin] $($rest:tt)*), + @pinned($($pinned:tt)*), + @not_pinned($($not_pinned:tt)*), + @fields($($fields:tt)*), + @accum($($accum:tt)*), + @is_pinned($($is_pinned:ident)?), + @pinned_drop($($pinned_drop:ident)?), + ) => { + $crate::pin_project!(find_pinned_fields: + @struct_attrs($($struct_attrs)*), + @vis($vis), + @name($name), + @impl_generics($($impl_generics)*), + @ty_generics($($ty_generics)*), + @where($($whr)*), + @fields_munch($($rest)*), + @pinned($($pinned)*), + @not_pinned($($not_pinned)*), + @fields($($fields)*), + @accum($($accum)*), + @is_pinned(yes), + @pinned_drop($($pinned_drop)?), + ); + }; + (find_pinned_fields: + @struct_attrs($($struct_attrs:tt)*), + @vis($vis:vis), + @name($name:ident), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @where($($whr:tt)*), + @fields_munch($fvis:vis $field:ident $($rest:tt)*), + @pinned($($pinned:tt)*), + @not_pinned($($not_pinned:tt)*), + @fields($($fields:tt)*), + @accum($($accum:tt)*), + @is_pinned($($is_pinned:ident)?), + @pinned_drop($($pinned_drop:ident)?), + ) => { + $crate::pin_project!(find_pinned_fields: + @struct_attrs($($struct_attrs)*), + @vis($vis), + @name($name), + @impl_generics($($impl_generics)*), + @ty_generics($($ty_generics)*), + @where($($whr)*), + @fields_munch($field $($rest)*), + @pinned($($pinned)*), + @not_pinned($($not_pinned)*), + @fields($($fields)*), + @accum($($accum)* $fvis), + @is_pinned(yes), + @pinned_drop($($pinned_drop)?), + ); + }; + (find_pinned_fields: + @struct_attrs($($struct_attrs:tt)*), + @vis($vis:vis), + @name($name:ident), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @where($($whr:tt)*), + @fields_munch(#[$($attr:tt)*] $($rest:tt)*), + @pinned($($pinned:tt)*), + @not_pinned($($not_pinned:tt)*), + @fields($($fields:tt)*), + @accum($($accum:tt)*), + @is_pinned($($is_pinned:ident)?), + @pinned_drop($($pinned_drop:ident)?), + ) => { + $crate::pin_project!(find_pinned_fields: + @struct_attrs($($struct_attrs)*), + @vis($vis), + @name($name), + @impl_generics($($impl_generics)*), + @ty_generics($($ty_generics)*), + @where($($whr)*), + @fields_munch($($rest)*), + @pinned($($pinned)*), + @not_pinned($($not_pinned)*), + @fields($($fields)*), + @accum($($accum)* #[$($attr)*]), + @is_pinned(yes), + @pinned_drop($($pinned_drop)?), + ); + }; + (find_pinned_fields: + @struct_attrs($($struct_attrs:tt)*), + @vis($vis:vis), + @name($name:ident), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @where($($whr:tt)*), + @fields_munch(), + @pinned($($pinned:tt)*), + @not_pinned($($not_pinned:tt)*), + @fields($($fields:tt)*), + @accum(), + @is_pinned(), + @pinned_drop($($pinned_drop:ident)?), + ) => { + $($struct_attrs)* + $vis struct $name <$($impl_generics)*> + where $($whr)* + { + $($fields)* + } + + const _: () = { + $vis struct __ThePinData<$($impl_generics)*> + where $($whr)* + { + __phantom: ::core::marker::PhantomData) -> $name<$($ty_generics)*>>, + } + + $crate::pin_project!(make_pin_data: + @pin_data(__ThePinData), + @impl_generics($($impl_generics)*), + @ty_generics($($ty_generics)*), + @where($($whr)*), + @pinned($($pinned)*), + @not_pinned($($not_pinned)*), + ); + + unsafe impl<$($impl_generics)*> $crate::init::__private::__PinData for $name<$($ty_generics)*> + where $($whr)* + { + type __PinData = __ThePinData<$($ty_generics)*>; + } + + #[allow(dead_code)] + struct __Unpin <'__pin, $($impl_generics)*> + where $($whr)* + { + __phantom_pin: ::core::marker::PhantomData &'__pin ()>, + __phantom: ::core::marker::PhantomData) -> $name<$($ty_generics)*>>, + $($pinned)* + } + + #[doc(hidden)] + impl<'__pin, $($impl_generics)*> ::core::marker::Unpin for $name<$($ty_generics)*> + where + __Unpin<'__pin, $($ty_generics)*>: ::core::marker::Unpin, + $($whr)* + {} + + $crate::pin_project!(drop_prevention: + @name($name), + @impl_generics($($impl_generics)*), + @ty_generics($($ty_generics)*), + @where($($whr)*), + @pinned_drop($($pinned_drop)?), + ); + }; + }; + (drop_prevention: + @name($name:ident), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @where($($whr:tt)*), + @pinned_drop(), + ) => { + trait MustNotImplDrop {} + #[allow(drop_bounds)] + impl MustNotImplDrop for T {} + impl<$($impl_generics)*> MustNotImplDrop for $name<$($ty_generics)*> + where $($whr)* + {} + #[allow(non_camel_case_types)] + trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} + impl UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} + impl<$($impl_generics)*> UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for $name<$($ty_generics)*> + where + $($whr)* + {} + }; + (drop_prevention: + @name($name:ident), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @where($($whr:tt)*), + @pinned_drop(PinnedDrop), + ) => { + impl<$($impl_generics)*> ::core::ops::Drop for $name<$($ty_generics)*> + where $($whr)* + { + fn drop(&mut self) { + let pinned = unsafe { ::core::pin::Pin::new_unchecked(self) }; + unsafe { $crate::init::PinnedDrop::drop(pinned) } + } + } + }; + (make_pin_data: + @pin_data($pin_data:ident), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @where($($whr:tt)*), + @pinned($($(#[$($p_attr:tt)*])* $pvis:vis $p_field:ident : $p_type:ty),* $(,)?), + @not_pinned($($(#[$($attr:tt)*])* $fvis:vis $field:ident : $type:ty),* $(,)?), + ) => { + #[allow(dead_code)] + impl<$($impl_generics)*> $pin_data<$($ty_generics)*> + where $($whr)* + { + $( + $pvis unsafe fn $p_field( + slot: *mut $p_type, + init: impl $crate::init::__private::__PinInitImpl<$p_type, E, W>, + ) -> ::core::result::Result<(), E> { + unsafe { $crate::init::__private::__PinInitImpl::__pinned_init(init, slot) } + } + )* + $( + $fvis unsafe fn $field( + slot: *mut $type, + init: impl $crate::init::__private::__InitImpl<$type, E, W>, + ) -> ::core::result::Result<(), E> { + unsafe { $crate::init::__private::__InitImpl::__init(init, slot) } + } + )* + } + }; +} diff --git a/rust/kernel/init/pinned_drop.rs b/rust/kernel/init/pinned_drop.rs new file mode 100644 index 00000000000000..d2e50763104a6f --- /dev/null +++ b/rust/kernel/init/pinned_drop.rs @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 + +// use the proc macro instead +#[doc(hidden)] +#[macro_export] +macro_rules! pinned_drop { + ( + @impl_sig($($impl_sig:tt)*), + @impl_body( + $(#[$($attr:tt)*])* + fn drop($self:ident: $st:ty) { + $($inner:stmt)* + } + ), + ) => { + unsafe $($impl_sig)* { + $(#[$($attr)*])* + unsafe fn drop($self: $st) { + $($inner)* + } + + fn __ensure_no_unsafe_op_in_drop($self: $st) { + if false { + $($inner)* + } + } + } + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 7f09072733efba..c14cba847470b7 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -25,6 +25,7 @@ #![feature(ptr_metadata)] #![feature(receiver_trait)] #![feature(unsize)] +#![feature(new_uninit)] // Ensure conditional compilation based on the kernel configuration works; // otherwise we may silently break things like initcall handling. @@ -57,6 +58,7 @@ pub mod file; pub mod fs; pub mod gpio; pub mod hwrng; +pub mod init; pub mod irq; pub mod kasync; pub mod miscdev; diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 26f8af9e16ab66..a5b78f10f25a16 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -21,7 +21,8 @@ pub use super::build_assert; pub use super::{ dbg, dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn, fmt, - pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn, + init, macros::pin_data, pin_init, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, + pr_notice, pr_warn, }; pub use super::{module_fs, module_misc_device}; diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index bf7fe671e31dab..afcbe53d15d17b 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -15,7 +15,12 @@ //! //! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html -use crate::{bindings, error::code::*, Error, Opaque, Result}; +use crate::{ + bindings, + init::{Init, PinInit}, + prelude::*, + Error, Opaque, Result, +}; use alloc::{ alloc::{alloc, dealloc}, vec::Vec, @@ -97,6 +102,14 @@ impl Arc { Ok(unsafe { Self::from_inner(inner) }) } + /// Creates a new `Arc` and initializes its contenst with the given initializer. + pub fn pin_init(init: impl PinInit) -> Result + where + Error: From, + { + UniqueArc::pin_init(init).map(|u| u.into()) + } + /// Deconstructs a [`Arc`] object into a `usize`. /// /// It can be reconstructed once via [`Arc::from_usize`]. diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 397e1496da28be..0ea84fec3ace0a 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -5,6 +5,8 @@ mod concat_idents; mod helpers; mod module; +mod pin_project; +mod pinned_drop; mod vtable; use proc_macro::TokenStream; @@ -189,3 +191,46 @@ pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream { pub fn concat_idents(ts: TokenStream) -> TokenStream { concat_idents::concat_idents(ts) } + +/// Used to specify the pin information of the fields of a struct. +/// +/// This is somewhat similar in purpose as +/// [pin-project-lite](https://crates.io/crates/pin-project-lite). +/// Place this macro on a struct definition and then `#[pin]` in front of the attributes of each +/// field you want to have structurally pinned. +/// +/// # Examples +/// +/// ```rust,ignore +/// #[pin_data] +/// struct A { +/// #[pin] +/// a: usize, +/// } +/// ``` +#[proc_macro_attribute] +pub fn pin_project(inner: TokenStream, item: TokenStream) -> TokenStream { + pin_project::pin_project(inner, item) +} + +/// Used to implement `PinnedDrop` safely. +/// +/// # Examples +/// +/// ```rust,ignore +/// #[pin_project(PinnedDrop)] +/// struct Foo { +/// a: usize, +/// } +/// +/// #[pinned_drop] +/// impl PinnedDrop for Foo { +/// fn drop(self: Pin<&mut Self>) { +/// pr_info!("dropping a Foo"); +/// } +/// } +/// ``` +#[proc_macro_attribute] +pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { + pinned_drop::pinned_drop(args, input) +} diff --git a/rust/macros/pin_project.rs b/rust/macros/pin_project.rs new file mode 100644 index 00000000000000..5a4507fcd4d416 --- /dev/null +++ b/rust/macros/pin_project.rs @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 + +use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; + +pub(crate) fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream { + let mut impl_generics = vec![]; + let mut ty_generics = vec![]; + let mut rest = vec![]; + let mut nesting = 0; + let mut toks = input.into_iter(); + let mut at_start = true; + for tt in &mut toks { + match tt.clone() { + TokenTree::Punct(p) if p.as_char() == '<' => { + if nesting >= 1 { + impl_generics.push(tt); + } + nesting += 1; + } + TokenTree::Punct(p) if p.as_char() == '>' => { + if nesting == 0 { + break; + } else { + nesting -= 1; + if nesting >= 1 { + impl_generics.push(tt); + } + if nesting == 0 { + break; + } + } + } + tt => { + if nesting == 1 { + match &tt { + TokenTree::Ident(i) if i.to_string() == "const" => {} + TokenTree::Ident(_) if at_start => { + ty_generics.push(tt.clone()); + ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); + at_start = false; + } + TokenTree::Punct(p) if p.as_char() == ',' => at_start = true, + TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { + ty_generics.push(tt.clone()); + ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); + } + _ => {} + } + } + if nesting >= 1 { + impl_generics.push(tt); + } else if nesting == 0 { + rest.push(tt); + } + } + } + } + rest.extend(toks); + let last = rest.pop(); + TokenStream::from_iter(vec![ + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Ident(Ident::new("kernel", Span::call_site())), + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Ident(Ident::new("pin_project", Span::call_site())), + TokenTree::Punct(Punct::new('!', Spacing::Alone)), + TokenTree::Group(Group::new( + Delimiter::Brace, + TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("parse_input", Span::call_site())), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("args", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(args), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("sig", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(rest), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("impl_generics", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(impl_generics), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("ty_generics", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(ty_generics), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("body", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(last), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + ]), + )), + ]) +} diff --git a/rust/macros/pinned_drop.rs b/rust/macros/pinned_drop.rs new file mode 100644 index 00000000000000..37fbe541b12c4d --- /dev/null +++ b/rust/macros/pinned_drop.rs @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0 + +use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; + +pub(crate) fn pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream { + let mut toks = input.into_iter().collect::>(); + assert!(!toks.is_empty()); + // ensure that we have an impl item + assert!(matches!(&toks[0], TokenTree::Ident(i) if i.to_string() == "impl")); + // ensure that we are implementing `PinnedDrop` + let mut nesting: usize = 0; + let mut pinned_drop_idx = None; + for (i, tt) in toks.iter().enumerate() { + match tt { + TokenTree::Punct(p) if p.as_char() == '<' => { + nesting += 1; + } + TokenTree::Punct(p) if p.as_char() == '>' => { + nesting = nesting.checked_sub(1).unwrap(); + continue; + } + _ => {} + } + if i >= 1 && nesting == 0 { + assert!( + matches!(tt, TokenTree::Ident(i) if i.to_string() == "PinnedDrop"), + "expected 'PinnedDrop', found: '{:?}'", + tt + ); + pinned_drop_idx = Some(i); + break; + } + } + let idx = pinned_drop_idx.unwrap(); + //inserting `::kernel::init::` in reverse order + toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Alone))); + toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Joint))); + toks.insert(idx, TokenTree::Ident(Ident::new("init", Span::call_site()))); + toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Alone))); + toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Joint))); + toks.insert( + idx, + TokenTree::Ident(Ident::new("kernel", Span::call_site())), + ); + toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Alone))); + toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Joint))); + // take the {} body + if let Some(TokenTree::Group(last)) = toks.pop() { + TokenStream::from_iter(vec![ + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Ident(Ident::new("kernel", Span::call_site())), + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Ident(Ident::new("pinned_drop", Span::call_site())), + TokenTree::Punct(Punct::new('!', Spacing::Alone)), + TokenTree::Group(Group::new( + Delimiter::Brace, + TokenStream::from_iter(vec![ + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("impl_sig", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(toks), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("impl_body", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(last.stream()), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + ]), + )), + ]) + } else { + TokenStream::from_iter(toks) + } +} From 9d58f98e35e42d90d0c328b87ca0833c036a5140 Mon Sep 17 00:00:00 2001 From: y86-dev Date: Fri, 7 Oct 2022 12:12:03 +0200 Subject: [PATCH 05/11] rust: use new init API for initializing everything This patch changes the API and internal logic such that the new init API is used. This change results in a lot less `unsafe`, because the new API is a safe abstraction over the unsafe interior. Signed-off-by: Benno Lossin --- drivers/android/context.rs | 26 ++-- drivers/android/node.rs | 30 ++-- drivers/android/process.rs | 44 +++--- drivers/android/thread.rs | 26 ++-- drivers/android/transaction.rs | 41 +++--- rust/kernel/device.rs | 23 ++- rust/kernel/init.rs | 4 +- rust/kernel/kasync/executor/workqueue.rs | 37 ++--- rust/kernel/prelude.rs | 4 +- rust/kernel/sync.rs | 106 +++++++------ rust/kernel/sync/arc.rs | 27 ++++ rust/kernel/sync/condvar.rs | 67 +++++---- rust/kernel/sync/guard.rs | 32 +--- rust/kernel/sync/mutex.rs | 98 +++++++----- rust/kernel/sync/revocable.rs | 63 ++++---- rust/kernel/sync/rwsem.rs | 94 +++++++----- rust/kernel/sync/seqlock.rs | 77 ++++++---- rust/kernel/sync/smutex.rs | 46 ++++-- rust/kernel/sync/spinlock.rs | 180 +++++++++++++++-------- rust/macros/lib.rs | 2 +- samples/rust/rust_miscdev.rs | 29 ++-- samples/rust/rust_semaphore.rs | 33 ++--- samples/rust/rust_sync.rs | 21 +-- 23 files changed, 624 insertions(+), 486 deletions(-) diff --git a/drivers/android/context.rs b/drivers/android/context.rs index ecb48a6bcb44a9..e4f22ede38c6a1 100644 --- a/drivers/android/context.rs +++ b/drivers/android/context.rs @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 use kernel::{ - bindings, + bindings, new_mutex, prelude::*, security, - sync::{Arc, Mutex, UniqueArc}, + sync::{Arc, Mutex}, }; use crate::{ @@ -17,7 +17,9 @@ struct Manager { uid: Option, } +#[pin_project] pub(crate) struct Context { + #[pin] manager: Mutex, } @@ -27,21 +29,15 @@ unsafe impl Sync for Context {} impl Context { pub(crate) fn new() -> Result> { - let mut ctx = Pin::from(UniqueArc::try_new(Self { - // SAFETY: Init is called below. - manager: unsafe { - Mutex::new(Manager { + Arc::pin_init::(pin_init!(Self { + manager: new_mutex!( + Manager { node: None, uid: None, - }) - }, - })?); - - // SAFETY: `manager` is also pinned when `ctx` is. - let manager = unsafe { ctx.as_mut().map_unchecked_mut(|c| &mut c.manager) }; - kernel::mutex_init!(manager, "Context::manager"); - - Ok(ctx.into()) + }, + "Contex::manager" + ), + })) } pub(crate) fn set_manager_node(&self, node_ref: NodeRef) -> Result { diff --git a/drivers/android/node.rs b/drivers/android/node.rs index ce4367a7843692..62f21b03b7834c 100644 --- a/drivers/android/node.rs +++ b/drivers/android/node.rs @@ -2,8 +2,10 @@ use core::sync::atomic::{AtomicU64, Ordering}; use kernel::{ + init::PinInit, io_buffer::IoBufferWriter, linked_list::{GetLinks, Links, List}, + new_spinlock, prelude::*, sync::{Arc, Guard, LockedBy, Mutex, SpinLock}, user_ptr::UserSlicePtrWriter, @@ -54,6 +56,7 @@ struct NodeDeathInner { aborted: bool, } +#[pin_project] pub(crate) struct NodeDeath { node: Arc, process: Arc, @@ -63,37 +66,30 @@ pub(crate) struct NodeDeath { // TODO: Add the moment we're using this for two lists, which isn't safe because we want to // remove from the list without knowing the list it's in. We need to separate this out. death_links: Links, + #[pin] inner: SpinLock, } impl NodeDeath { /// Constructs a new node death notification object. - /// - /// # Safety - /// - /// The caller must call `NodeDeath::init` before using the notification object. - pub(crate) unsafe fn new(node: Arc, process: Arc, cookie: usize) -> Self { - Self { + #[allow(clippy::new_ret_no_self)] + pub(crate) fn new(node: Arc, process: Arc, cookie: usize) -> impl PinInit { + pin_init!(Self { node, process, cookie, work_links: Links::new(), death_links: Links::new(), - inner: unsafe { - SpinLock::new(NodeDeathInner { + inner: new_spinlock!( + NodeDeathInner { dead: false, cleared: false, notification_done: false, aborted: false, - }) - }, - } - } - - pub(crate) fn init(self: Pin<&mut Self>) { - // SAFETY: `inner` is pinned when `self` is. - let inner = unsafe { self.map_unchecked_mut(|n| &mut n.inner) }; - kernel::spinlock_init!(inner, "NodeDeath::inner"); + }, + "NodeDeath::inner" + ), + }) } /// Sets the cleared flag to `true`. diff --git a/drivers/android/process.rs b/drivers/android/process.rs index 97a60b183ec27e..e677299e36c9f7 100644 --- a/drivers/android/process.rs +++ b/drivers/android/process.rs @@ -7,7 +7,7 @@ use kernel::{ file::{self, File, IoctlCommand, IoctlHandler, PollTable}, io_buffer::{IoBufferReader, IoBufferWriter}, linked_list::List, - mm, + mm, new_mutex, pages::Pages, prelude::*, rbtree::RBTree, @@ -242,6 +242,7 @@ impl ProcessNodeRefs { } } +#[pin_project] pub(crate) struct Process { ctx: Arc, @@ -255,10 +256,12 @@ pub(crate) struct Process { // lock. We may want to split up the process state at some point to use a spin lock for the // other fields. // TODO: Make this private again. + #[pin] pub(crate) inner: Mutex, // References are in a different mutex to avoid recursive acquisition when // incrementing/decrementing a node in another process. + #[pin] node_refs: Mutex, } @@ -268,25 +271,13 @@ unsafe impl Sync for Process {} impl Process { fn new(ctx: Arc, cred: ARef) -> Result> { - let mut process = Pin::from(UniqueArc::try_new(Self { + Arc::pin_init::(pin_init!(Self { ctx, cred, - task: Task::current().group_leader().into(), - // SAFETY: `inner` is initialised in the call to `mutex_init` below. - inner: unsafe { Mutex::new(ProcessInner::new()) }, - // SAFETY: `node_refs` is initialised in the call to `mutex_init` below. - node_refs: unsafe { Mutex::new(ProcessNodeRefs::new()) }, - })?); - - // SAFETY: `inner` is pinned when `Process` is. - let pinned = unsafe { process.as_mut().map_unchecked_mut(|p| &mut p.inner) }; - kernel::mutex_init!(pinned, "Process::inner"); - - // SAFETY: `node_refs` is pinned when `Process` is. - let pinned = unsafe { process.as_mut().map_unchecked_mut(|p| &mut p.node_refs) }; - kernel::mutex_init!(pinned, "Process::node_refs"); - - Ok(process.into()) + task: ARef::from(Task::current().group_leader()), + inner: new_mutex!(ProcessInner::new(), "Process::inner"), + node_refs: new_mutex!(ProcessNodeRefs::new(), "Process::node_refs"), + })) } /// Attempts to fetch a work item from the process queue. @@ -714,14 +705,15 @@ impl Process { return Ok(()); } - let death = { - let mut pinned = Pin::from(death.write( - // SAFETY: `init` is called below. - unsafe { NodeDeath::new(info.node_ref.node.clone(), self.clone(), cookie) }, - )); - pinned.as_mut().init(); - Arc::::from(pinned) - }; + let death = Arc::::from( + death + .pin_init_now::(NodeDeath::new( + info.node_ref.node.clone(), + self.clone(), + cookie, + )) + .map_err(|(i, _)| i)?, + ); info.death = Some(death.clone()); diff --git a/drivers/android/thread.rs b/drivers/android/thread.rs index c405388c4fb45f..f5105458c14e45 100644 --- a/drivers/android/thread.rs +++ b/drivers/android/thread.rs @@ -10,9 +10,10 @@ use kernel::{ file::{File, PollTable}, io_buffer::{IoBufferReader, IoBufferWriter}, linked_list::{GetLinks, Links, List}, + new_condvar, new_spinlock, prelude::*, security, - sync::{Arc, CondVar, SpinLock, UniqueArc}, + sync::{Arc, CondVar, SpinLock}, user_ptr::{UserSlicePtr, UserSlicePtrWriter}, Either, }; @@ -229,10 +230,13 @@ impl InnerThread { } } +#[pin_project] pub(crate) struct Thread { pub(crate) id: i32, pub(crate) process: Arc, + #[pin] inner: SpinLock, + #[pin] work_condvar: CondVar, links: Links, } @@ -241,23 +245,13 @@ impl Thread { pub(crate) fn new(id: i32, process: Arc) -> Result> { let return_work = Arc::try_new(ThreadError::new(InnerThread::set_return_work))?; let reply_work = Arc::try_new(ThreadError::new(InnerThread::set_reply_work))?; - let mut thread = Pin::from(UniqueArc::try_new(Self { + let thread = Arc::pin_init::(pin_init!(Self { id, process, - // SAFETY: `inner` is initialised in the call to `spinlock_init` below. - inner: unsafe { SpinLock::new(InnerThread::new()) }, - // SAFETY: `work_condvar` is initialised in the call to `condvar_init` below. - work_condvar: unsafe { CondVar::new() }, + inner: new_spinlock!(InnerThread::new(), "Thread::inner"), + work_condvar: new_condvar!("Thread::work_condvar"), links: Links::new(), - })?); - - // SAFETY: `inner` is pinned when `thread` is. - let inner = unsafe { thread.as_mut().map_unchecked_mut(|t| &mut t.inner) }; - kernel::spinlock_init!(inner, "Thread::inner"); - - // SAFETY: `work_condvar` is pinned when `thread` is. - let condvar = unsafe { thread.as_mut().map_unchecked_mut(|t| &mut t.work_condvar) }; - kernel::condvar_init!(condvar, "Thread::work_condvar"); + }))?; { let mut inner = thread.inner.lock(); @@ -265,7 +259,7 @@ impl Thread { inner.set_return_work(return_work); } - Ok(thread.into()) + Ok(thread) } pub(crate) fn set_current_transaction(&self, transaction: Arc) { diff --git a/drivers/android/transaction.rs b/drivers/android/transaction.rs index 34f325d608cbd1..39f24bad147f83 100644 --- a/drivers/android/transaction.rs +++ b/drivers/android/transaction.rs @@ -7,6 +7,8 @@ use kernel::{ io_buffer::IoBufferWriter, linked_list::List, linked_list::{GetLinks, Links}, + macros::pinned_drop, + new_spinlock, prelude::*, sync::{Arc, SpinLock, UniqueArc}, user_ptr::UserSlicePtrWriter, @@ -26,7 +28,9 @@ struct TransactionInner { file_list: List>, } +#[pin_project(PinnedDrop)] pub(crate) struct Transaction { + #[pin] inner: SpinLock, // TODO: Node should be released when the buffer is released. node_ref: Option, @@ -55,26 +59,20 @@ impl Transaction { let data_address = alloc.ptr; let file_list = alloc.take_file_list(); alloc.keep_alive(); - let mut tr = Pin::from(UniqueArc::try_new(Self { - // SAFETY: `spinlock_init` is called below. - inner: unsafe { SpinLock::new(TransactionInner { file_list }) }, + let tr = UniqueArc::pin_init::(pin_init!(Self { + inner: new_spinlock!(TransactionInner { file_list }, "Transaction::inner"), node_ref: Some(node_ref), stack_next, from: from.clone(), to, code: tr.code, flags: tr.flags, - data_size: tr.data_size as _, + data_size: tr.data_size as usize, data_address, - offsets_size: tr.offsets_size as _, + offsets_size: tr.offsets_size as usize, links: Links::new(), free_allocation: AtomicBool::new(true), - })?); - - // SAFETY: `inner` is pinned when `tr` is. - let pinned = unsafe { tr.as_mut().map_unchecked_mut(|t| &mut t.inner) }; - kernel::spinlock_init!(pinned, "Transaction::inner"); - + }))?; Ok(tr.into()) } @@ -88,26 +86,20 @@ impl Transaction { let data_address = alloc.ptr; let file_list = alloc.take_file_list(); alloc.keep_alive(); - let mut tr = Pin::from(UniqueArc::try_new(Self { - // SAFETY: `spinlock_init` is called below. - inner: unsafe { SpinLock::new(TransactionInner { file_list }) }, + let tr = UniqueArc::pin_init::(pin_init!(Self { + inner: new_spinlock!(TransactionInner { file_list }, "Transaction::inner"), node_ref: None, stack_next: None, from: from.clone(), to, code: tr.code, flags: tr.flags, - data_size: tr.data_size as _, + data_size: tr.data_size as usize, data_address, - offsets_size: tr.offsets_size as _, + offsets_size: tr.offsets_size as usize, links: Links::new(), free_allocation: AtomicBool::new(true), - })?); - - // SAFETY: `inner` is pinned when `tr` is. - let pinned = unsafe { tr.as_mut().map_unchecked_mut(|t| &mut t.inner) }; - kernel::spinlock_init!(pinned, "Transaction::inner"); - + }))?; Ok(tr.into()) } @@ -285,8 +277,9 @@ impl DeliverToRead for Transaction { } } -impl Drop for Transaction { - fn drop(&mut self) { +#[pinned_drop] +impl PinnedDrop for Transaction { + fn drop(self: Pin<&mut Self>) { if self.free_allocation.load(Ordering::Relaxed) { self.to.buffer_get(self.data_address); } diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 9b00b239aefdff..388f742eca0858 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -9,9 +9,12 @@ use crate::{clk::Clk, error::from_kernel_err_ptr}; use crate::{ bindings, + macros::pin_project, + pin_init, + prelude::*, revocable::{Revocable, RevocableGuard}, str::CStr, - sync::{LockClassKey, NeedsLockClass, RevocableMutex, RevocableMutexGuard, UniqueArc}, + sync::{LockClassKey, RevocableMutex, RevocableMutexGuard, UniqueArc}, Result, }; use core::{ @@ -246,7 +249,9 @@ impl Drop for Device { /// /// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not /// explicitly called by the device drivers. +#[pin_project] pub struct Data { + #[pin] registrations: RevocableMutex, resources: Revocable, general: V, @@ -258,12 +263,11 @@ pub struct Data { macro_rules! new_device_data { ($reg:expr, $res:expr, $gen:expr, $name:literal) => {{ static CLASS1: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new(); - static CLASS2: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new(); let regs = $reg; let res = $res; let gen = $gen; let name = $crate::c_str!($name); - $crate::device::Data::try_new(regs, res, gen, name, &CLASS1, &CLASS2) + $crate::device::Data::try_new(regs, res, gen, name, &CLASS1) }}; } @@ -278,19 +282,12 @@ impl Data { general: V, name: &'static CStr, key1: &'static LockClassKey, - key2: &'static LockClassKey, ) -> Result>> { - let mut ret = Pin::from(UniqueArc::try_new(Self { - // SAFETY: We call `RevocableMutex::init` below. - registrations: unsafe { RevocableMutex::new(registrations) }, + UniqueArc::pin_init::(pin_init!(Self { + registrations: RevocableMutex::new(registrations, name, key1), resources: Revocable::new(resources), general, - })?); - - // SAFETY: `Data::registrations` is pinned when `Data` is. - let pinned = unsafe { ret.as_mut().map_unchecked_mut(|d| &mut d.registrations) }; - pinned.init(name, key1, key2); - Ok(ret) + })) } /// Returns the resources if they're still available. diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 7b5467baf5f89f..6a8d9d2e75e37e 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -153,8 +153,8 @@ mod pinned_drop; /// ``` #[macro_export] macro_rules! stack_init { - (let $var:ident = $val:expr) => { - let mut $var = $crate::init::__private::StackInit::uninit(); + (let $var:ident $(: $t:ty)? = $val:expr) => { + let mut $var = $crate::init::__private::StackInit$(::<$t>)?::uninit(); let val = $val; let mut $var = unsafe { $crate::init::__private::StackInit::init(&mut $var, val) }; }; diff --git a/rust/kernel/kasync/executor/workqueue.rs b/rust/kernel/kasync/executor/workqueue.rs index dcde56115b2ebe..6533e53e8b9f84 100644 --- a/rust/kernel/kasync/executor/workqueue.rs +++ b/rust/kernel/kasync/executor/workqueue.rs @@ -5,7 +5,9 @@ use super::{ArcWake, AutoStopHandle}; use crate::{ error::code::*, - mutex_init, + macros::pin_project, + new_mutex, pin_init, + prelude::*, revocable::AsyncRevocable, sync::{Arc, ArcBorrow, LockClassKey, Mutex, UniqueArc}, unsafe_list, @@ -188,9 +190,12 @@ struct ExecutorInner { /// /// # Ok::<(), Error>(()) /// ``` +#[pin_project] pub struct Executor { queue: Either, + #[pin] inner: Mutex, + #[pin] _pin: PhantomPinned, } @@ -217,22 +222,20 @@ impl Executor { /// /// It uses the given work queue to run its tasks. fn new_internal(queue: Either) -> Result> { - let mut e = Pin::from(UniqueArc::try_new(Self { - queue, - _pin: PhantomPinned, - // SAFETY: `mutex_init` is called below. - inner: unsafe { - Mutex::new(ExecutorInner { - stopped: false, - tasks: unsafe_list::List::new(), - }) - }, - })?); - // SAFETY: `tasks` is pinned when the executor is. - let pinned = unsafe { e.as_mut().map_unchecked_mut(|e| &mut e.inner) }; - mutex_init!(pinned, "Executor::inner"); - - Ok(AutoStopHandle::new(e.into())) + Ok(AutoStopHandle::new( + UniqueArc::pin_init::(pin_init!(Self { + inner: new_mutex!( + ExecutorInner { + stopped: false, + tasks: unsafe_list::List::new() + }, + "Executor::inner" + ), + queue, + _pin: PhantomPinned, + }))? + .into(), + )) } } diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index a5b78f10f25a16..05ab8d30bc5b15 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -21,7 +21,7 @@ pub use super::build_assert; pub use super::{ dbg, dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn, fmt, - init, macros::pin_data, pin_init, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, + init, macros::pin_project, pin_init, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn, }; @@ -35,3 +35,5 @@ pub use super::static_assert; pub use super::{error::code::*, Error, Result}; pub use super::{str::CStr, ARef, ThisModule}; + +pub use super::init::InPlaceInit; diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index b2c722187b9800..e8100d2892b22e 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -8,21 +8,19 @@ //! # Examples //! //! ``` -//! # use kernel::mutex_init; +//! # use kernel::new_mutex; //! # use kernel::sync::Mutex; //! # use alloc::boxed::Box; //! # use core::pin::Pin; -//! // SAFETY: `init` is called below. -//! let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(10) }).unwrap()); -//! mutex_init!(data.as_mut(), "test::data"); +//! let data = Box::pin_init(new_mutex!(10, "test::data")).unwrap(); //! //! assert_eq!(*data.lock(), 10); //! *data.lock() = 20; //! assert_eq!(*data.lock(), 20); //! ``` -use crate::{bindings, str::CStr}; -use core::{cell::UnsafeCell, mem::MaybeUninit, pin::Pin}; +use crate::{bindings, init::PinInit}; +use core::{cell::UnsafeCell, mem::MaybeUninit}; mod arc; mod condvar; @@ -39,7 +37,7 @@ mod spinlock; pub use arc::{new_refcount, Arc, ArcBorrow, StaticArc, UniqueArc}; pub use condvar::CondVar; -pub use guard::{Guard, Lock, LockFactory, LockInfo, LockIniter, ReadLock, WriteLock}; +pub use guard::{Guard, Lock, LockFactory, LockInfo, ReadLock, WriteLock}; pub use locked_by::LockedBy; pub use mutex::{Mutex, RevocableMutex, RevocableMutexGuard}; pub use nowait::{NoWaitLock, NoWaitLockGuard}; @@ -72,33 +70,14 @@ impl LockClassKey { /// specialised name that uses this macro. #[doc(hidden)] #[macro_export] -macro_rules! init_with_lockdep { - ($obj:expr, $name:expr) => {{ +macro_rules! new_with_lockdep { + ($what:ty, $name:expr $(, $obj:expr $(,)?)?) => {{ static CLASS1: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new(); - static CLASS2: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new(); - let obj = $obj; let name = $crate::c_str!($name); - $crate::sync::NeedsLockClass::init(obj, name, &CLASS1, &CLASS2) + <$what>::new($($obj,)? name, &CLASS1) }}; } -/// A trait for types that need a lock class during initialisation. -/// -/// Implementers of this trait benefit from the [`init_with_lockdep`] macro that generates a new -/// class for each initialisation call site. -pub trait NeedsLockClass { - /// Initialises the type instance so that it can be safely used. - /// - /// Callers are encouraged to use the [`init_with_lockdep`] macro as it automatically creates a - /// new lock class on each usage. - fn init( - self: Pin<&mut Self>, - name: &'static CStr, - key1: &'static LockClassKey, - key2: &'static LockClassKey, - ); -} - /// Automatically initialises static instances of synchronisation primitives. /// /// The syntax resembles that of regular static variables, except that the value assigned is that @@ -131,35 +110,70 @@ macro_rules! init_static_sync { ($($(#[$outer:meta])* $v:vis static $id:ident : $t:ty $(= $value:expr)?;)*) => { $( $(#[$outer])* - $v static $id: $t = { + $v static $id: $crate::sync::StaticInit<$t> = { #[link_section = ".init_array"] #[used] static TMP: extern "C" fn() = { extern "C" fn constructor() { // SAFETY: This locally-defined function is only called from a constructor, // which guarantees that `$id` is not accessible from other threads - // concurrently. - #[allow(clippy::cast_ref_to_mut)] - let mutable = unsafe { &mut *(&$id as *const _ as *mut $t) }; - // SAFETY: It's a shared static, so it cannot move. - let pinned = unsafe { core::pin::Pin::new_unchecked(mutable) }; - $crate::init_with_lockdep!(pinned, stringify!($id)); + // concurrently and this is only called once. + unsafe { $crate::sync::StaticInit::init(&$id, $crate::new_with_lockdep!($t, stringify!($id) $(, $value)? )) }; } constructor }; - $crate::init_static_sync!(@call_new $t, $($value)?) + // SAFETY: the initializer is called above in the ctor + unsafe { $crate::sync::StaticInit::uninit() } }; )* }; - (@call_new $t:ty, $value:expr) => {{ - let v = $value; - // SAFETY: the initialisation function is called by the constructor above. - unsafe { <$t>::new(v) } - }}; - (@call_new $t:ty,) => { - // SAFETY: the initialisation function is called by the constructor above. - unsafe { <$t>::new() } - }; +} + +/// A statically initialized value. +pub struct StaticInit { + inner: MaybeUninit>, +} + +unsafe impl Sync for StaticInit {} +unsafe impl Send for StaticInit {} + +impl StaticInit { + /// Creates a new `StaticInit` that is uninitialized. + /// + /// # Safety + /// + /// The caller calls `Self::init` exactly once before using this value. + pub const unsafe fn uninit() -> Self { + Self { + inner: MaybeUninit::uninit(), + } + } + + /// Initializes the contents of `self`. + /// + /// # Safety + /// + /// The caller calls this function exactly once and before any other function (even implicitly + /// derefing) of `self` is called. + pub unsafe fn init(&self, init: impl PinInit) + where + E: Into, + { + unsafe { + let ptr = UnsafeCell::raw_get(self.inner.as_ptr()); + match init.__pinned_init(ptr).map_err(|e| e.into()) { + Ok(()) => {} + Err(e) => match e {}, + } + } + } +} + +impl core::ops::Deref for StaticInit { + type Target = T; + fn deref(&self) -> &Self::Target { + unsafe { &*self.inner.assume_init_ref().get() } + } } /// Reschedules the caller's task if needed. diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index afcbe53d15d17b..4516c2bf526d40 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -516,6 +516,33 @@ impl UniqueArc> { unsafe { self.assume_init() } } + /// Initialize the value after creating the `UniqueArc`. + #[allow(clippy::type_complexity)] + pub fn pin_init_now( + mut self, + init: impl PinInit, + ) -> core::result::Result>, (E, UniqueArc>)> { + unsafe { + match init.__pinned_init(self.deref_mut().as_mut_ptr()) { + Ok(()) => Ok(Pin::from(self.assume_init())), + Err(e) => Err((e, self)), + } + } + } + + /// Initialize the value after creating the `UniqueArc`. + pub fn init_now( + mut self, + init: impl Init, + ) -> core::result::Result, (E, UniqueArc>)> { + unsafe { + match init.__init(self.deref_mut().as_mut_ptr()) { + Ok(()) => Ok(self.assume_init()), + Err(e) => Err((e, self)), + } + } + } + /// Unsafely assume that `self` is initialized. /// /// # Safety diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index b6102906fb3cfc..126ad8312c6af7 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -5,15 +5,23 @@ //! This module allows Rust code to use the kernel's [`struct wait_queue_head`] as a condition //! variable. -use super::{Guard, Lock, LockClassKey, LockInfo, NeedsLockClass}; -use crate::{bindings, str::CStr, task::Task, Opaque}; -use core::{marker::PhantomPinned, pin::Pin}; +use super::{Guard, Lock, LockClassKey, LockInfo}; +use crate::{ + bindings, + init::{self, PinInit}, + macros::pin_project, + pin_init, + str::CStr, + task::Task, + Opaque, +}; +use core::marker::PhantomPinned; /// Safely initialises a [`CondVar`] with the given name, generating a new lock class. #[macro_export] -macro_rules! condvar_init { - ($condvar:expr, $name:literal) => { - $crate::init_with_lockdep!($condvar, $name) +macro_rules! new_condvar { + ($name:literal) => { + $crate::new_with_lockdep!($crate::sync::CondVar, $name) }; } @@ -25,8 +33,14 @@ const POLLFREE: u32 = 0x4000; /// it wakes up when notified by another thread (via [`CondVar::notify_one`] or /// [`CondVar::notify_all`]) or because the thread received a signal. /// +/// A [`CondVar`] is created using the [initialization API][init]. You can either call the `new` +/// function or use the [`new_condvar!`] macro which automatically creates the [`LockClassKey`] for you. +/// /// [`struct wait_queue_head`]: ../../../include/linux/wait.h +/// [init]: ../init/index.html +#[pin_project] pub struct CondVar { + #[pin] pub(crate) wait_list: Opaque, /// A condvar needs to be pinned because it contains a [`struct list_head`] that is @@ -44,15 +58,27 @@ unsafe impl Sync for CondVar {} impl CondVar { /// Constructs a new conditional variable. - /// - /// # Safety - /// - /// The caller must call `CondVar::init` before using the conditional variable. - pub const unsafe fn new() -> Self { - Self { - wait_list: Opaque::uninit(), - _pin: PhantomPinned, + #[allow(clippy::new_ret_no_self)] + pub const fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { + fn init_wait_list( + name: &'static CStr, + key: &'static LockClassKey, + ) -> impl PinInit> { + let init = move |place: *mut Opaque| unsafe { + bindings::__init_waitqueue_head( + Opaque::raw_get(place), + name.as_char_ptr(), + key.get(), + ); + Ok(()) + }; + // SAFETY: waitqueue has been initialized + unsafe { init::pin_init_from_closure(init) } } + pin_init!(Self { + wait_list: init_wait_list(name, key), + _pin: PhantomPinned, + }) } /// Atomically releases the given lock (whose ownership is proven by the guard) and puts the @@ -125,16 +151,3 @@ impl CondVar { self.notify(1, bindings::POLLHUP | POLLFREE); } } - -impl NeedsLockClass for CondVar { - fn init( - self: Pin<&mut Self>, - name: &'static CStr, - key: &'static LockClassKey, - _: &'static LockClassKey, - ) { - unsafe { - bindings::__init_waitqueue_head(self.wait_list.get(), name.as_char_ptr(), key.get()) - }; - } -} diff --git a/rust/kernel/sync/guard.rs b/rust/kernel/sync/guard.rs index 757d85eac7afe5..e8853994829886 100644 --- a/rust/kernel/sync/guard.rs +++ b/rust/kernel/sync/guard.rs @@ -6,9 +6,8 @@ //! the ([`Lock`]) trait. It also contains the definition of the trait, which can be leveraged by //! other constructs to work on generic locking primitives. -use super::{LockClassKey, NeedsLockClass}; -use crate::{str::CStr, Bool, False, True}; -use core::pin::Pin; +use super::LockClassKey; +use crate::{init::PinInit, str::CStr, Bool, False, True}; /// Allows mutual exclusion primitives that implement the [`Lock`] trait to automatically unlock /// when a guard goes out of scope. It also provides a safe and convenient way to access the data @@ -132,28 +131,11 @@ pub unsafe trait Lock { pub trait LockFactory { /// The parametrised type of the mutual exclusion primitive that can be created by this factory. type LockedType; + /// Error that can occur when creating a lock of this kind. + type Error; + /// the initializer used to initialize a lock of this kind. + type Init: PinInit, Self::Error>; /// Constructs a new instance of the mutual exclusion primitive. - /// - /// # Safety - /// - /// The caller must call [`LockIniter::init_lock`] before using the lock. - unsafe fn new_lock(data: T) -> Self::LockedType; -} - -/// A lock that can be initialised with a single lock class key. -pub trait LockIniter { - /// Initialises the lock instance so that it can be safely used. - fn init_lock(self: Pin<&mut Self>, name: &'static CStr, key: &'static LockClassKey); -} - -impl NeedsLockClass for L { - fn init( - self: Pin<&mut Self>, - name: &'static CStr, - key: &'static LockClassKey, - _: &'static LockClassKey, - ) { - self.init_lock(name, key); - } + fn new_lock(data: T, name: &'static CStr, key: &'static LockClassKey) -> Self::Init; } diff --git a/rust/kernel/sync/mutex.rs b/rust/kernel/sync/mutex.rs index c51ae5e3a8a02f..8f78ce8ae03a17 100644 --- a/rust/kernel/sync/mutex.rs +++ b/rust/kernel/sync/mutex.rs @@ -4,15 +4,22 @@ //! //! This module allows Rust code to use the kernel's [`struct mutex`]. -use super::{Guard, Lock, LockClassKey, LockFactory, LockIniter, WriteLock}; -use crate::{bindings, str::CStr, Opaque}; -use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin}; +use super::{Guard, Lock, LockClassKey, LockFactory, WriteLock}; +use crate::{ + bindings, + init::{self, PinInit}, + macros::pin_project, + pin_init, + str::CStr, + Opaque, +}; +use core::{cell::UnsafeCell, marker::PhantomPinned}; /// Safely initialises a [`Mutex`] with the given name, generating a new lock class. #[macro_export] -macro_rules! mutex_init { - ($mutex:expr, $name:literal) => { - $crate::init_with_lockdep!($mutex, $name) +macro_rules! new_mutex { + ($value:expr, $name:literal) => { + $crate::new_with_lockdep!($crate::sync::Mutex<_>, $name, $value) }; } @@ -20,19 +27,22 @@ macro_rules! mutex_init { /// only one at a time is allowed to progress, the others will block (sleep) until the mutex is /// unlocked, at which point another thread will be allowed to wake up and make progress. /// -/// A [`Mutex`] must first be initialised with a call to [`Mutex::init_lock`] before it can be -/// used. The [`mutex_init`] macro is provided to automatically assign a new lock class to a mutex -/// instance. +/// A [`Mutex`] is created using the [initialization API][init]. You can either call the `new` +/// function or use the [`new_mutex!`] macro which automatically creates the [`LockClassKey`] for you. /// /// Since it may block, [`Mutex`] needs to be used with care in atomic contexts. /// /// [`struct mutex`]: ../../../include/linux/mutex.h +/// [init]: ../init/index.html +#[pin_project] pub struct Mutex { /// The kernel `struct mutex` object. + #[pin] mutex: Opaque, /// A mutex needs to be pinned because it contains a [`struct list_head`] that is /// self-referential, so it cannot be safely moved once it is initialised. + #[pin] _pin: PhantomPinned, /// The data protected by the mutex. @@ -49,16 +59,46 @@ unsafe impl Sync for Mutex {} impl Mutex { /// Constructs a new mutex. - /// - /// # Safety - /// - /// The caller must call [`Mutex::init_lock`] before using the mutex. - pub const unsafe fn new(t: T) -> Self { - Self { - mutex: Opaque::uninit(), - data: UnsafeCell::new(t), - _pin: PhantomPinned, + #[allow(clippy::new_ret_no_self)] + pub const fn new( + data: T, + name: &'static CStr, + key: &'static LockClassKey, + ) -> impl PinInit { + MutexInit { data, name, key } + } +} + +#[doc(hidden)] +pub struct MutexInit { + name: &'static CStr, + key: &'static LockClassKey, + data: T, +} + +unsafe impl PinInit> for MutexInit { + unsafe fn __pinned_init( + self, + slot: *mut Mutex, + ) -> core::result::Result<(), core::convert::Infallible> { + fn init_mutex( + name: &'static CStr, + key: &'static LockClassKey, + ) -> impl PinInit> { + let init = move |slot: *mut Opaque| unsafe { + bindings::__mutex_init(Opaque::raw_get(slot), name.as_char_ptr(), key.get()); + Ok(()) + }; + // SAFETY: mutex has been initialized + unsafe { init::pin_init_from_closure(init) } } + let init = pin_init!(Mutex { + mutex: init_mutex(self.name, self.key), + data: UnsafeCell::new(self.data), + _pin: PhantomPinned, + }); + // SAFETY: we are inside of an initializer + unsafe { init.__pinned_init(slot) } } } @@ -74,16 +114,11 @@ impl Mutex { impl LockFactory for Mutex { type LockedType = Mutex; + type Error = core::convert::Infallible; + type Init = MutexInit; - unsafe fn new_lock(data: U) -> Mutex { - // SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called. - unsafe { Mutex::new(data) } - } -} - -impl LockIniter for Mutex { - fn init_lock(self: Pin<&mut Self>, name: &'static CStr, key: &'static LockClassKey) { - unsafe { bindings::__mutex_init(self.mutex.get(), name.as_char_ptr(), key.get()) }; + fn new_lock(data: U, name: &'static CStr, key: &'static LockClassKey) -> Self::Init { + MutexInit { data, name, key } } } @@ -120,7 +155,7 @@ unsafe impl Lock for Mutex { /// /// ``` /// # use kernel::sync::RevocableMutex; -/// # use kernel::revocable_init; +/// # use kernel::{new_revocable, stack_init}; /// # use core::pin::Pin; /// /// struct Example { @@ -133,11 +168,8 @@ unsafe impl Lock for Mutex { /// Some(guard.a + guard.b) /// } /// -/// // SAFETY: We call `revocable_init` immediately below. -/// let mut v = unsafe { RevocableMutex::new(Example { a: 10, b: 20 }) }; -/// // SAFETY: We never move out of `v`. -/// let pinned = unsafe { Pin::new_unchecked(&mut v) }; -/// revocable_init!(pinned, "example::v"); +/// stack_init!(let v: RevocableMutex<_> = new_revocable!(Example { a: 10, b: 20 }, "example::v")); +/// let v = v.unwrap(); /// assert_eq!(read_sum(&v), Some(30)); /// v.revoke(); /// assert_eq!(read_sum(&v), None); diff --git a/rust/kernel/sync/revocable.rs b/rust/kernel/sync/revocable.rs index 8fd7f07f2a65c3..b27839c8807ecb 100644 --- a/rust/kernel/sync/revocable.rs +++ b/rust/kernel/sync/revocable.rs @@ -3,8 +3,11 @@ //! Synchronisation primitives where access to their contents can be revoked at runtime. use crate::{ + init::PinInit, + macros::pin_project, + pin_init, str::CStr, - sync::{Guard, Lock, LockClassKey, LockFactory, LockInfo, NeedsLockClass, ReadLock, WriteLock}, + sync::{Guard, Lock, LockClassKey, LockFactory, LockInfo, ReadLock, WriteLock}, True, }; use core::{ @@ -69,11 +72,14 @@ impl Drop for Inner { /// sleep while holding on to a guard should use [`crate::revocable::Revocable`] instead, which is /// more efficient as it uses RCU to keep objects alive. /// +/// A [`Revocable`] is created using the [initialization API][init]. You can either call the `new` +/// function or use the [`new_revocable!`] macro which automatically creates the [`LockClassKey`] for you. +/// /// # Examples /// /// ``` /// # use kernel::sync::{Mutex, Revocable}; -/// # use kernel::revocable_init; +/// # use kernel::{new_revocable, stack_init}; /// # use core::pin::Pin; /// /// struct Example { @@ -88,56 +94,39 @@ impl Drop for Inner { /// Some(guard.a + guard.b) /// } /// -/// // SAFETY: We call `revocable_init` immediately below. -/// let mut v = unsafe { Revocable::, Example>::new(Example { a: 10, b: 20 }) }; -/// // SAFETY: We never move out of `v`. -/// let pinned = unsafe { Pin::new_unchecked(&mut v) }; -/// revocable_init!(pinned, "example::v"); +/// stack_init!(let v: Revocable::, Example> = new_revocable!(Example { a: 10, b: 20 }, "example::v")); +/// let v = v.unwrap(); /// assert_eq!(add_two(&v), Some(34)); /// v.revoke(); /// assert_eq!(add_two(&v), None); /// ``` +/// [init]: ../init/index.html +/// [`new_revocable!`]: kernel::new_revocable +#[pin_project] pub struct Revocable { - inner: F::LockedType>, + #[pin] + inner: ::LockedType>, } /// Safely initialises a [`Revocable`] instance with the given name, generating a new lock class. #[macro_export] -macro_rules! revocable_init { - ($mutex:expr, $name:literal) => { - $crate::init_with_lockdep!($mutex, $name) +macro_rules! new_revocable { + ($value:expr, $name:literal) => { + $crate::new_with_lockdep!($crate::sync::Revocable<_, _>, $name, $value) }; } impl Revocable { /// Creates a new revocable instance of the given lock. - /// - /// # Safety - /// - /// The caller must call [`Revocable::init`] before using the revocable synch primitive. - pub unsafe fn new(data: T) -> Self { - Self { - // SAFETY: The safety requirements of this function require that `Revocable::init` - // be called before the returned object can be used. Lock initialisation is called - // from `Revocable::init`. - inner: unsafe { F::new_lock(Inner::new(data)) }, - } - } -} - -impl NeedsLockClass for Revocable -where - F::LockedType>: NeedsLockClass, -{ - fn init( - self: Pin<&mut Self>, + #[allow(clippy::new_ret_no_self)] + pub fn new( + data: T, name: &'static CStr, - key1: &'static LockClassKey, - key2: &'static LockClassKey, - ) { - // SAFETY: `inner` is pinned when `self` is. - let inner = unsafe { self.map_unchecked_mut(|r| &mut r.inner) }; - inner.init(name, key1, key2); + key: &'static LockClassKey, + ) -> impl PinInit { + pin_init!(Self { + inner: F::new_lock(Inner::new(data), name, key), + }) } } diff --git a/rust/kernel/sync/rwsem.rs b/rust/kernel/sync/rwsem.rs index 6556d7d30d3658..fc8f45e7678e9c 100644 --- a/rust/kernel/sync/rwsem.rs +++ b/rust/kernel/sync/rwsem.rs @@ -7,17 +7,23 @@ //! C header: [`include/linux/rwsem.h`](../../../../include/linux/rwsem.h) use super::{ - mutex::EmptyGuardContext, Guard, Lock, LockClassKey, LockFactory, LockIniter, ReadLock, - WriteLock, + mutex::EmptyGuardContext, Guard, Lock, LockClassKey, LockFactory, ReadLock, WriteLock, }; -use crate::{bindings, str::CStr, Opaque}; -use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin}; +use crate::{ + bindings, + init::{self, PinInit}, + macros::pin_project, + pin_init, + str::CStr, + Opaque, +}; +use core::{cell::UnsafeCell, marker::PhantomPinned}; /// Safely initialises a [`RwSemaphore`] with the given name, generating a new lock class. #[macro_export] -macro_rules! rwsemaphore_init { - ($rwsem:expr, $name:literal) => { - $crate::init_with_lockdep!($rwsem, $name) +macro_rules! new_rwsemaphore { + ($value:expr, $name:literal) => { + $crate::new_with_lockdep!($crate::sync::RwSemaphore<_>, $name, $value) }; } @@ -26,19 +32,22 @@ macro_rules! rwsemaphore_init { /// It's a read/write mutex. That is, it allows multiple readers to acquire it concurrently, but /// only one writer at a time. On contention, waiters sleep. /// -/// A [`RwSemaphore`] must first be initialised with a call to [`RwSemaphore::init_lock`] before it -/// can be used. The [`rwsemaphore_init`] macro is provided to automatically assign a new lock -/// class to an [`RwSemaphore`] instance. +/// A [`RwSemaphore`] is created using the [initialization API][init]. You can either call the `new` +/// function or use the [`new_rwsemaphore!`] macro which automatically creates the [`LockClassKey`] for you. /// /// Since it may block, [`RwSemaphore`] needs to be used with care in atomic contexts. /// /// [`struct rw_semaphore`]: ../../../include/linux/rwsem.h +/// [init]: ../init/index.html +#[pin_project] pub struct RwSemaphore { /// The kernel `struct rw_semaphore` object. + #[pin] rwsem: Opaque, /// An rwsem needs to be pinned because it contains a [`struct list_head`] that is /// self-referential, so it cannot be safely moved once it is initialised. + #[pin] _pin: PhantomPinned, /// The data protected by the rwsem. @@ -57,16 +66,41 @@ unsafe impl Sync for RwSemaphore {} impl RwSemaphore { /// Constructs a new rw semaphore. - /// - /// # Safety - /// - /// The caller must call [`RwSemaphore::init_lock`] before using the rw semaphore. - pub unsafe fn new(t: T) -> Self { - Self { - rwsem: Opaque::uninit(), - data: UnsafeCell::new(t), - _pin: PhantomPinned, + #[allow(clippy::new_ret_no_self)] + pub fn new(data: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { + Init { data, name, key } + } +} + +#[doc(hidden)] +pub struct Init { + name: &'static CStr, + key: &'static LockClassKey, + data: T, +} + +unsafe impl PinInit> for Init { + unsafe fn __pinned_init( + self, + slot: *mut RwSemaphore, + ) -> core::result::Result<(), core::convert::Infallible> { + fn init_rw_semaphore( + name: &'static CStr, + key: &'static LockClassKey, + ) -> impl PinInit> { + let init = move |slot: *mut Opaque| unsafe { + bindings::__init_rwsem(Opaque::raw_get(slot), name.as_char_ptr(), key.get()); + Ok(()) + }; + unsafe { init::pin_init_from_closure(init) } } + let init = pin_init!(RwSemaphore { + rwsem: init_rw_semaphore(self.name, self.key), + data: UnsafeCell::new(self.data), + _pin: PhantomPinned, + }); + // SAFETY: we are inside of an initializer + unsafe { init.__pinned_init(slot) } } } @@ -90,16 +124,11 @@ impl RwSemaphore { impl LockFactory for RwSemaphore { type LockedType = RwSemaphore; + type Error = core::convert::Infallible; + type Init = Init; - unsafe fn new_lock(data: U) -> RwSemaphore { - // SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called. - unsafe { RwSemaphore::new(data) } - } -} - -impl LockIniter for RwSemaphore { - fn init_lock(self: Pin<&mut Self>, name: &'static CStr, key: &'static LockClassKey) { - unsafe { bindings::__init_rwsem(self.rwsem.get(), name.as_char_ptr(), key.get()) }; + fn new_lock(data: U, name: &'static CStr, key: &'static LockClassKey) -> Self::Init { + Init { data, name, key } } } @@ -158,7 +187,7 @@ unsafe impl Lock for RwSemaphore { /// /// ``` /// # use kernel::sync::RevocableRwSemaphore; -/// # use kernel::revocable_init; +/// # use kernel::{new_revocable, stack_init}; /// # use core::pin::Pin; /// /// struct Example { @@ -178,11 +207,8 @@ unsafe impl Lock for RwSemaphore { /// Some(guard.a + guard.b) /// } /// -/// // SAFETY: We call `revocable_init` immediately below. -/// let mut v = unsafe { RevocableRwSemaphore::new(Example { a: 10, b: 20 }) }; -/// // SAFETY: We never move out of `v`. -/// let pinned = unsafe { Pin::new_unchecked(&mut v) }; -/// revocable_init!(pinned, "example::v"); +/// stack_init!(let v: RevocableRwSemaphore<_> = new_revocable!(Example { a: 10, b: 20 }, "example::v")); +/// let v = v.unwrap(); /// assert_eq!(read_sum(&v), Some(30)); /// assert_eq!(add_two(&v), Some(34)); /// v.revoke(); diff --git a/rust/kernel/sync/seqlock.rs b/rust/kernel/sync/seqlock.rs index 5014e70621f695..436b5847353c5d 100644 --- a/rust/kernel/sync/seqlock.rs +++ b/rust/kernel/sync/seqlock.rs @@ -7,14 +7,24 @@ //! //! See . -use super::{Guard, Lock, LockClassKey, LockFactory, LockIniter, NeedsLockClass, ReadLock}; -use crate::{bindings, str::CStr, Opaque}; -use core::{cell::UnsafeCell, marker::PhantomPinned, ops::Deref, pin::Pin}; +use super::{Guard, Lock, LockClassKey, LockFactory, ReadLock}; +use crate::{ + bindings, + init::{self, PinInit}, + macros::pin_project, + pin_init, + str::CStr, + Opaque, +}; +use core::{cell::UnsafeCell, marker::PhantomPinned, ops::Deref}; /// Exposes sequential locks backed by the kernel's `seqcount_t`. /// /// The write-side critical section is protected by a lock implementing the [`LockFactory`] trait. /// +/// A [`SeqLock`] is created using the [initialization API][init]. You can call the `new` +/// function to create one. +/// /// # Examples /// /// ``` @@ -51,9 +61,14 @@ use core::{cell::UnsafeCell, marker::PhantomPinned, ops::Deref, pin::Pin}; /// guard.b.store(b + 1, Ordering::Relaxed); /// } /// ``` -pub struct SeqLock { +/// [init]: ../init/index.html +#[pin_project] +pub struct SeqLock { + #[pin] _p: PhantomPinned, + #[pin] count: Opaque, + #[pin] write_lock: L, } @@ -68,22 +83,39 @@ unsafe impl Sync for SeqLock where L::Inner: Sync {} impl SeqLock { /// Constructs a new instance of [`SeqLock`]. - /// - /// # Safety - /// - /// The caller must call [`SeqLock::init`] before using the seqlock. - pub unsafe fn new(data: L::Inner) -> Self + #[allow(clippy::new_ret_no_self)] + pub const fn new( + data: L::Inner, + name: &'static CStr, + key1: &'static LockClassKey, + key2: &'static LockClassKey, + ) -> impl PinInit where L: LockFactory = L>, L::Inner: Sized, + ::Error: From, { - Self { - _p: PhantomPinned, - count: Opaque::uninit(), - // SAFETY: `L::init_lock` is called from `SeqLock::init`, which is required to be - // called by the function's safety requirements. - write_lock: unsafe { L::new_lock(data) }, + fn init_count( + name: &'static CStr, + key2: &'static LockClassKey, + ) -> impl PinInit> { + let init = move |place: *mut Opaque| { + unsafe { + bindings::__seqcount_init( + Opaque::raw_get(place), + name.as_char_ptr(), + key2.get(), + ) + }; + Ok(()) + }; + unsafe { init::pin_init_from_closure(init) } } + pin_init!(Self { + _p: PhantomPinned, + count: init_count(name, key2), + write_lock: L::new_lock(data, name, key1), + }) } } @@ -129,21 +161,6 @@ impl SeqLock { } } -impl NeedsLockClass for SeqLock { - fn init( - mut self: Pin<&mut Self>, - name: &'static CStr, - key1: &'static LockClassKey, - key2: &'static LockClassKey, - ) { - // SAFETY: `write_lock` is pinned when `self` is. - let pinned = unsafe { self.as_mut().map_unchecked_mut(|s| &mut s.write_lock) }; - pinned.init_lock(name, key1); - // SAFETY: `key2` is valid as it has a static lifetime. - unsafe { bindings::__seqcount_init(self.count.get(), name.as_char_ptr(), key2.get()) }; - } -} - // SAFETY: The underlying lock ensures mutual exclusion. unsafe impl Lock for SeqLock { type Inner = L::Inner; diff --git a/rust/kernel/sync/smutex.rs b/rust/kernel/sync/smutex.rs index 4714008d65b7ae..359a57b8649454 100644 --- a/rust/kernel/sync/smutex.rs +++ b/rust/kernel/sync/smutex.rs @@ -46,10 +46,15 @@ //! When the waiter queue is non-empty, unlocking the mutex always results in the first waiter being //! popped form the queue and awakened. -use super::{mutex::EmptyGuardContext, Guard, Lock, LockClassKey, LockFactory, LockIniter}; -use crate::{bindings, str::CStr, Opaque}; +use super::{mutex::EmptyGuardContext, Guard, Lock, LockClassKey, LockFactory}; +use crate::{ + bindings, + init::{Init, PinInit}, + str::CStr, + Opaque, +}; +use core::cell::UnsafeCell; use core::sync::atomic::{AtomicUsize, Ordering}; -use core::{cell::UnsafeCell, pin::Pin}; /// The value that is OR'd into the [`Mutex::waiter_stack`] when the mutex is locked. const LOCKED: usize = 1; @@ -144,16 +149,39 @@ impl Mutex { } } -impl LockFactory for Mutex { - type LockedType = Mutex; +#[doc(hidden)] +pub struct MutexInit { + data: T, +} + +unsafe impl PinInit> for MutexInit { + unsafe fn __pinned_init( + self, + slot: *mut Mutex, + ) -> core::result::Result<(), core::convert::Infallible> { + unsafe { self.__init(slot) } + } +} - unsafe fn new_lock(data: U) -> Mutex { - Mutex::new(data) +unsafe impl Init> for MutexInit { + unsafe fn __init( + self, + slot: *mut Mutex, + ) -> core::result::Result<(), core::convert::Infallible> { + // SAFETY: pointer is valid + unsafe { slot.write(Mutex::new(self.data)) }; + Ok(()) } } -impl LockIniter for Mutex { - fn init_lock(self: Pin<&mut Self>, _name: &'static CStr, _key: &'static LockClassKey) {} +impl LockFactory for Mutex { + type LockedType = Mutex; + type Error = core::convert::Infallible; + type Init = MutexInit; + + fn new_lock(data: U, _: &'static CStr, _: &'static LockClassKey) -> Self::Init { + MutexInit { data } + } } // SAFETY: The mutex implementation ensures mutual exclusion. diff --git a/rust/kernel/sync/spinlock.rs b/rust/kernel/sync/spinlock.rs index b326af4196bbac..088991fbd02049 100644 --- a/rust/kernel/sync/spinlock.rs +++ b/rust/kernel/sync/spinlock.rs @@ -7,17 +7,23 @@ //! See . use super::{ - mutex::EmptyGuardContext, Guard, Lock, LockClassKey, LockFactory, LockInfo, LockIniter, - WriteLock, + mutex::EmptyGuardContext, Guard, Lock, LockClassKey, LockFactory, LockInfo, WriteLock, }; -use crate::{bindings, str::CStr, Opaque, True}; -use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin}; +use crate::{ + bindings, + init::{self, PinInit}, + macros::pin_project, + pin_init, + str::CStr, + Opaque, True, +}; +use core::{cell::UnsafeCell, marker::PhantomPinned}; /// Safely initialises a [`SpinLock`] with the given name, generating a new lock class. #[macro_export] -macro_rules! spinlock_init { - ($spinlock:expr, $name:literal) => { - $crate::init_with_lockdep!($spinlock, $name) +macro_rules! new_spinlock { + ($value:expr, $name:literal) => { + $crate::new_with_lockdep!($crate::sync::SpinLock<_>, $name, $value) }; } @@ -25,9 +31,8 @@ macro_rules! spinlock_init { /// one at a time is allowed to progress, the others will block (spinning) until the spinlock is /// unlocked, at which point another CPU will be allowed to make progress. /// -/// A [`SpinLock`] must first be initialised with a call to [`SpinLock::init_lock`] before it can be -/// used. The [`spinlock_init`] macro is provided to automatically assign a new lock class to a -/// spinlock instance. +/// A [`SpinLock`] is created using the [initialization API][init]. You can either call the `new` +/// function or use the [`new_spinlock!`] macro which automatically creates the [`LockClassKey`] for you. /// /// There are two ways to acquire the lock: /// - [`SpinLock::lock`], which doesn't manage interrupt state, so it should be used in only two @@ -41,7 +46,7 @@ macro_rules! spinlock_init { /// # Examples /// /// ``` -/// # use kernel::sync::SpinLock; +/// # use kernel::{new_spinlock, stack_init, sync::SpinLock}; /// # use core::pin::Pin; /// /// struct Example { @@ -64,10 +69,8 @@ macro_rules! spinlock_init { /// } /// /// // Initialises a spinlock. -/// // SAFETY: `spinlock_init` is called below. -/// let mut value = unsafe { SpinLock::new(Example { a: 1, b: 2 }) }; -/// // SAFETY: We don't move `value`. -/// kernel::spinlock_init!(unsafe { Pin::new_unchecked(&mut value) }, "value"); +/// stack_init!(let value = new_spinlock!(Example { a: 1, b: 2 }, "value")); +/// let value = value.unwrap(); /// /// // Calls the example functions. /// assert_eq!(value.lock().a, 1); @@ -78,11 +81,15 @@ macro_rules! spinlock_init { /// ``` /// /// [`spinlock_t`]: ../../../include/linux/spinlock.h +/// [init]: ../init/index.html +#[pin_project] pub struct SpinLock { + #[pin] spin_lock: Opaque, /// Spinlocks are architecture-defined. So we conservatively require them to be pinned in case /// some architecture uses self-references now or in the future. + #[pin] _pin: PhantomPinned, data: UnsafeCell, @@ -97,16 +104,45 @@ unsafe impl Sync for SpinLock {} impl SpinLock { /// Constructs a new spinlock. - /// - /// # Safety - /// - /// The caller must call [`SpinLock::init_lock`] before using the spinlock. - pub const unsafe fn new(t: T) -> Self { - Self { - spin_lock: Opaque::uninit(), - data: UnsafeCell::new(t), - _pin: PhantomPinned, + #[allow(clippy::new_ret_no_self)] + pub const fn new( + data: T, + name: &'static CStr, + key: &'static LockClassKey, + ) -> impl PinInit { + Init { data, name, key } + } +} + +#[doc(hidden)] +pub struct Init { + name: &'static CStr, + key: &'static LockClassKey, + data: T, +} + +unsafe impl PinInit> for Init { + unsafe fn __pinned_init( + self, + slot: *mut SpinLock, + ) -> core::result::Result<(), core::convert::Infallible> { + fn init_spinlock( + name: &'static CStr, + key: &'static LockClassKey, + ) -> impl PinInit> { + let init = move |slot: *mut Opaque| unsafe { + bindings::__spin_lock_init(Opaque::raw_get(slot), name.as_char_ptr(), key.get()); + Ok(()) + }; + unsafe { init::pin_init_from_closure(init) } } + let init = pin_init!(SpinLock { + spin_lock: init_spinlock(self.name, self.key), + data: UnsafeCell::new(self.data), + _pin: PhantomPinned, + }); + // SAFETY: we are inside of an initializer + unsafe { init.__pinned_init(slot) } } } @@ -132,16 +168,11 @@ impl SpinLock { impl LockFactory for SpinLock { type LockedType = SpinLock; + type Error = core::convert::Infallible; + type Init = Init; - unsafe fn new_lock(data: U) -> SpinLock { - // SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called. - unsafe { SpinLock::new(data) } - } -} - -impl LockIniter for SpinLock { - fn init_lock(self: Pin<&mut Self>, name: &'static CStr, key: &'static LockClassKey) { - unsafe { bindings::__spin_lock_init(self.spin_lock.get(), name.as_char_ptr(), key.get()) }; + fn new_lock(data: U, name: &'static CStr, key: &'static LockClassKey) -> Self::Init { + Init { data, name, key } } } @@ -196,9 +227,9 @@ unsafe impl Lock for SpinLock { /// Safely initialises a [`RawSpinLock`] with the given name, generating a new lock class. #[macro_export] -macro_rules! rawspinlock_init { - ($spinlock:expr, $name:literal) => { - $crate::init_with_lockdep!($spinlock, $name) +macro_rules! new_rawspinlock { + ($value:expr, $name:literal) => { + $crate::new_with_lockdep!($crate::sync::RawSpinLock<_>, $name, $value) }; } @@ -210,7 +241,7 @@ macro_rules! rawspinlock_init { /// # Examples /// /// ``` -/// # use kernel::sync::RawSpinLock; +/// # use kernel::{sync::RawSpinLock, stack_init, new_rawspinlock}; /// # use core::pin::Pin; /// /// struct Example { @@ -234,21 +265,22 @@ macro_rules! rawspinlock_init { /// /// // Initialises a raw spinlock and calls the example functions. /// fn spinlock_example() { -/// // SAFETY: `rawspinlock_init` is called below. -/// let mut value = unsafe { RawSpinLock::new(Example { a: 1, b: 2 }) }; -/// // SAFETY: We don't move `value`. -/// kernel::rawspinlock_init!(unsafe { Pin::new_unchecked(&mut value) }, "value"); +/// stack_init!(let value = new_rawspinlock!(Example { a: 1, b: 2 }, "value")); +/// let value = value.unwrap(); /// lock_example(&value); /// lock_irqdisable_example(&value); /// } /// ``` /// /// [`raw_spinlock_t`]: ../../../include/linux/spinlock.h +#[pin_project] pub struct RawSpinLock { + #[pin] spin_lock: Opaque, // Spinlocks are architecture-defined. So we conservatively require them to be pinned in case // some architecture uses self-references now or in the future. + #[pin] _pin: PhantomPinned, data: UnsafeCell, @@ -263,16 +295,49 @@ unsafe impl Sync for RawSpinLock {} impl RawSpinLock { /// Constructs a new raw spinlock. - /// - /// # Safety - /// - /// The caller must call [`RawSpinLock::init_lock`] before using the raw spinlock. - pub const unsafe fn new(t: T) -> Self { - Self { - spin_lock: Opaque::uninit(), - data: UnsafeCell::new(t), - _pin: PhantomPinned, + #[allow(clippy::new_ret_no_self)] + pub const fn new( + data: T, + name: &'static CStr, + key: &'static LockClassKey, + ) -> impl PinInit { + RInit { data, name, key } + } +} + +#[doc(hidden)] +pub struct RInit { + name: &'static CStr, + key: &'static LockClassKey, + data: T, +} + +unsafe impl PinInit> for RInit { + unsafe fn __pinned_init( + self, + slot: *mut RawSpinLock, + ) -> core::result::Result<(), core::convert::Infallible> { + fn init_spinlock( + name: &'static CStr, + key: &'static LockClassKey, + ) -> impl PinInit> { + let init = move |place: *mut Opaque| unsafe { + bindings::_raw_spin_lock_init( + Opaque::raw_get(place), + name.as_char_ptr(), + key.get(), + ); + Ok(()) + }; + unsafe { init::pin_init_from_closure(init) } } + let init = pin_init!(RawSpinLock { + spin_lock: init_spinlock(self.name, self.key), + data: UnsafeCell::new(self.data), + _pin: PhantomPinned, + }); + // SAFETY: we are inside of an initializer + unsafe { init.__pinned_init(slot) } } } @@ -298,18 +363,11 @@ impl RawSpinLock { impl LockFactory for RawSpinLock { type LockedType = RawSpinLock; + type Error = core::convert::Infallible; + type Init = RInit; - unsafe fn new_lock(data: U) -> RawSpinLock { - // SAFETY: The safety requirements of `new_lock` also require that `init_lock` be called. - unsafe { RawSpinLock::new(data) } - } -} - -impl LockIniter for RawSpinLock { - fn init_lock(self: Pin<&mut Self>, name: &'static CStr, key: &'static LockClassKey) { - unsafe { - bindings::_raw_spin_lock_init(self.spin_lock.get(), name.as_char_ptr(), key.get()) - }; + fn new_lock(data: U, name: &'static CStr, key: &'static LockClassKey) -> Self::Init { + RInit { data, name, key } } } diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 0ea84fec3ace0a..3216b7ae661985 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -202,7 +202,7 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream { /// # Examples /// /// ```rust,ignore -/// #[pin_data] +/// #[pin_project] /// struct A { /// #[pin] /// a: usize, diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs index 24766b2040bdee..8ec0ca280785ec 100644 --- a/samples/rust/rust_miscdev.rs +++ b/samples/rust/rust_miscdev.rs @@ -6,7 +6,8 @@ use kernel::prelude::*; use kernel::{ file::{self, File}, io_buffer::{IoBufferReader, IoBufferWriter}, - miscdev, + macros::pin_project, + miscdev, new_condvar, new_mutex, pin_init, sync::{Arc, ArcBorrow, CondVar, Mutex, UniqueArc}, }; @@ -24,29 +25,23 @@ struct SharedStateInner { token_count: usize, } +#[pin_project] struct SharedState { + #[pin] state_changed: CondVar, + #[pin] inner: Mutex, } impl SharedState { fn try_new() -> Result> { - let mut state = Pin::from(UniqueArc::try_new(Self { - // SAFETY: `condvar_init!` is called below. - state_changed: unsafe { CondVar::new() }, - // SAFETY: `mutex_init!` is called below. - inner: unsafe { Mutex::new(SharedStateInner { token_count: 0 }) }, - })?); - - // SAFETY: `state_changed` is pinned when `state` is. - let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.state_changed) }; - kernel::condvar_init!(pinned, "SharedState::state_changed"); - - // SAFETY: `inner` is pinned when `state` is. - let pinned = unsafe { state.as_mut().map_unchecked_mut(|s| &mut s.inner) }; - kernel::mutex_init!(pinned, "SharedState::inner"); - - Ok(state.into()) + Ok( + UniqueArc::pin_init::(pin_init!(Self { + state_changed: new_condvar!("SharedState::state_changed"), + inner: new_mutex!(SharedStateInner { token_count: 0 }, "SharedState::inner"), + }))? + .into(), + ) } } diff --git a/samples/rust/rust_semaphore.rs b/samples/rust/rust_semaphore.rs index 37949461403259..390bb825c99988 100644 --- a/samples/rust/rust_semaphore.rs +++ b/samples/rust/rust_semaphore.rs @@ -15,11 +15,11 @@ use core::sync::atomic::{AtomicU64, Ordering}; use kernel::{ - condvar_init, file::{self, File, IoctlCommand, IoctlHandler}, io_buffer::{IoBufferReader, IoBufferWriter}, + macros::pin_project, miscdev::Registration, - mutex_init, + new_condvar, new_mutex, pin_init, prelude::*, sync::{Arc, CondVar, Mutex, UniqueArc}, user_ptr::{UserSlicePtrReader, UserSlicePtrWriter}, @@ -38,8 +38,11 @@ struct SemaphoreInner { max_seen: usize, } +#[pin_project] struct Semaphore { + #[pin] changed: CondVar, + #[pin] inner: Mutex, } @@ -109,26 +112,16 @@ impl kernel::Module for RustSemaphore { fn init(name: &'static CStr, _module: &'static ThisModule) -> Result { pr_info!("Rust semaphore sample (init)\n"); - let mut sema = Pin::from(UniqueArc::try_new(Semaphore { - // SAFETY: `condvar_init!` is called below. - changed: unsafe { CondVar::new() }, - - // SAFETY: `mutex_init!` is called below. - inner: unsafe { - Mutex::new(SemaphoreInner { + let sema = UniqueArc::pin_init::(pin_init!(Semaphore { + changed: new_condvar!("Semaphore::changed"), + inner: new_mutex!( + SemaphoreInner { count: 0, max_seen: 0, - }) - }, - })?); - - // SAFETY: `changed` is pinned when `sema` is. - let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.changed) }; - condvar_init!(pinned, "Semaphore::changed"); - - // SAFETY: `inner` is pinned when `sema` is. - let pinned = unsafe { sema.as_mut().map_unchecked_mut(|s| &mut s.inner) }; - mutex_init!(pinned, "Semaphore::inner"); + }, + "Semaphore::inner" + ), + }))?; Ok(Self { _dev: Registration::new_pinned(fmt!("{name}"), sema.into())?, diff --git a/samples/rust/rust_sync.rs b/samples/rust/rust_sync.rs index 2e0714fcc3d6c9..cae5ef3fbcfa47 100644 --- a/samples/rust/rust_sync.rs +++ b/samples/rust/rust_sync.rs @@ -4,8 +4,8 @@ use kernel::prelude::*; use kernel::{ - condvar_init, mutex_init, spinlock_init, - sync::{CondVar, Mutex, SpinLock}, + new_condvar, new_mutex, new_spinlock, + sync::{CondVar, Mutex}, }; module! { @@ -29,16 +29,11 @@ impl kernel::Module for RustSync { // Test mutexes. { - // SAFETY: `init` is called below. - let mut data = Pin::from(Box::try_new(unsafe { Mutex::new(0) })?); - mutex_init!(data.as_mut(), "RustSync::init::data1"); + let data = Box::pin_init(new_mutex!(0, "RustSync::init::data1"))?; *data.lock() = 10; pr_info!("Value: {}\n", *data.lock()); - // SAFETY: `init` is called below. - let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?); - condvar_init!(cv.as_mut(), "RustSync::init::cv1"); - + let cv = Box::pin_init(new_condvar!("RustSync::init::cv1"))?; { let mut guard = data.lock(); while *guard != 10 { @@ -62,15 +57,11 @@ impl kernel::Module for RustSync { // Test spinlocks. { - // SAFETY: `init` is called below. - let mut data = Pin::from(Box::try_new(unsafe { SpinLock::new(0) })?); - spinlock_init!(data.as_mut(), "RustSync::init::data2"); + let data = Box::pin_init(new_spinlock!(0, "RustSync::init::data2"))?; *data.lock() = 10; pr_info!("Value: {}\n", *data.lock()); - // SAFETY: `init` is called below. - let mut cv = Pin::from(Box::try_new(unsafe { CondVar::new() })?); - condvar_init!(cv.as_mut(), "RustSync::init::cv2"); + let cv = Box::pin_init(new_condvar!("RustSync::init::cv2"))?; { let mut guard = data.lock(); while *guard != 10 { From 48e56dd2dac2b0c483e69cd6897ec6d2ae048c93 Mon Sep 17 00:00:00 2001 From: y86-dev Date: Thu, 20 Oct 2022 12:16:59 +0200 Subject: [PATCH 06/11] Added `try[_pin]_init!` and removed turbofish --- drivers/android/context.rs | 2 +- drivers/android/process.rs | 2 +- drivers/android/thread.rs | 2 +- drivers/android/transaction.rs | 4 +- rust/kernel/device.rs | 2 +- rust/kernel/init.rs | 410 +++++++++++++++++++++-- rust/kernel/kasync/executor/workqueue.rs | 2 +- rust/kernel/sync/revocable.rs | 7 +- rust/kernel/sync/seqlock.rs | 7 +- samples/rust/rust_miscdev.rs | 13 +- samples/rust/rust_semaphore.rs | 2 +- 11 files changed, 410 insertions(+), 43 deletions(-) diff --git a/drivers/android/context.rs b/drivers/android/context.rs index e4f22ede38c6a1..9be1f5db900544 100644 --- a/drivers/android/context.rs +++ b/drivers/android/context.rs @@ -29,7 +29,7 @@ unsafe impl Sync for Context {} impl Context { pub(crate) fn new() -> Result> { - Arc::pin_init::(pin_init!(Self { + Arc::pin_init(pin_init!(Self { manager: new_mutex!( Manager { node: None, diff --git a/drivers/android/process.rs b/drivers/android/process.rs index e677299e36c9f7..cea1d82c5bd464 100644 --- a/drivers/android/process.rs +++ b/drivers/android/process.rs @@ -271,7 +271,7 @@ unsafe impl Sync for Process {} impl Process { fn new(ctx: Arc, cred: ARef) -> Result> { - Arc::pin_init::(pin_init!(Self { + Arc::pin_init(pin_init!(Self { ctx, cred, task: ARef::from(Task::current().group_leader()), diff --git a/drivers/android/thread.rs b/drivers/android/thread.rs index f5105458c14e45..a6725d14829934 100644 --- a/drivers/android/thread.rs +++ b/drivers/android/thread.rs @@ -245,7 +245,7 @@ impl Thread { pub(crate) fn new(id: i32, process: Arc) -> Result> { let return_work = Arc::try_new(ThreadError::new(InnerThread::set_return_work))?; let reply_work = Arc::try_new(ThreadError::new(InnerThread::set_reply_work))?; - let thread = Arc::pin_init::(pin_init!(Self { + let thread = Arc::pin_init(pin_init!(Self { id, process, inner: new_spinlock!(InnerThread::new(), "Thread::inner"), diff --git a/drivers/android/transaction.rs b/drivers/android/transaction.rs index 39f24bad147f83..7f4c66008368e9 100644 --- a/drivers/android/transaction.rs +++ b/drivers/android/transaction.rs @@ -59,7 +59,7 @@ impl Transaction { let data_address = alloc.ptr; let file_list = alloc.take_file_list(); alloc.keep_alive(); - let tr = UniqueArc::pin_init::(pin_init!(Self { + let tr = UniqueArc::pin_init(pin_init!(Self { inner: new_spinlock!(TransactionInner { file_list }, "Transaction::inner"), node_ref: Some(node_ref), stack_next, @@ -86,7 +86,7 @@ impl Transaction { let data_address = alloc.ptr; let file_list = alloc.take_file_list(); alloc.keep_alive(); - let tr = UniqueArc::pin_init::(pin_init!(Self { + let tr = UniqueArc::pin_init(pin_init!(Self { inner: new_spinlock!(TransactionInner { file_list }, "Transaction::inner"), node_ref: None, stack_next: None, diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 388f742eca0858..6ae7e634444640 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -283,7 +283,7 @@ impl Data { name: &'static CStr, key1: &'static LockClassKey, ) -> Result>> { - UniqueArc::pin_init::(pin_init!(Self { + UniqueArc::pin_init(pin_init!(Self { registrations: RevocableMutex::new(registrations, name, key1), resources: Revocable::new(resources), general, diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 6a8d9d2e75e37e..3fcb5a93d6de4c 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -40,7 +40,6 @@ //! a: new_mutex!(42, "Foo::a"), //! b: 24, //! }); -//! # let foo: Result>> = Box::pin_init::(foo); //! ``` //! //! `foo` now is of the type `impl`[`PinInit`]. We can now use any smart pointer that we like @@ -60,7 +59,7 @@ //! # a: new_mutex!(42, "Foo::a"), //! # b: 24, //! # }); -//! let foo: Result>> = Box::pin_init::(foo); +//! let foo: Result>> = Box::pin_init(foo); //! ``` //! //! ## Using a function/macro that returns an initializer @@ -76,7 +75,7 @@ //! To declare an init macro/function you just return an `impl`[`PinInit`]: //! ```rust //! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] -//! # use kernel::{sync::Mutex, prelude::*, new_mutex, init::PinInit}; +//! # use kernel::{sync::Mutex, prelude::*, new_mutex, init::PinInit, try_pin_init}; //! #[pin_project] //! struct DriverData { //! #[pin] @@ -86,7 +85,7 @@ //! //! impl DriverData { //! fn new() -> impl PinInit { -//! pin_init!(Self { +//! try_pin_init!(Self { //! status: new_mutex!(0, "DriverData::status"), //! buffer: Box::init(kernel::init::zeroed())?, //! }) @@ -143,13 +142,14 @@ mod pinned_drop; /// /// let a = new_mutex!(42, "Foo::a"); /// -/// stack_init!(let foo = pin_init!(Foo { +/// stack_init!(let foo =? pin_init!(Foo { /// a, /// b: Bar { /// x: 64, /// }, /// })); -/// let foo: Result> = foo; +/// let foo: Pin<&mut Foo> = foo; +/// # Ok::<(), core::convert::Infallible>(()) /// ``` #[macro_export] macro_rules! stack_init { @@ -165,7 +165,10 @@ macro_rules! stack_init { }; } -/// Construct an in-place initializer for structs. +/// Construct an in-place, pinned initializer for structs. +/// +/// This macro defaults the error to [`Infallible`]. If you need [`Error`], then use +/// [`try_pin_init!`]. /// /// The syntax is identical to a normal struct initializer: /// @@ -305,18 +308,205 @@ macro_rules! stack_init { /// } /// } /// ``` +/// +/// [`try_pin_init!`]: kernel::try_pin_init #[macro_export] macro_rules! pin_init { ($(&$this:ident in)? $t:ident $(<$($generics:ty),* $(,)?>)? { $($field:ident $(: $val:expr)?),* $(,)? }) => { - $crate::pin_init!(@this($($this)?), @type_name($t $(<$($generics),*>)?), @typ($t $(<$($generics),*>)?), @fields($($field $(: $val)?),*)) + $crate::try_pin_init!( + @this($($this)?), + @type_name($t), + @typ($t $(<$($generics),*>)?), + @fields($($field $(: $val)?),*), + @error(::core::convert::Infallible), + ) + }; +} + +/// Construct an in-place, pinned initializer for structs. +/// +/// This macro defaults the error to [`Error`]. If you need [`Infallible`], then use +/// [`pin_init!`]. If you want to specify a custom error, append `? ` after the struct +/// initializer. +/// +/// The syntax is identical to a normal struct initializer: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use core::pin::Pin; +/// #[pin_project] +/// struct Foo { +/// a: usize, +/// b: Bar, +/// } +/// +/// #[pin_project] +/// struct Bar { +/// x: u32, +/// } +/// +/// # fn demo() -> impl PinInit { +/// let a = 42; +/// +/// let initializer = pin_init!(Foo { +/// a, +/// b: Bar { +/// x: 64, +/// }, +/// }); +/// # initializer } +/// # Box::pin_init(demo()).unwrap(); +/// ``` +/// Arbitrary rust expressions can be used to set the value of a variable. +/// +/// # Init-functions +/// +/// When working with this library it is often desired to let others construct your types without +/// giving access to all fields. This is where you would normally write a plain function `new` +/// that would return a new instance of your type. With this library that is also possible, however +/// there are a few extra things to keep in mind. +/// +/// To create an initializer function, simple declare it like this: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, prelude::*, init::*}; +/// # use core::pin::Pin; +/// # #[pin_project] +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # #[pin_project] +/// # struct Bar { +/// # x: u32, +/// # } +/// +/// impl Foo { +/// fn new() -> impl PinInit { +/// pin_init!(Self { +/// a: 42, +/// b: Bar { +/// x: 64, +/// }, +/// }) +/// } +/// } +/// ``` +/// +/// Users of `Foo` can now create it like this: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use core::pin::Pin; +/// # #[pin_project] +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # #[pin_project] +/// # struct Bar { +/// # x: u32, +/// # } +/// # impl Foo { +/// # fn new() -> impl PinInit { +/// # pin_init!(Self { +/// # a: 42, +/// # b: Bar { +/// # x: 64, +/// # }, +/// # }) +/// # } +/// # } +/// let foo = Box::pin_init(Foo::new()); +/// ``` +/// +/// They can also easily embed it into their own `struct`s: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use core::pin::Pin; +/// # #[pin_project] +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # #[pin_project] +/// # struct Bar { +/// # x: u32, +/// # } +/// # impl Foo { +/// # fn new() -> impl PinInit { +/// # pin_init!(Self { +/// # a: 42, +/// # b: Bar { +/// # x: 64, +/// # }, +/// # }) +/// # } +/// # } +/// #[pin_project] +/// struct FooContainer { +/// #[pin] +/// foo1: Foo, +/// #[pin] +/// foo2: Foo, +/// other: u32, +/// } +/// +/// impl FooContainer { +/// fn new(other: u32) -> impl PinInit { +/// pin_init!(Self { +/// foo1: Foo::new(), +/// foo2: Foo::new(), +/// other, +/// }) +/// } +/// } +/// ``` + +#[macro_export] +macro_rules! try_pin_init { + ($(&$this:ident in)? $t:ident $(<$($generics:ty),* $(,)?>)? { + $($field:ident $(: $val:expr)?),* + $(,)? + }) => { + $crate::try_pin_init!( + @this($($this)?), + @type_name($t), + @typ($t $(<$($generics),*>)?), + @fields($($field $(: $val)?),*), + @error($crate::error::Error), + ) }; - (@this($($this:ident)?), @type_name($t:ident $(<$($generics:ty),*>)?), @typ($ty:ty), @fields($($field:ident $(: $val:expr)?),*)) => {{ + ($(&$this:ident in)? $t:ident $(<$($generics:ty),* $(,)?>)? { + $($field:ident $(: $val:expr)?),* + $(,)? + }? $err:ty) => { + $crate::try_pin_init!( + @this($($this)?), + @type_name($t), + @typ($t $(<$($generics),*>)?), + @fields($($field $(: $val)?),*), + @error($err), + ) + }; + ( + @this($($this:ident)?), + @type_name($t:ident), + @typ($ty:ty), + @fields($($field:ident $(: $val:expr)?),*), + @error($err:ty), + ) => {{ // we do not want to allow arbitrary returns struct __InitOk; - let init = move |slot: *mut $ty| -> ::core::result::Result<__InitOk, _> { + let init = move |slot: *mut $ty| -> ::core::result::Result<__InitOk, $err> { { // shadow the structure so it cannot be used to return early struct __InitOk; @@ -340,7 +530,7 @@ macro_rules! pin_init { )* #[allow(unreachable_code, clippy::diverging_sub_expression)] if false { - let _: $t $(<$($generics),*>)? = $t { + let _: $ty = $t { $($field: ::core::todo!()),* }; } @@ -351,16 +541,19 @@ macro_rules! pin_init { } Ok(__InitOk) }; - let init = move |slot: *mut $ty| -> ::core::result::Result<(), _> { + let init = move |slot: *mut $ty| -> ::core::result::Result<(), $err> { init(slot).map(|__InitOk| ()) }; - let init = unsafe { $crate::init::pin_init_from_closure::<$t $(<$($generics),*>)?, _>(init) }; + let init = unsafe { $crate::init::pin_init_from_closure::<$ty, $err>(init) }; init }} } /// Construct an in-place initializer for structs. /// +/// This macro defaults the error to [`Infallible`]. If you need [`Error`], then use +/// [`try_init!`]. +/// /// The syntax is identical to a normal struct initializer: /// /// ```rust @@ -489,15 +682,194 @@ macro_rules! pin_init { /// } /// } /// ``` +/// +/// [`try_init!`]: kernel::try_init #[macro_export] macro_rules! init { - ($t:ident $(<$($generics:ty),* $(,)?>)? { + ($(&$this:ident in)? $t:ident $(<$($generics:ty),* $(,)?>)? { + $($field:ident $(: $val:expr)?),* + $(,)? + }) => { + $crate::try_init!( + @this($($this)?), + @type_name($t), + @typ($t $(<$($generics),*>)?), + @fields($($field $(: $val)?),*), + @error(::core::convert::Infallible), + ) + } +} + +/// Construct an in-place initializer for structs. +/// +/// This macro defaults the error to [`Error`]. If you need [`Infallible`], then use +/// [`init!`]. If you want to specify a custom error, append `? ` after the struct +/// initializer. +/// +/// The syntax is identical to a normal struct initializer: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, init::*}; +/// # use core::pin::Pin; +/// struct Foo { +/// a: usize, +/// b: Bar, +/// } +/// +/// struct Bar { +/// x: u32, +/// } +/// +/// # fn demo() -> impl Init { +/// let a = 42; +/// +/// let initializer = init!(Foo { +/// a, +/// b: Bar { +/// x: 64, +/// }, +/// }); +/// # initializer } +/// # Box::init(demo()).unwrap(); +/// ``` +/// +/// Arbitrary rust expressions can be used to set the value of a variable. +/// +/// # Init-functions +/// +/// When working with this library it is often desired to let others construct your types without +/// giving access to all fields. This is where you would normally write a plain function `new` +/// that would return a new instance of your type. With this library that is also possible, however +/// there are a few extra things to keep in mind. +/// +/// To create an initializer function, simple declare it like this: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, init::*}; +/// # use core::pin::Pin; +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # struct Bar { +/// # x: u32, +/// # } +/// +/// impl Foo { +/// fn new() -> impl Init { +/// init!(Self { +/// a: 42, +/// b: Bar { +/// x: 64, +/// }, +/// }) +/// } +/// } +/// ``` +/// +/// Users of `Foo` can now create it like this: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, init::*}; +/// # use core::pin::Pin; +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # struct Bar { +/// # x: u32, +/// # } +/// # impl Foo { +/// # fn new() -> impl Init { +/// # init!(Self { +/// # a: 42, +/// # b: Bar { +/// # x: 64, +/// # }, +/// # }) +/// # } +/// # } +/// let foo = Box::init(Foo::new()); +/// ``` +/// +/// They can also easily embed it into their own `struct`s: +/// +/// ```rust +/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] +/// # use kernel::{init, pin_init, init::*}; +/// # use core::pin::Pin; +/// # struct Foo { +/// # a: usize, +/// # b: Bar, +/// # } +/// # struct Bar { +/// # x: u32, +/// # } +/// # impl Foo { +/// # fn new() -> impl Init { +/// # init!(Self { +/// # a: 42, +/// # b: Bar { +/// # x: 64, +/// # }, +/// # }) +/// # } +/// # } +/// struct FooContainer { +/// foo1: Foo, +/// foo2: Foo, +/// other: u32, +/// } +/// +/// impl FooContainer { +/// fn new(other: u32) -> impl Init { +/// init!(Self { +/// foo1: Foo::new(), +/// foo2: Foo::new(), +/// other, +/// }) +/// } +/// } +/// ``` +#[macro_export] +macro_rules! try_init { + ($(&$this:ident in)? $t:ident $(<$($generics:ty),* $(,)?>)? { $($field:ident $(: $val:expr)?),* $(,)? - }) => {{ + }) => { + $crate::try_init!( + @this($($this)?), + @type_name($t), + @typ($t $(<$($generics),*>)?), + @fields($($field $(: $val)?),*), + @error($crate::error::Error), + ) + }; + ($(&$this:ident in)? $t:ident $(<$($generics:ty),* $(,)?>)? { + $($field:ident $(: $val:expr)?),* + $(,)? + }? $err:ty) => { + $crate::try_init!( + @this($($this)?), + @type_name($t), + @typ($t $(<$($generics),*>)?), + @fields($($field $(: $val)?),*), + @error($err), + ) + }; + ( + @this($($this:ident)?), + @type_name($t:ident), + @typ($ty:ty), + @fields($($field:ident $(: $val:expr)?),*), + @error($err:ty), + ) => {{ // we do not want to allow arbitrary returns struct __InitOk; - let init = move |slot: *mut $t $(<$($generics),*>)?| -> ::core::result::Result<__InitOk, _> { + let init = move |slot: *mut $ty| -> ::core::result::Result<__InitOk, $err> { { // shadow the structure so it cannot be used to return early struct __InitOk; @@ -515,7 +887,7 @@ macro_rules! init { )* #[allow(unreachable_code, clippy::diverging_sub_expression)] if false { - let _: $t $(<$($generics),*>)? = $t { + let _: $ty = $t { $($field: ::core::todo!()),* }; } @@ -526,10 +898,10 @@ macro_rules! init { } Ok(__InitOk) }; - let init = move |slot: *mut $t $(<$($generics),*>)?| -> ::core::result::Result<(), _> { + let init = move |slot: *mut $ty| -> ::core::result::Result<(), $err> { init(slot).map(|__InitOk| ()) }; - let init = unsafe { $crate::init::init_from_closure::<$t $(<$($generics),*>)?, _>(init) }; + let init = unsafe { $crate::init::init_from_closure::<$ty, $err>(init) }; init }} } diff --git a/rust/kernel/kasync/executor/workqueue.rs b/rust/kernel/kasync/executor/workqueue.rs index 6533e53e8b9f84..e86d8d7d50d0bd 100644 --- a/rust/kernel/kasync/executor/workqueue.rs +++ b/rust/kernel/kasync/executor/workqueue.rs @@ -223,7 +223,7 @@ impl Executor { /// It uses the given work queue to run its tasks. fn new_internal(queue: Either) -> Result> { Ok(AutoStopHandle::new( - UniqueArc::pin_init::(pin_init!(Self { + UniqueArc::pin_init(pin_init!(Self { inner: new_mutex!( ExecutorInner { stopped: false, diff --git a/rust/kernel/sync/revocable.rs b/rust/kernel/sync/revocable.rs index b27839c8807ecb..48739dfd062778 100644 --- a/rust/kernel/sync/revocable.rs +++ b/rust/kernel/sync/revocable.rs @@ -5,10 +5,9 @@ use crate::{ init::PinInit, macros::pin_project, - pin_init, str::CStr, sync::{Guard, Lock, LockClassKey, LockFactory, LockInfo, ReadLock, WriteLock}, - True, + try_pin_init, True, }; use core::{ mem::MaybeUninit, @@ -124,9 +123,9 @@ impl Revocable { name: &'static CStr, key: &'static LockClassKey, ) -> impl PinInit { - pin_init!(Self { + try_pin_init!(Self { inner: F::new_lock(Inner::new(data), name, key), - }) + }? F::Error) } } diff --git a/rust/kernel/sync/seqlock.rs b/rust/kernel/sync/seqlock.rs index 436b5847353c5d..e85c9ad7a4bc2c 100644 --- a/rust/kernel/sync/seqlock.rs +++ b/rust/kernel/sync/seqlock.rs @@ -12,9 +12,8 @@ use crate::{ bindings, init::{self, PinInit}, macros::pin_project, - pin_init, str::CStr, - Opaque, + try_pin_init, Opaque, }; use core::{cell::UnsafeCell, marker::PhantomPinned, ops::Deref}; @@ -111,11 +110,11 @@ impl SeqLock { }; unsafe { init::pin_init_from_closure(init) } } - pin_init!(Self { + try_pin_init!(Self { _p: PhantomPinned, count: init_count(name, key2), write_lock: L::new_lock(data, name, key1), - }) + }? L::Error) } } diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs index 8ec0ca280785ec..f8ade71f8484b2 100644 --- a/samples/rust/rust_miscdev.rs +++ b/samples/rust/rust_miscdev.rs @@ -8,7 +8,7 @@ use kernel::{ io_buffer::{IoBufferReader, IoBufferWriter}, macros::pin_project, miscdev, new_condvar, new_mutex, pin_init, - sync::{Arc, ArcBorrow, CondVar, Mutex, UniqueArc}, + sync::{Arc, ArcBorrow, CondVar, Mutex}, }; module! { @@ -35,13 +35,10 @@ struct SharedState { impl SharedState { fn try_new() -> Result> { - Ok( - UniqueArc::pin_init::(pin_init!(Self { - state_changed: new_condvar!("SharedState::state_changed"), - inner: new_mutex!(SharedStateInner { token_count: 0 }, "SharedState::inner"), - }))? - .into(), - ) + Arc::pin_init(pin_init!(Self { + state_changed: new_condvar!("SharedState::state_changed"), + inner: new_mutex!(SharedStateInner { token_count: 0 }, "SharedState::inner"), + })) } } diff --git a/samples/rust/rust_semaphore.rs b/samples/rust/rust_semaphore.rs index 390bb825c99988..21e1e1428d1a69 100644 --- a/samples/rust/rust_semaphore.rs +++ b/samples/rust/rust_semaphore.rs @@ -112,7 +112,7 @@ impl kernel::Module for RustSemaphore { fn init(name: &'static CStr, _module: &'static ThisModule) -> Result { pr_info!("Rust semaphore sample (init)\n"); - let sema = UniqueArc::pin_init::(pin_init!(Semaphore { + let sema = UniqueArc::pin_init(pin_init!(Semaphore { changed: new_condvar!("Semaphore::changed"), inner: new_mutex!( SemaphoreInner { From 7a8d1911d8c3aa84b0a6fc826f6f1c3895893819 Mon Sep 17 00:00:00 2001 From: y86-dev Date: Sat, 22 Oct 2022 12:12:31 +0200 Subject: [PATCH 07/11] Safety comments and using Vec::splice --- rust/kernel/sync.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index e8100d2892b22e..0d50950a2a5b4c 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -134,7 +134,11 @@ pub struct StaticInit { inner: MaybeUninit>, } +// SAFETY: Need to implement Send/Sync, because of the `UnsafeCell`. One can only get a `&T` from a +// `StaticInit`. Except when calling `init` which is unsafe and only done before other code can +// access the `StaticInit`. unsafe impl Sync for StaticInit {} +// SAFETY: same as above. unsafe impl Send for StaticInit {} impl StaticInit { @@ -142,7 +146,7 @@ impl StaticInit { /// /// # Safety /// - /// The caller calls `Self::init` exactly once before using this value. + /// The caller calls `Self::init` exactly once before using this value in any way. pub const unsafe fn uninit() -> Self { Self { inner: MaybeUninit::uninit(), @@ -154,11 +158,13 @@ impl StaticInit { /// # Safety /// /// The caller calls this function exactly once and before any other function (even implicitly - /// derefing) of `self` is called. + /// derefing) of `self` is called. `self` stays pinned indefinetly. pub unsafe fn init(&self, init: impl PinInit) where E: Into, { + // SAFETY: This function has unique access to `self` because of the unsafety contract. + // `self` is also pinned indefinetly and `inner` is structurally pinned. unsafe { let ptr = UnsafeCell::raw_get(self.inner.as_ptr()); match init.__pinned_init(ptr).map_err(|e| e.into()) { @@ -172,6 +178,7 @@ impl StaticInit { impl core::ops::Deref for StaticInit { type Target = T; fn deref(&self) -> &Self::Target { + // SAFETY: self.inner has been initialized because of the contract of `Self::uninit()` unsafe { &*self.inner.assume_init_ref().get() } } } From 1c7e882d9ccd7f75f17bda2952926c75356b27eb Mon Sep 17 00:00:00 2001 From: y86-dev Date: Sat, 22 Oct 2022 16:38:46 +0200 Subject: [PATCH 08/11] Fixed stuff forgotten last commit and fixed typos --- drivers/android/process.rs | 2 +- rust/kernel/sync.rs | 6 +++--- rust/macros/pinned_drop.rs | 26 ++++++++++++++------------ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/android/process.rs b/drivers/android/process.rs index cea1d82c5bd464..37c4eeecf53fe7 100644 --- a/drivers/android/process.rs +++ b/drivers/android/process.rs @@ -712,7 +712,7 @@ impl Process { self.clone(), cookie, )) - .map_err(|(i, _)| i)?, + .unwrap_or_else(|(err, _)| match err {}), ); info.death = Some(death.clone()); diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs index 0d50950a2a5b4c..0620f738f81e02 100644 --- a/rust/kernel/sync.rs +++ b/rust/kernel/sync.rs @@ -158,13 +158,13 @@ impl StaticInit { /// # Safety /// /// The caller calls this function exactly once and before any other function (even implicitly - /// derefing) of `self` is called. `self` stays pinned indefinetly. - pub unsafe fn init(&self, init: impl PinInit) + /// derefing) of `self` is called. `self` stays pinned indefinitely. + pub unsafe fn init(&'static self, init: impl PinInit) where E: Into, { // SAFETY: This function has unique access to `self` because of the unsafety contract. - // `self` is also pinned indefinetly and `inner` is structurally pinned. + // `self` is also pinned indefinitely and `inner` is structurally pinned. unsafe { let ptr = UnsafeCell::raw_get(self.inner.as_ptr()); match init.__pinned_init(ptr).map_err(|e| e.into()) { diff --git a/rust/macros/pinned_drop.rs b/rust/macros/pinned_drop.rs index 37fbe541b12c4d..4d972dfc1d8c63 100644 --- a/rust/macros/pinned_drop.rs +++ b/rust/macros/pinned_drop.rs @@ -32,19 +32,21 @@ pub(crate) fn pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream } } let idx = pinned_drop_idx.unwrap(); - //inserting `::kernel::init::` in reverse order - toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Alone))); - toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Joint))); - toks.insert(idx, TokenTree::Ident(Ident::new("init", Span::call_site()))); - toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Alone))); - toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Joint))); - toks.insert( - idx, - TokenTree::Ident(Ident::new("kernel", Span::call_site())), + // fully qualify the `PinnedDrop`. + toks.splice( + idx..idx, + vec![ + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Ident(Ident::new("kernel", Span::call_site())), + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Ident(Ident::new("init", Span::call_site())), + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + ], ); - toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Alone))); - toks.insert(idx, TokenTree::Punct(Punct::new(':', Spacing::Joint))); - // take the {} body + // take the {} body. if let Some(TokenTree::Group(last)) = toks.pop() { TokenStream::from_iter(vec![ TokenTree::Punct(Punct::new(':', Spacing::Joint)), From 901221e59274aeb9336d05dd3c61a9ea6cccd1e5 Mon Sep 17 00:00:00 2001 From: y86-dev Date: Tue, 1 Nov 2022 22:08:14 +0100 Subject: [PATCH 09/11] Implemented review suggestions --- rust/kernel/sync/arc.rs | 34 +++++++------ rust/macros/pin_project.rs | 97 ++++++++++++++++++-------------------- rust/macros/pinned_drop.rs | 14 +----- 3 files changed, 62 insertions(+), 83 deletions(-) diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 4516c2bf526d40..30623d36f61f27 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -32,7 +32,7 @@ use core::{ mem::{ManuallyDrop, MaybeUninit}, ops::{Deref, DerefMut}, pin::Pin, - ptr::{self, addr_of_mut, NonNull}, + ptr::{self, NonNull}, }; /// A reference-counted pointer to an instance of `T`. @@ -49,9 +49,12 @@ pub struct Arc { _p: PhantomData>, } +#[pin_project] #[repr(C)] struct ArcInner { + #[pin] refcount: Opaque, + #[pin] data: T, } @@ -483,21 +486,17 @@ impl UniqueArc { let inner = NonNull::new(unsafe { alloc(layout) }) .ok_or(ENOMEM)? .cast::>>(); - // TODO do this using `pinned-init` - - // INVARIANT: The refcount is initialised to a non-zero value. - let refcount = Opaque::new(new_refcount()); - // SAFETY: `inner` is writable and properly aligned. - unsafe { addr_of_mut!((*inner.as_ptr()).refcount).write(refcount) }; - // assert that there are only two fields: refcount and data (done in a closure to avoid - // overflowing the stack in debug mode with a big `T`) - #[allow(unreachable_code, clippy::diverging_sub_expression)] - let _check = || { - let _check: ArcInner> = ArcInner { - refcount: todo!(), - data: todo!(), - }; - }; + let init = pin_init!(ArcInner> { + // INVARIANT: The refcount is initialised to a non-zero value. + refcount: Opaque::new(new_refcount()), + data: init::uninit(), + }); + // SAFETY: the pointer is valid, as we just allocated it. It will also stay pinned (type + // invariant). + match unsafe { init.__pinned_init(inner.as_ptr()) } { + Ok(()) => {} + Err(e) => match e {}, + } // SAFETY: We just created `inner` with a reference count of 1, which is owned by the new // `Arc` object. @@ -517,11 +516,10 @@ impl UniqueArc> { } /// Initialize the value after creating the `UniqueArc`. - #[allow(clippy::type_complexity)] pub fn pin_init_now( mut self, init: impl PinInit, - ) -> core::result::Result>, (E, UniqueArc>)> { + ) -> core::result::Result>, (E, Self)> { unsafe { match init.__pinned_init(self.deref_mut().as_mut_ptr()) { Ok(()) => Ok(Pin::from(self.assume_init())), diff --git a/rust/macros/pin_project.rs b/rust/macros/pin_project.rs index 5a4507fcd4d416..8021d81a3f7002 100644 --- a/rust/macros/pin_project.rs +++ b/rust/macros/pin_project.rs @@ -42,7 +42,6 @@ pub(crate) fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream TokenTree::Punct(p) if p.as_char() == ',' => at_start = true, TokenTree::Punct(p) if p.as_char() == '\'' && at_start => { ty_generics.push(tt.clone()); - ty_generics.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); } _ => {} } @@ -57,55 +56,49 @@ pub(crate) fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream } rest.extend(toks); let last = rest.pop(); - TokenStream::from_iter(vec![ - TokenTree::Punct(Punct::new(':', Spacing::Joint)), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - TokenTree::Ident(Ident::new("kernel", Span::call_site())), - TokenTree::Punct(Punct::new(':', Spacing::Joint)), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - TokenTree::Ident(Ident::new("pin_project", Span::call_site())), - TokenTree::Punct(Punct::new('!', Spacing::Alone)), - TokenTree::Group(Group::new( - Delimiter::Brace, - TokenStream::from_iter(vec![ - TokenTree::Ident(Ident::new("parse_input", Span::call_site())), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - TokenTree::Punct(Punct::new('@', Spacing::Alone)), - TokenTree::Ident(Ident::new("args", Span::call_site())), - TokenTree::Group(Group::new( - Delimiter::Parenthesis, - TokenStream::from_iter(args), - )), - TokenTree::Punct(Punct::new(',', Spacing::Alone)), - TokenTree::Punct(Punct::new('@', Spacing::Alone)), - TokenTree::Ident(Ident::new("sig", Span::call_site())), - TokenTree::Group(Group::new( - Delimiter::Parenthesis, - TokenStream::from_iter(rest), - )), - TokenTree::Punct(Punct::new(',', Spacing::Alone)), - TokenTree::Punct(Punct::new('@', Spacing::Alone)), - TokenTree::Ident(Ident::new("impl_generics", Span::call_site())), - TokenTree::Group(Group::new( - Delimiter::Parenthesis, - TokenStream::from_iter(impl_generics), - )), - TokenTree::Punct(Punct::new(',', Spacing::Alone)), - TokenTree::Punct(Punct::new('@', Spacing::Alone)), - TokenTree::Ident(Ident::new("ty_generics", Span::call_site())), - TokenTree::Group(Group::new( - Delimiter::Parenthesis, - TokenStream::from_iter(ty_generics), - )), - TokenTree::Punct(Punct::new(',', Spacing::Alone)), - TokenTree::Punct(Punct::new('@', Spacing::Alone)), - TokenTree::Ident(Ident::new("body", Span::call_site())), - TokenTree::Group(Group::new( - Delimiter::Parenthesis, - TokenStream::from_iter(last), - )), - TokenTree::Punct(Punct::new(',', Spacing::Alone)), - ]), - )), - ]) + let mut ret = vec![]; + ret.extend("::kernel::pin_project!".parse::().unwrap()); + ret.push(TokenTree::Group(Group::new( + Delimiter::Brace, + TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("parse_input", Span::call_site())), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("args", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(args), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("sig", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(rest), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("impl_generics", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(impl_generics), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("ty_generics", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(ty_generics), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Punct(Punct::new('@', Spacing::Alone)), + TokenTree::Ident(Ident::new("body", Span::call_site())), + TokenTree::Group(Group::new( + Delimiter::Parenthesis, + TokenStream::from_iter(last), + )), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + ]), + ))); + TokenStream::from_iter(ret) } diff --git a/rust/macros/pinned_drop.rs b/rust/macros/pinned_drop.rs index 4d972dfc1d8c63..9403dc3cdbe8d8 100644 --- a/rust/macros/pinned_drop.rs +++ b/rust/macros/pinned_drop.rs @@ -33,19 +33,7 @@ pub(crate) fn pinned_drop(_args: TokenStream, input: TokenStream) -> TokenStream } let idx = pinned_drop_idx.unwrap(); // fully qualify the `PinnedDrop`. - toks.splice( - idx..idx, - vec![ - TokenTree::Punct(Punct::new(':', Spacing::Joint)), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - TokenTree::Ident(Ident::new("kernel", Span::call_site())), - TokenTree::Punct(Punct::new(':', Spacing::Joint)), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - TokenTree::Ident(Ident::new("init", Span::call_site())), - TokenTree::Punct(Punct::new(':', Spacing::Joint)), - TokenTree::Punct(Punct::new(':', Spacing::Alone)), - ], - ); + toks.splice(idx..idx, "::kernel::init::".parse::().unwrap()); // take the {} body. if let Some(TokenTree::Group(last)) = toks.pop() { TokenStream::from_iter(vec![ From ae4289f023c90a64f7fbca9da150733ead2adfdc Mon Sep 17 00:00:00 2001 From: y86-dev Date: Tue, 1 Nov 2022 22:39:28 +0100 Subject: [PATCH 10/11] Added `ffi_initX` used to create initializers from C functions --- rust/kernel/init.rs | 1 + rust/kernel/init/common.rs | 36 +++++++++++++++++++++++++++++ rust/kernel/sync/condvar.rs | 23 +++++++------------ rust/kernel/sync/mutex.rs | 21 ++++++++--------- rust/kernel/sync/rwsem.rs | 20 ++++++++-------- rust/kernel/sync/seqlock.rs | 26 ++++++++------------- rust/kernel/sync/spinlock.rs | 44 +++++++++++++++--------------------- 7 files changed, 90 insertions(+), 81 deletions(-) create mode 100644 rust/kernel/init/common.rs diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 3fcb5a93d6de4c..f04bf45ef762c5 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -117,6 +117,7 @@ use core::{ #[doc(hidden)] pub mod __private; +pub mod common; mod pin_project; mod pinned_drop; diff --git a/rust/kernel/init/common.rs b/rust/kernel/init/common.rs new file mode 100644 index 00000000000000..71364f51e61159 --- /dev/null +++ b/rust/kernel/init/common.rs @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Module containing common kernel initializer functions. + +use crate::{ + init::{self, PinInit}, + Opaque, +}; + +macro_rules! create_func { + ($name:ident $(, $arg_name:ident: $arg_typ:ident)*) => { + /// Create an initializer using the given initalizer function from C. + /// + /// # Safety + /// The given function **must** under all circumstances initialize the memory location to a valid + /// `T`. If it fails to do so it results in UB. + /// + /// If any parameters are given, those need to be valid for the function. Valid means that + /// calling the function with those parameters complies with the above requirement **and** every + /// other requirement on the function itself. + pub unsafe fn $name(init_func: unsafe extern "C" fn(*mut T $(, $arg_name: $arg_typ)*) $(, $arg_name: $arg_typ)*) -> impl PinInit> { + unsafe { + init::pin_init_from_closure(move |slot| { + init_func(Opaque::raw_get(slot) $(, $arg_name)*); + Ok(()) + }) + } + } + } +} + +create_func!(ffi_init); +create_func!(ffi_init1, arg1: A1); +create_func!(ffi_init2, arg1: A1, arg2: A2); +create_func!(ffi_init3, arg1: A1, arg2: A2, arg3: A3); +create_func!(ffi_init4, arg1: A1, arg2: A2, arg3: A3, arg4: A4); diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index 126ad8312c6af7..ec7f362db04347 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -60,23 +60,16 @@ impl CondVar { /// Constructs a new conditional variable. #[allow(clippy::new_ret_no_self)] pub const fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit { - fn init_wait_list( - name: &'static CStr, - key: &'static LockClassKey, - ) -> impl PinInit> { - let init = move |place: *mut Opaque| unsafe { - bindings::__init_waitqueue_head( - Opaque::raw_get(place), + pin_init!(Self { + // SAFETY: __init_waitqueue_head is an init function and name and key are valid + // parameters + wait_list: unsafe { + init::common::ffi_init2( + bindings::__init_waitqueue_head, name.as_char_ptr(), key.get(), - ); - Ok(()) - }; - // SAFETY: waitqueue has been initialized - unsafe { init::pin_init_from_closure(init) } - } - pin_init!(Self { - wait_list: init_wait_list(name, key), + ) + }, _pin: PhantomPinned, }) } diff --git a/rust/kernel/sync/mutex.rs b/rust/kernel/sync/mutex.rs index 8f78ce8ae03a17..6dc700d13ef201 100644 --- a/rust/kernel/sync/mutex.rs +++ b/rust/kernel/sync/mutex.rs @@ -81,19 +81,16 @@ unsafe impl PinInit> for MutexInit { self, slot: *mut Mutex, ) -> core::result::Result<(), core::convert::Infallible> { - fn init_mutex( - name: &'static CStr, - key: &'static LockClassKey, - ) -> impl PinInit> { - let init = move |slot: *mut Opaque| unsafe { - bindings::__mutex_init(Opaque::raw_get(slot), name.as_char_ptr(), key.get()); - Ok(()) - }; - // SAFETY: mutex has been initialized - unsafe { init::pin_init_from_closure(init) } - } let init = pin_init!(Mutex { - mutex: init_mutex(self.name, self.key), + // SAFETY: __mutex_init is an initializer function and name and key are valid + // parameters. + mutex: unsafe { + init::common::ffi_init2( + bindings::__mutex_init, + self.name.as_char_ptr(), + self.key.get(), + ) + }, data: UnsafeCell::new(self.data), _pin: PhantomPinned, }); diff --git a/rust/kernel/sync/rwsem.rs b/rust/kernel/sync/rwsem.rs index fc8f45e7678e9c..914fd3cf451398 100644 --- a/rust/kernel/sync/rwsem.rs +++ b/rust/kernel/sync/rwsem.rs @@ -84,18 +84,16 @@ unsafe impl PinInit> for Init { self, slot: *mut RwSemaphore, ) -> core::result::Result<(), core::convert::Infallible> { - fn init_rw_semaphore( - name: &'static CStr, - key: &'static LockClassKey, - ) -> impl PinInit> { - let init = move |slot: *mut Opaque| unsafe { - bindings::__init_rwsem(Opaque::raw_get(slot), name.as_char_ptr(), key.get()); - Ok(()) - }; - unsafe { init::pin_init_from_closure(init) } - } let init = pin_init!(RwSemaphore { - rwsem: init_rw_semaphore(self.name, self.key), + // SAFETY: __init_rwsem is an initializer function and name and key are valid + // parameters. + rwsem: unsafe { + init::common::ffi_init2( + bindings::__init_rwsem, + self.name.as_char_ptr(), + self.key.get(), + ) + }, data: UnsafeCell::new(self.data), _pin: PhantomPinned, }); diff --git a/rust/kernel/sync/seqlock.rs b/rust/kernel/sync/seqlock.rs index e85c9ad7a4bc2c..49bacbabef93e3 100644 --- a/rust/kernel/sync/seqlock.rs +++ b/rust/kernel/sync/seqlock.rs @@ -94,25 +94,17 @@ impl SeqLock { L::Inner: Sized, ::Error: From, { - fn init_count( - name: &'static CStr, - key2: &'static LockClassKey, - ) -> impl PinInit> { - let init = move |place: *mut Opaque| { - unsafe { - bindings::__seqcount_init( - Opaque::raw_get(place), - name.as_char_ptr(), - key2.get(), - ) - }; - Ok(()) - }; - unsafe { init::pin_init_from_closure(init) } - } try_pin_init!(Self { _p: PhantomPinned, - count: init_count(name, key2), + // SAFETY: __seqcount_init is an initializer function and name and key are valid + // parameters. + count: unsafe { + init::common::ffi_init2( + bindings::__seqcount_init, + name.as_char_ptr(), + key2.get() + ) + }, write_lock: L::new_lock(data, name, key1), }? L::Error) } diff --git a/rust/kernel/sync/spinlock.rs b/rust/kernel/sync/spinlock.rs index 088991fbd02049..d7b12b846db6af 100644 --- a/rust/kernel/sync/spinlock.rs +++ b/rust/kernel/sync/spinlock.rs @@ -126,18 +126,16 @@ unsafe impl PinInit> for Init { self, slot: *mut SpinLock, ) -> core::result::Result<(), core::convert::Infallible> { - fn init_spinlock( - name: &'static CStr, - key: &'static LockClassKey, - ) -> impl PinInit> { - let init = move |slot: *mut Opaque| unsafe { - bindings::__spin_lock_init(Opaque::raw_get(slot), name.as_char_ptr(), key.get()); - Ok(()) - }; - unsafe { init::pin_init_from_closure(init) } - } let init = pin_init!(SpinLock { - spin_lock: init_spinlock(self.name, self.key), + // SAFETY: __spin_lock_init is an initializer function and name and key are valid + // parameters. + spin_lock: unsafe { + init::common::ffi_init2( + bindings::__spin_lock_init, + self.name.as_char_ptr(), + self.key.get(), + ) + }, data: UnsafeCell::new(self.data), _pin: PhantomPinned, }); @@ -317,22 +315,16 @@ unsafe impl PinInit> for RInit { self, slot: *mut RawSpinLock, ) -> core::result::Result<(), core::convert::Infallible> { - fn init_spinlock( - name: &'static CStr, - key: &'static LockClassKey, - ) -> impl PinInit> { - let init = move |place: *mut Opaque| unsafe { - bindings::_raw_spin_lock_init( - Opaque::raw_get(place), - name.as_char_ptr(), - key.get(), - ); - Ok(()) - }; - unsafe { init::pin_init_from_closure(init) } - } let init = pin_init!(RawSpinLock { - spin_lock: init_spinlock(self.name, self.key), + // SAFETY: _raw_spin_lock_init is an initializer function and name and key are valid + // parameters. + spin_lock: unsafe { + init::common::ffi_init2( + bindings::_raw_spin_lock_init, + self.name.as_char_ptr(), + self.key.get(), + ) + }, data: UnsafeCell::new(self.data), _pin: PhantomPinned, }); From 308d6ee431158b3264693cec8f432c748f945072 Mon Sep 17 00:00:00 2001 From: y86-dev Date: Wed, 9 Nov 2022 12:58:31 +0100 Subject: [PATCH 11/11] Renamed `pin_project` -> `pin_data` --- drivers/android/context.rs | 2 +- drivers/android/node.rs | 2 +- drivers/android/process.rs | 2 +- drivers/android/thread.rs | 2 +- drivers/android/transaction.rs | 2 +- rust/kernel/device.rs | 4 +- rust/kernel/init.rs | 66 +++++++++---------- .../init/{pin_project.rs => pin_data.rs} | 18 ++--- rust/kernel/kasync/executor/workqueue.rs | 4 +- rust/kernel/prelude.rs | 2 +- rust/kernel/sync/arc.rs | 2 +- rust/kernel/sync/condvar.rs | 4 +- rust/kernel/sync/mutex.rs | 4 +- rust/kernel/sync/revocable.rs | 4 +- rust/kernel/sync/rwsem.rs | 4 +- rust/kernel/sync/seqlock.rs | 4 +- rust/kernel/sync/spinlock.rs | 6 +- rust/macros/lib.rs | 10 +-- rust/macros/{pin_project.rs => pin_data.rs} | 4 +- samples/rust/rust_miscdev.rs | 4 +- samples/rust/rust_semaphore.rs | 4 +- 21 files changed, 77 insertions(+), 77 deletions(-) rename rust/kernel/init/{pin_project.rs => pin_data.rs} (96%) rename rust/macros/{pin_project.rs => pin_data.rs} (96%) diff --git a/drivers/android/context.rs b/drivers/android/context.rs index 9be1f5db900544..ceee038a953f1b 100644 --- a/drivers/android/context.rs +++ b/drivers/android/context.rs @@ -17,7 +17,7 @@ struct Manager { uid: Option, } -#[pin_project] +#[pin_data] pub(crate) struct Context { #[pin] manager: Mutex, diff --git a/drivers/android/node.rs b/drivers/android/node.rs index 62f21b03b7834c..41f90bbef8f709 100644 --- a/drivers/android/node.rs +++ b/drivers/android/node.rs @@ -56,7 +56,7 @@ struct NodeDeathInner { aborted: bool, } -#[pin_project] +#[pin_data] pub(crate) struct NodeDeath { node: Arc, process: Arc, diff --git a/drivers/android/process.rs b/drivers/android/process.rs index 37c4eeecf53fe7..4fd02ec5a8b757 100644 --- a/drivers/android/process.rs +++ b/drivers/android/process.rs @@ -242,7 +242,7 @@ impl ProcessNodeRefs { } } -#[pin_project] +#[pin_data] pub(crate) struct Process { ctx: Arc, diff --git a/drivers/android/thread.rs b/drivers/android/thread.rs index a6725d14829934..c9707ec14e8d8f 100644 --- a/drivers/android/thread.rs +++ b/drivers/android/thread.rs @@ -230,7 +230,7 @@ impl InnerThread { } } -#[pin_project] +#[pin_data] pub(crate) struct Thread { pub(crate) id: i32, pub(crate) process: Arc, diff --git a/drivers/android/transaction.rs b/drivers/android/transaction.rs index 7f4c66008368e9..40645eee17bf2a 100644 --- a/drivers/android/transaction.rs +++ b/drivers/android/transaction.rs @@ -28,7 +28,7 @@ struct TransactionInner { file_list: List>, } -#[pin_project(PinnedDrop)] +#[pin_data(PinnedDrop)] pub(crate) struct Transaction { #[pin] inner: SpinLock, diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 6ae7e634444640..37a17d475626ad 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -9,7 +9,7 @@ use crate::{clk::Clk, error::from_kernel_err_ptr}; use crate::{ bindings, - macros::pin_project, + macros::pin_data, pin_init, prelude::*, revocable::{Revocable, RevocableGuard}, @@ -249,7 +249,7 @@ impl Drop for Device { /// /// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not /// explicitly called by the device drivers. -#[pin_project] +#[pin_data] pub struct Data { #[pin] registrations: RevocableMutex, diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index f04bf45ef762c5..80f1a1730e0d22 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -22,14 +22,14 @@ //! //! ## Directly creating an in-place constructor //! -//! If you want to use [`PinInit`], then you will have to annotate your struct with [`#[pin_project]`]. +//! If you want to use [`PinInit`], then you will have to annotate your struct with [`#[pin_data]`]. //! It is a macro that uses `#[pin]` as a marker for [structurally pinned fields]. //! //! ```rust //! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] //! use kernel::{prelude::*, sync::Mutex, new_mutex}; //! # use core::pin::Pin; -//! #[pin_project] +//! #[pin_data] //! struct Foo { //! #[pin] //! a: Mutex, @@ -49,7 +49,7 @@ //! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] //! # use kernel::{prelude::*, sync::Mutex, new_mutex}; //! # use core::pin::Pin; -//! # #[pin_project] +//! # #[pin_data] //! # struct Foo { //! # #[pin] //! # a: Mutex, @@ -76,7 +76,7 @@ //! ```rust //! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] //! # use kernel::{sync::Mutex, prelude::*, new_mutex, init::PinInit, try_pin_init}; -//! #[pin_project] +//! #[pin_data] //! struct DriverData { //! #[pin] //! status: Mutex, @@ -118,7 +118,7 @@ use core::{ #[doc(hidden)] pub mod __private; pub mod common; -mod pin_project; +mod pin_data; mod pinned_drop; /// Initialize a type directly on the stack. @@ -127,16 +127,16 @@ mod pinned_drop; /// /// ```rust /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] -/// # use kernel::{init, pin_init, stack_init, init::*, macros::pin_project, sync::Mutex, new_mutex}; +/// # use kernel::{init, pin_init, stack_init, init::*, macros::pin_data, sync::Mutex, new_mutex}; /// # use core::pin::Pin; -/// #[pin_project] +/// #[pin_data] /// struct Foo { /// #[pin] /// a: Mutex, /// b: Bar, /// } /// -/// #[pin_project] +/// #[pin_data] /// struct Bar { /// x: u32, /// } @@ -175,15 +175,15 @@ macro_rules! stack_init { /// /// ```rust /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] -/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; -/// #[pin_project] +/// #[pin_data] /// struct Foo { /// a: usize, /// b: Bar, /// } /// -/// #[pin_project] +/// #[pin_data] /// struct Bar { /// x: u32, /// } @@ -215,12 +215,12 @@ macro_rules! stack_init { /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] /// # use kernel::{init, pin_init, prelude::*, init::*}; /// # use core::pin::Pin; -/// # #[pin_project] +/// # #[pin_data] /// # struct Foo { /// # a: usize, /// # b: Bar, /// # } -/// # #[pin_project] +/// # #[pin_data] /// # struct Bar { /// # x: u32, /// # } @@ -241,14 +241,14 @@ macro_rules! stack_init { /// /// ```rust /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] -/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; -/// # #[pin_project] +/// # #[pin_data] /// # struct Foo { /// # a: usize, /// # b: Bar, /// # } -/// # #[pin_project] +/// # #[pin_data] /// # struct Bar { /// # x: u32, /// # } @@ -269,14 +269,14 @@ macro_rules! stack_init { /// /// ```rust /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] -/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; -/// # #[pin_project] +/// # #[pin_data] /// # struct Foo { /// # a: usize, /// # b: Bar, /// # } -/// # #[pin_project] +/// # #[pin_data] /// # struct Bar { /// # x: u32, /// # } @@ -290,7 +290,7 @@ macro_rules! stack_init { /// # }) /// # } /// # } -/// #[pin_project] +/// #[pin_data] /// struct FooContainer { /// #[pin] /// foo1: Foo, @@ -337,15 +337,15 @@ macro_rules! pin_init { /// /// ```rust /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] -/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; -/// #[pin_project] +/// #[pin_data] /// struct Foo { /// a: usize, /// b: Bar, /// } /// -/// #[pin_project] +/// #[pin_data] /// struct Bar { /// x: u32, /// } @@ -377,12 +377,12 @@ macro_rules! pin_init { /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] /// # use kernel::{init, pin_init, prelude::*, init::*}; /// # use core::pin::Pin; -/// # #[pin_project] +/// # #[pin_data] /// # struct Foo { /// # a: usize, /// # b: Bar, /// # } -/// # #[pin_project] +/// # #[pin_data] /// # struct Bar { /// # x: u32, /// # } @@ -403,14 +403,14 @@ macro_rules! pin_init { /// /// ```rust /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] -/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; -/// # #[pin_project] +/// # #[pin_data] /// # struct Foo { /// # a: usize, /// # b: Bar, /// # } -/// # #[pin_project] +/// # #[pin_data] /// # struct Bar { /// # x: u32, /// # } @@ -431,14 +431,14 @@ macro_rules! pin_init { /// /// ```rust /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] -/// # use kernel::{init, pin_init, macros::pin_project, init::*}; +/// # use kernel::{init, pin_init, macros::pin_data, init::*}; /// # use core::pin::Pin; -/// # #[pin_project] +/// # #[pin_data] /// # struct Foo { /// # a: usize, /// # b: Bar, /// # } -/// # #[pin_project] +/// # #[pin_data] /// # struct Bar { /// # x: u32, /// # } @@ -452,7 +452,7 @@ macro_rules! pin_init { /// # }) /// # } /// # } -/// #[pin_project] +/// #[pin_data] /// struct FooContainer { /// #[pin] /// foo1: Foo, @@ -1050,7 +1050,7 @@ pub const unsafe fn pin_init_from_closure( /// ```rust /// # use kernel::sync::Mutex; /// use kernel::macros::pinned_drop; -/// #[pin_project(PinnedDrop)] +/// #[pin_data(PinnedDrop)] /// struct Foo { /// #[pin] /// mtx: Mutex, diff --git a/rust/kernel/init/pin_project.rs b/rust/kernel/init/pin_data.rs similarity index 96% rename from rust/kernel/init/pin_project.rs rename to rust/kernel/init/pin_data.rs index 7365de1fae92ee..53ae757299d9dc 100644 --- a/rust/kernel/init/pin_project.rs +++ b/rust/kernel/init/pin_data.rs @@ -3,7 +3,7 @@ // use the proc macro instead #[doc(hidden)] #[macro_export] -macro_rules! pin_project { +macro_rules! _pin_data { (parse_input: @args($($pinned_drop:ident)?), @sig( @@ -15,7 +15,7 @@ macro_rules! pin_project { @ty_generics($($ty_generics:tt)*), @body({ $($fields:tt)* }), ) => { - $crate::pin_project!(find_pinned_fields: + $crate::_pin_data!(find_pinned_fields: @struct_attrs($(#[$($struct_attr)*])*), @vis($vis), @name($name), @@ -46,7 +46,7 @@ macro_rules! pin_project { @is_pinned(yes), @pinned_drop($($pinned_drop:ident)?), ) => { - $crate::pin_project!(find_pinned_fields: + $crate::_pin_data!(find_pinned_fields: @struct_attrs($($struct_attrs)*), @vis($vis), @name($name), @@ -77,7 +77,7 @@ macro_rules! pin_project { @is_pinned(), @pinned_drop($($pinned_drop:ident)?), ) => { - $crate::pin_project!(find_pinned_fields: + $crate::_pin_data!(find_pinned_fields: @struct_attrs($($struct_attrs)*), @vis($vis), @name($name), @@ -108,7 +108,7 @@ macro_rules! pin_project { @is_pinned($($is_pinned:ident)?), @pinned_drop($($pinned_drop:ident)?), ) => { - $crate::pin_project!(find_pinned_fields: + $crate::_pin_data!(find_pinned_fields: @struct_attrs($($struct_attrs)*), @vis($vis), @name($name), @@ -139,7 +139,7 @@ macro_rules! pin_project { @is_pinned($($is_pinned:ident)?), @pinned_drop($($pinned_drop:ident)?), ) => { - $crate::pin_project!(find_pinned_fields: + $crate::_pin_data!(find_pinned_fields: @struct_attrs($($struct_attrs)*), @vis($vis), @name($name), @@ -170,7 +170,7 @@ macro_rules! pin_project { @is_pinned($($is_pinned:ident)?), @pinned_drop($($pinned_drop:ident)?), ) => { - $crate::pin_project!(find_pinned_fields: + $crate::_pin_data!(find_pinned_fields: @struct_attrs($($struct_attrs)*), @vis($vis), @name($name), @@ -215,7 +215,7 @@ macro_rules! pin_project { __phantom: ::core::marker::PhantomData) -> $name<$($ty_generics)*>>, } - $crate::pin_project!(make_pin_data: + $crate::_pin_data!(make_pin_data: @pin_data(__ThePinData), @impl_generics($($impl_generics)*), @ty_generics($($ty_generics)*), @@ -246,7 +246,7 @@ macro_rules! pin_project { $($whr)* {} - $crate::pin_project!(drop_prevention: + $crate::_pin_data!(drop_prevention: @name($name), @impl_generics($($impl_generics)*), @ty_generics($($ty_generics)*), diff --git a/rust/kernel/kasync/executor/workqueue.rs b/rust/kernel/kasync/executor/workqueue.rs index e86d8d7d50d0bd..a40ed6a5c0c5d4 100644 --- a/rust/kernel/kasync/executor/workqueue.rs +++ b/rust/kernel/kasync/executor/workqueue.rs @@ -5,7 +5,7 @@ use super::{ArcWake, AutoStopHandle}; use crate::{ error::code::*, - macros::pin_project, + macros::pin_data, new_mutex, pin_init, prelude::*, revocable::AsyncRevocable, @@ -190,7 +190,7 @@ struct ExecutorInner { /// /// # Ok::<(), Error>(()) /// ``` -#[pin_project] +#[pin_data] pub struct Executor { queue: Either, #[pin] diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index 05ab8d30bc5b15..e95be94bb06f91 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -21,7 +21,7 @@ pub use super::build_assert; pub use super::{ dbg, dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn, fmt, - init, macros::pin_project, pin_init, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, + init, macros::pin_data, pin_init, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn, }; diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 30623d36f61f27..2be0f126da5b39 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -49,7 +49,7 @@ pub struct Arc { _p: PhantomData>, } -#[pin_project] +#[pin_data] #[repr(C)] struct ArcInner { #[pin] diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index ec7f362db04347..6ebd7707362c52 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -9,7 +9,7 @@ use super::{Guard, Lock, LockClassKey, LockInfo}; use crate::{ bindings, init::{self, PinInit}, - macros::pin_project, + macros::pin_data, pin_init, str::CStr, task::Task, @@ -38,7 +38,7 @@ const POLLFREE: u32 = 0x4000; /// /// [`struct wait_queue_head`]: ../../../include/linux/wait.h /// [init]: ../init/index.html -#[pin_project] +#[pin_data] pub struct CondVar { #[pin] pub(crate) wait_list: Opaque, diff --git a/rust/kernel/sync/mutex.rs b/rust/kernel/sync/mutex.rs index 6dc700d13ef201..5bbfe1735efd8e 100644 --- a/rust/kernel/sync/mutex.rs +++ b/rust/kernel/sync/mutex.rs @@ -8,7 +8,7 @@ use super::{Guard, Lock, LockClassKey, LockFactory, WriteLock}; use crate::{ bindings, init::{self, PinInit}, - macros::pin_project, + macros::pin_data, pin_init, str::CStr, Opaque, @@ -34,7 +34,7 @@ macro_rules! new_mutex { /// /// [`struct mutex`]: ../../../include/linux/mutex.h /// [init]: ../init/index.html -#[pin_project] +#[pin_data] pub struct Mutex { /// The kernel `struct mutex` object. #[pin] diff --git a/rust/kernel/sync/revocable.rs b/rust/kernel/sync/revocable.rs index 48739dfd062778..348c0b4f3da46a 100644 --- a/rust/kernel/sync/revocable.rs +++ b/rust/kernel/sync/revocable.rs @@ -4,7 +4,7 @@ use crate::{ init::PinInit, - macros::pin_project, + macros::pin_data, str::CStr, sync::{Guard, Lock, LockClassKey, LockFactory, LockInfo, ReadLock, WriteLock}, try_pin_init, True, @@ -101,7 +101,7 @@ impl Drop for Inner { /// ``` /// [init]: ../init/index.html /// [`new_revocable!`]: kernel::new_revocable -#[pin_project] +#[pin_data] pub struct Revocable { #[pin] inner: ::LockedType>, diff --git a/rust/kernel/sync/rwsem.rs b/rust/kernel/sync/rwsem.rs index 914fd3cf451398..e814f6832ea767 100644 --- a/rust/kernel/sync/rwsem.rs +++ b/rust/kernel/sync/rwsem.rs @@ -12,7 +12,7 @@ use super::{ use crate::{ bindings, init::{self, PinInit}, - macros::pin_project, + macros::pin_data, pin_init, str::CStr, Opaque, @@ -39,7 +39,7 @@ macro_rules! new_rwsemaphore { /// /// [`struct rw_semaphore`]: ../../../include/linux/rwsem.h /// [init]: ../init/index.html -#[pin_project] +#[pin_data] pub struct RwSemaphore { /// The kernel `struct rw_semaphore` object. #[pin] diff --git a/rust/kernel/sync/seqlock.rs b/rust/kernel/sync/seqlock.rs index 49bacbabef93e3..cb6fd34bc2452d 100644 --- a/rust/kernel/sync/seqlock.rs +++ b/rust/kernel/sync/seqlock.rs @@ -11,7 +11,7 @@ use super::{Guard, Lock, LockClassKey, LockFactory, ReadLock}; use crate::{ bindings, init::{self, PinInit}, - macros::pin_project, + macros::pin_data, str::CStr, try_pin_init, Opaque, }; @@ -61,7 +61,7 @@ use core::{cell::UnsafeCell, marker::PhantomPinned, ops::Deref}; /// } /// ``` /// [init]: ../init/index.html -#[pin_project] +#[pin_data] pub struct SeqLock { #[pin] _p: PhantomPinned, diff --git a/rust/kernel/sync/spinlock.rs b/rust/kernel/sync/spinlock.rs index d7b12b846db6af..6fe4c6fd63a8b5 100644 --- a/rust/kernel/sync/spinlock.rs +++ b/rust/kernel/sync/spinlock.rs @@ -12,7 +12,7 @@ use super::{ use crate::{ bindings, init::{self, PinInit}, - macros::pin_project, + macros::pin_data, pin_init, str::CStr, Opaque, True, @@ -82,7 +82,7 @@ macro_rules! new_spinlock { /// /// [`spinlock_t`]: ../../../include/linux/spinlock.h /// [init]: ../init/index.html -#[pin_project] +#[pin_data] pub struct SpinLock { #[pin] spin_lock: Opaque, @@ -271,7 +271,7 @@ macro_rules! new_rawspinlock { /// ``` /// /// [`raw_spinlock_t`]: ../../../include/linux/spinlock.h -#[pin_project] +#[pin_data] pub struct RawSpinLock { #[pin] spin_lock: Opaque, diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index 3216b7ae661985..26468794e97516 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -5,7 +5,7 @@ mod concat_idents; mod helpers; mod module; -mod pin_project; +mod pin_data; mod pinned_drop; mod vtable; @@ -202,15 +202,15 @@ pub fn concat_idents(ts: TokenStream) -> TokenStream { /// # Examples /// /// ```rust,ignore -/// #[pin_project] +/// #[pin_data] /// struct A { /// #[pin] /// a: usize, /// } /// ``` #[proc_macro_attribute] -pub fn pin_project(inner: TokenStream, item: TokenStream) -> TokenStream { - pin_project::pin_project(inner, item) +pub fn pin_data(inner: TokenStream, item: TokenStream) -> TokenStream { + pin_data::pin_data(inner, item) } /// Used to implement `PinnedDrop` safely. @@ -218,7 +218,7 @@ pub fn pin_project(inner: TokenStream, item: TokenStream) -> TokenStream { /// # Examples /// /// ```rust,ignore -/// #[pin_project(PinnedDrop)] +/// #[pin_data(PinnedDrop)] /// struct Foo { /// a: usize, /// } diff --git a/rust/macros/pin_project.rs b/rust/macros/pin_data.rs similarity index 96% rename from rust/macros/pin_project.rs rename to rust/macros/pin_data.rs index 8021d81a3f7002..5c62529f81c1a4 100644 --- a/rust/macros/pin_project.rs +++ b/rust/macros/pin_data.rs @@ -2,7 +2,7 @@ use proc_macro::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree}; -pub(crate) fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream { +pub(crate) fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream { let mut impl_generics = vec![]; let mut ty_generics = vec![]; let mut rest = vec![]; @@ -57,7 +57,7 @@ pub(crate) fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream rest.extend(toks); let last = rest.pop(); let mut ret = vec![]; - ret.extend("::kernel::pin_project!".parse::().unwrap()); + ret.extend("::kernel::_pin_data!".parse::().unwrap()); ret.push(TokenTree::Group(Group::new( Delimiter::Brace, TokenStream::from_iter(vec![ diff --git a/samples/rust/rust_miscdev.rs b/samples/rust/rust_miscdev.rs index f8ade71f8484b2..4444a817d9e08b 100644 --- a/samples/rust/rust_miscdev.rs +++ b/samples/rust/rust_miscdev.rs @@ -6,7 +6,7 @@ use kernel::prelude::*; use kernel::{ file::{self, File}, io_buffer::{IoBufferReader, IoBufferWriter}, - macros::pin_project, + macros::pin_data, miscdev, new_condvar, new_mutex, pin_init, sync::{Arc, ArcBorrow, CondVar, Mutex}, }; @@ -25,7 +25,7 @@ struct SharedStateInner { token_count: usize, } -#[pin_project] +#[pin_data] struct SharedState { #[pin] state_changed: CondVar, diff --git a/samples/rust/rust_semaphore.rs b/samples/rust/rust_semaphore.rs index 21e1e1428d1a69..2d9c4adfbe8920 100644 --- a/samples/rust/rust_semaphore.rs +++ b/samples/rust/rust_semaphore.rs @@ -17,7 +17,7 @@ use core::sync::atomic::{AtomicU64, Ordering}; use kernel::{ file::{self, File, IoctlCommand, IoctlHandler}, io_buffer::{IoBufferReader, IoBufferWriter}, - macros::pin_project, + macros::pin_data, miscdev::Registration, new_condvar, new_mutex, pin_init, prelude::*, @@ -38,7 +38,7 @@ struct SemaphoreInner { max_seen: usize, } -#[pin_project] +#[pin_data] struct Semaphore { #[pin] changed: CondVar,