mirror of
https://github.com/torvalds/linux.git
synced 2025-04-09 14:45:27 +00:00
rust: pin-init: synchronize documentation with the user-space version
Synchronize documentation and examples with the user-space version. Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Fiona Behrens <me@kloenk.dev> Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250308110339.2997091-18-benno.lossin@proton.me Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
9b2299af3b
commit
02c01c089d
@ -1,11 +1,9 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
//! This module contains API-internal items for pin-init.
|
||||
//! This module contains library internal items.
|
||||
//!
|
||||
//! These items must not be used outside of
|
||||
//! - `kernel/init.rs`
|
||||
//! - `macros/pin_data.rs`
|
||||
//! - `macros/pinned_drop.rs`
|
||||
//! These items must not be used outside of this crate and the pin-init-internal crate located at
|
||||
//! `../internal`.
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -1,10 +1,37 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
//! API to safely and fallibly initialize pinned `struct`s using in-place constructors.
|
||||
//! Library to safely and fallibly initialize pinned `struct`s using in-place constructors.
|
||||
//!
|
||||
//! [Pinning][pinning] is Rust's way of ensuring data does not move.
|
||||
//!
|
||||
//! It also allows in-place initialization of big `struct`s that would otherwise produce a stack
|
||||
//! overflow.
|
||||
//!
|
||||
//! This library's main use-case is in [Rust-for-Linux]. Although this version can be used
|
||||
//! standalone.
|
||||
//!
|
||||
//! There are cases when you want to in-place initialize a struct. For example when it is very big
|
||||
//! and moving it from the stack is not an option, because it is bigger than the stack itself.
|
||||
//! Another reason would be that you need the address of the object to initialize it. This stands
|
||||
//! in direct conflict with Rust's normal process of first initializing an object and then moving
|
||||
//! it into it's final memory location. For more information, see
|
||||
//! <https://rust-for-linux.com/the-safe-pinned-initialization-problem>.
|
||||
//!
|
||||
//! This library allows you to do in-place initialization safely.
|
||||
//!
|
||||
//! ## Nightly Needed for `alloc` feature
|
||||
//!
|
||||
//! This library requires the [`allocator_api` unstable feature] when the `alloc` feature is
|
||||
//! enabled and thus this feature can only be used with a nightly compiler. When enabling the
|
||||
//! `alloc` feature, the user will be required to activate `allocator_api` as well.
|
||||
//!
|
||||
//! [`allocator_api` unstable feature]: https://doc.rust-lang.org/nightly/unstable-book/library-features/allocator-api.html
|
||||
//!
|
||||
//! The feature is enabled by default, thus by default `pin-init` will require a nightly compiler.
|
||||
//! However, using the crate on stable compilers is possible by disabling `alloc`. In practice this
|
||||
//! will require the `std` feature, because stable compilers have neither `Box` nor `Arc` in no-std
|
||||
//! mode.
|
||||
//!
|
||||
//! # Overview
|
||||
//!
|
||||
//! To initialize a `struct` with an in-place constructor you will need two things:
|
||||
@ -17,12 +44,17 @@
|
||||
//! - a custom function/macro returning an in-place constructor provided by someone else,
|
||||
//! - using the unsafe function [`pin_init_from_closure()`] to manually create an initializer.
|
||||
//!
|
||||
//! Aside from pinned initialization, this API also supports in-place construction without pinning,
|
||||
//! the macros/types/functions are generally named like the pinned variants without the `pin`
|
||||
//! prefix.
|
||||
//! Aside from pinned initialization, this library also supports in-place construction without
|
||||
//! pinning, the macros/types/functions are generally named like the pinned variants without the
|
||||
//! `pin_` prefix.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Throughout the examples we will often make use of the `CMutex` type which can be found in
|
||||
//! `../examples/mutex.rs`. It is essentially a userland rebuild of the `struct mutex` type from
|
||||
//! the Linux kernel. It also uses a wait list and a basic spinlock. Importantly the wait list
|
||||
//! requires it to be pinned to be locked and thus is a prime candidate for using this library.
|
||||
//!
|
||||
//! ## Using the [`pin_init!`] macro
|
||||
//!
|
||||
//! If you want to use [`PinInit`], then you will have to annotate your `struct` with
|
||||
@ -36,7 +68,7 @@
|
||||
//! # #![feature(allocator_api)]
|
||||
//! # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
|
||||
//! # use core::pin::Pin;
|
||||
//! use pin_init::*;
|
||||
//! use pin_init::{pin_data, pin_init, InPlaceInit};
|
||||
//!
|
||||
//! #[pin_data]
|
||||
//! struct Foo {
|
||||
@ -80,8 +112,8 @@
|
||||
//!
|
||||
//! ## Using a custom 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.
|
||||
//! Many types that use this library supply a function/macro that returns an initializer, because
|
||||
//! the above method only works for types where you can access the fields.
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! # #![feature(allocator_api)]
|
||||
@ -132,7 +164,7 @@
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! # #![feature(extern_types)]
|
||||
//! use pin_init::*;
|
||||
//! use pin_init::{pin_data, pinned_drop, PinInit, PinnedDrop, pin_init_from_closure};
|
||||
//! use core::{
|
||||
//! ptr::addr_of_mut,
|
||||
//! marker::PhantomPinned,
|
||||
@ -141,8 +173,11 @@
|
||||
//! mem::MaybeUninit,
|
||||
//! };
|
||||
//! mod bindings {
|
||||
//! #[repr(C)]
|
||||
//! pub struct foo {
|
||||
//! /* fields from C ... */
|
||||
//! }
|
||||
//! extern "C" {
|
||||
//! pub type foo;
|
||||
//! pub fn init_foo(ptr: *mut foo);
|
||||
//! pub fn destroy_foo(ptr: *mut foo);
|
||||
//! #[must_use = "you must check the error return code"]
|
||||
@ -200,6 +235,10 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! For more information on how to use [`pin_init_from_closure()`], take a look at the uses inside
|
||||
//! the `kernel` crate. The [`sync`] module is a good starting point.
|
||||
//!
|
||||
//! [`sync`]: https://rust.docs.kernel.org/kernel/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
|
||||
@ -214,11 +253,10 @@
|
||||
)]
|
||||
#![cfg_attr(not(kernel), doc = "[`Arc<T>`]: alloc::alloc::sync::Arc")]
|
||||
#![cfg_attr(not(kernel), doc = "[`Box<T>`]: alloc::alloc::boxed::Box")]
|
||||
//! [`impl PinInit<Foo>`]: PinInit
|
||||
//! [`impl PinInit<T, E>`]: PinInit
|
||||
//! [`impl Init<T, E>`]: Init
|
||||
//! [`pin_data`]: crate::pin_data
|
||||
//! [`pin_init!`]: crate::pin_init!
|
||||
//! [`impl PinInit<Foo>`]: crate::PinInit
|
||||
//! [`impl PinInit<T, E>`]: crate::PinInit
|
||||
//! [`impl Init<T, E>`]: crate::Init
|
||||
//! [Rust-for-Linux]: https://rust-for-linux.com/
|
||||
|
||||
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
|
||||
#![cfg_attr(
|
||||
@ -404,8 +442,6 @@ pub use ::pin_init_internal::Zeroable;
|
||||
/// A normal `let` binding with optional type annotation. The expression is expected to implement
|
||||
/// [`PinInit`]/[`Init`] with the error type [`Infallible`]. If you want to use a different error
|
||||
/// type, then use [`stack_try_pin_init!`].
|
||||
///
|
||||
/// [`stack_try_pin_init!`]: crate::stack_try_pin_init!
|
||||
#[macro_export]
|
||||
macro_rules! stack_pin_init {
|
||||
(let $var:ident $(: $t:ty)? = $val:expr) => {
|
||||
@ -542,10 +578,10 @@ macro_rules! stack_try_pin_init {
|
||||
///
|
||||
/// # Init-functions
|
||||
///
|
||||
/// When working with this API 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 API that is also possible.
|
||||
/// However, there are a few extra things to keep in mind.
|
||||
/// 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, simply declare it like this:
|
||||
///
|
||||
@ -674,22 +710,22 @@ macro_rules! stack_try_pin_init {
|
||||
/// #[pin]
|
||||
/// pin: PhantomPinned,
|
||||
/// }
|
||||
/// pin_init!(&this in Buf {
|
||||
///
|
||||
/// let init = pin_init!(&this in Buf {
|
||||
/// buf: [0; 64],
|
||||
/// // SAFETY: TODO.
|
||||
/// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() },
|
||||
/// pin: PhantomPinned,
|
||||
/// });
|
||||
/// pin_init!(Buf {
|
||||
/// let init = pin_init!(Buf {
|
||||
/// buf: [1; 64],
|
||||
/// ..Zeroable::zeroed()
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// [`try_pin_init!`]: crate::try_pin_init
|
||||
/// [`NonNull<Self>`]: core::ptr::NonNull
|
||||
// For a detailed example of how this macro works, see the module documentation of the hidden
|
||||
// module `__internal` inside of `init/__internal.rs`.
|
||||
// module `macros` inside of `macros.rs`.
|
||||
#[macro_export]
|
||||
macro_rules! pin_init {
|
||||
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
|
||||
@ -719,7 +755,8 @@ macro_rules! pin_init {
|
||||
/// ```rust,ignore
|
||||
/// # #![feature(allocator_api)]
|
||||
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
|
||||
/// use pin_init::*;
|
||||
/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, zeroed};
|
||||
///
|
||||
/// #[pin_data]
|
||||
/// struct BigBuf {
|
||||
/// big: Box<[u8; 1024 * 1024 * 1024]>,
|
||||
@ -730,7 +767,7 @@ macro_rules! pin_init {
|
||||
/// impl BigBuf {
|
||||
/// fn new() -> impl PinInit<Self, Error> {
|
||||
/// try_pin_init!(Self {
|
||||
/// big: Box::init(init::zeroed())?,
|
||||
/// big: Box::init(zeroed())?,
|
||||
/// small: [0; 1024 * 1024],
|
||||
/// ptr: core::ptr::null_mut(),
|
||||
/// }? Error)
|
||||
@ -739,7 +776,7 @@ macro_rules! pin_init {
|
||||
/// # let _ = Box::pin_init(BigBuf::new());
|
||||
/// ```
|
||||
// For a detailed example of how this macro works, see the module documentation of the hidden
|
||||
// module `__internal` inside of `init/__internal.rs`.
|
||||
// module `macros` inside of `macros.rs`.
|
||||
#[macro_export]
|
||||
macro_rules! try_pin_init {
|
||||
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
|
||||
@ -772,9 +809,30 @@ macro_rules! try_pin_init {
|
||||
/// This initializer is for initializing data in-place that might later be moved. If you want to
|
||||
/// pin-initialize, use [`pin_init!`].
|
||||
///
|
||||
/// [`try_init!`]: crate::try_init!
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![feature(allocator_api)]
|
||||
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
|
||||
/// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
|
||||
/// # use pin_init::InPlaceInit;
|
||||
/// use pin_init::{init, Init, zeroed};
|
||||
///
|
||||
/// struct BigBuf {
|
||||
/// small: [u8; 1024 * 1024],
|
||||
/// }
|
||||
///
|
||||
/// impl BigBuf {
|
||||
/// fn new() -> impl Init<Self> {
|
||||
/// init!(Self {
|
||||
/// small <- zeroed(),
|
||||
/// })
|
||||
/// }
|
||||
/// }
|
||||
/// # let _ = Box::init(BigBuf::new());
|
||||
/// ```
|
||||
// For a detailed example of how this macro works, see the module documentation of the hidden
|
||||
// module `__internal` inside of `init/__internal.rs`.
|
||||
// module `macros` inside of `macros.rs`.
|
||||
#[macro_export]
|
||||
macro_rules! init {
|
||||
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
|
||||
@ -804,7 +862,9 @@ macro_rules! init {
|
||||
/// ```rust,ignore
|
||||
/// # #![feature(allocator_api)]
|
||||
/// # use core::alloc::AllocError;
|
||||
/// use pin_init::*;
|
||||
/// # use pin_init::InPlaceInit;
|
||||
/// use pin_init::{try_init, Init, zeroed};
|
||||
///
|
||||
/// struct BigBuf {
|
||||
/// big: Box<[u8; 1024 * 1024 * 1024]>,
|
||||
/// small: [u8; 1024 * 1024],
|
||||
@ -818,10 +878,10 @@ macro_rules! init {
|
||||
/// }? AllocError)
|
||||
/// }
|
||||
/// }
|
||||
/// # let _ = Box::init(BigBuf::new());
|
||||
/// ```
|
||||
/// [`try_pin_init!`]: crate::try_pin_init
|
||||
// For a detailed example of how this macro works, see the module documentation of the hidden
|
||||
// module `__internal` inside of `init/__internal.rs`.
|
||||
// module `macros` inside of `macros.rs`.
|
||||
#[macro_export]
|
||||
macro_rules! try_init {
|
||||
($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
|
||||
@ -847,7 +907,8 @@ macro_rules! try_init {
|
||||
///
|
||||
/// This will succeed:
|
||||
/// ```ignore
|
||||
/// use pin_init::assert_pinned;
|
||||
/// use pin_init::{pin_data, assert_pinned};
|
||||
///
|
||||
/// #[pin_data]
|
||||
/// struct MyStruct {
|
||||
/// #[pin]
|
||||
@ -859,7 +920,8 @@ macro_rules! try_init {
|
||||
///
|
||||
/// This will fail:
|
||||
/// ```compile_fail,ignore
|
||||
/// use pin_init::assert_pinned;
|
||||
/// use pin_init::{pin_data, assert_pinned};
|
||||
///
|
||||
/// #[pin_data]
|
||||
/// struct MyStruct {
|
||||
/// some_field: u64,
|
||||
@ -872,7 +934,9 @@ macro_rules! try_init {
|
||||
/// work around this, you may pass the `inline` parameter to the macro. The `inline` parameter can
|
||||
/// only be used when the macro is invoked from a function body.
|
||||
/// ```ignore
|
||||
/// use pin_init::assert_pinned;
|
||||
/// # use core::pin::Pin;
|
||||
/// use pin_init::{pin_data, assert_pinned};
|
||||
///
|
||||
/// #[pin_data]
|
||||
/// struct Foo<T> {
|
||||
/// #[pin]
|
||||
@ -1056,14 +1120,15 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// # #![expect(clippy::disallowed_names)]
|
||||
/// use pin_init::{init_from_closure, zeroed};
|
||||
/// use pin_init::{init, zeroed, Init};
|
||||
///
|
||||
/// struct Foo {
|
||||
/// buf: [u8; 1_000_000],
|
||||
/// }
|
||||
///
|
||||
/// impl Foo {
|
||||
/// fn setup(&mut self) {
|
||||
/// pr_info!("Setting up foo");
|
||||
/// println!("Setting up foo");
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
@ -1302,8 +1367,6 @@ pub trait InPlaceWrite<T> {
|
||||
/// # Safety
|
||||
///
|
||||
/// This trait must be implemented via the [`pinned_drop`] proc-macro attribute on the impl.
|
||||
///
|
||||
/// [`pinned_drop`]: crate::pinned_drop
|
||||
pub unsafe trait PinnedDrop: __internal::HasPinData {
|
||||
/// Executes the pinned destructor of this type.
|
||||
///
|
||||
|
@ -1,8 +1,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
//! This module provides the macros that actually implement the proc-macros `pin_data` and
|
||||
//! `pinned_drop`. It also contains `__init_internal` the implementation of the `{try_}{pin_}init!`
|
||||
//! macros.
|
||||
//! `pinned_drop`. It also contains `__init_internal`, the implementation of the
|
||||
//! `{try_}{pin_}init!` macros.
|
||||
//!
|
||||
//! These macros should never be called directly, since they expect their input to be
|
||||
//! in a certain format which is internal. If used incorrectly, these macros can lead to UB even in
|
||||
@ -11,16 +11,17 @@
|
||||
//! This architecture has been chosen because the kernel does not yet have access to `syn` which
|
||||
//! would make matters a lot easier for implementing these as proc-macros.
|
||||
//!
|
||||
//! Since this library and the kernel implementation should diverge as little as possible, the same
|
||||
//! approach has been taken here.
|
||||
//!
|
||||
//! # Macro expansion example
|
||||
//!
|
||||
//! This section is intended for readers trying to understand the macros in this module and the
|
||||
//! `pin_init!` macros from `init.rs`.
|
||||
//! `[try_][pin_]init!` macros from `lib.rs`.
|
||||
//!
|
||||
//! We will look at the following example:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! # use pin_init::*;
|
||||
//! # use core::pin::Pin;
|
||||
//! #[pin_data]
|
||||
//! #[repr(C)]
|
||||
//! struct Bar<T> {
|
||||
@ -45,7 +46,7 @@
|
||||
//! #[pinned_drop]
|
||||
//! impl PinnedDrop for Foo {
|
||||
//! fn drop(self: Pin<&mut Self>) {
|
||||
//! pr_info!("{self:p} is getting dropped.");
|
||||
//! println!("{self:p} is getting dropped.");
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
@ -75,7 +76,6 @@
|
||||
//! Here is the definition of `Bar` from our example:
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! # use pin_init::*;
|
||||
//! #[pin_data]
|
||||
//! #[repr(C)]
|
||||
//! struct Bar<T> {
|
||||
@ -251,7 +251,7 @@
|
||||
//! // is an error later. This `DropGuard` will drop the field when it gets
|
||||
//! // dropped and has not yet been forgotten.
|
||||
//! let __t_guard = unsafe {
|
||||
//! ::pinned_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).t))
|
||||
//! ::pin_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).t))
|
||||
//! };
|
||||
//! // Expansion of `x: 0,`:
|
||||
//! // Since this can be an arbitrary expression we cannot place it inside
|
||||
@ -412,7 +412,7 @@
|
||||
//! #[pinned_drop]
|
||||
//! impl PinnedDrop for Foo {
|
||||
//! fn drop(self: Pin<&mut Self>) {
|
||||
//! pr_info!("{self:p} is getting dropped.");
|
||||
//! println!("{self:p} is getting dropped.");
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
@ -423,7 +423,7 @@
|
||||
//! // `unsafe`, full path and the token parameter are added, everything else stays the same.
|
||||
//! unsafe impl ::pin_init::PinnedDrop for Foo {
|
||||
//! fn drop(self: Pin<&mut Self>, _: ::pin_init::__internal::OnlyCallFromDrop) {
|
||||
//! pr_info!("{self:p} is getting dropped.");
|
||||
//! println!("{self:p} is getting dropped.");
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
Loading…
x
Reference in New Issue
Block a user