Skip to content

Commit d0fdc39

Browse files
y86-devojeda
authored andcommitted
rust: init: add PinnedDrop trait and macros
The `PinnedDrop` trait that facilitates destruction of pinned types. It has to be implemented via the `#[pinned_drop]` macro, since the `drop` function should not be called by normal code, only by other destructors. It also only works on structs that are annotated with `#[pin_data(PinnedDrop)]`. Co-developed-by: Gary Guo <[email protected]> Signed-off-by: Gary Guo <[email protected]> Signed-off-by: Benno Lossin <[email protected]> Reviewed-by: Alice Ryhl <[email protected]> Reviewed-by: Andreas Hindborg <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 92c4a1e commit d0fdc39

File tree

5 files changed

+488
-0
lines changed

5 files changed

+488
-0
lines changed

rust/kernel/init.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,78 @@
104104
//! }
105105
//! ```
106106
//!
107+
//! ## Manual creation of an initializer
108+
//!
109+
//! Often when working with primitives the previous approaches are not sufficient. That is where
110+
//! [`pin_init_from_closure()`] comes in. This `unsafe` function allows you to create a
111+
//! [`impl PinInit<T, E>`] directly from a closure. Of course you have to ensure that the closure
112+
//! actually does the initialization in the correct way. Here are the things to look out for
113+
//! (we are calling the parameter to the closure `slot`):
114+
//! - when the closure returns `Ok(())`, then it has completed the initialization successfully, so
115+
//! `slot` now contains a valid bit pattern for the type `T`,
116+
//! - when the closure returns `Err(e)`, then the caller may deallocate the memory at `slot`, so
117+
//! you need to take care to clean up anything if your initialization fails mid-way,
118+
//! - you may assume that `slot` will stay pinned even after the closure returns until `drop` of
119+
//! `slot` gets called.
120+
//!
121+
//! ```rust
122+
//! use kernel::{prelude::*, init};
123+
//! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin};
124+
//! # mod bindings {
125+
//! # pub struct foo;
126+
//! # pub unsafe fn init_foo(_ptr: *mut foo) {}
127+
//! # pub unsafe fn destroy_foo(_ptr: *mut foo) {}
128+
//! # pub unsafe fn enable_foo(_ptr: *mut foo, _flags: u32) -> i32 { 0 }
129+
//! # }
130+
//! /// # Invariants
131+
//! ///
132+
//! /// `foo` is always initialized
133+
//! #[pin_data(PinnedDrop)]
134+
//! pub struct RawFoo {
135+
//! #[pin]
136+
//! foo: Opaque<bindings::foo>,
137+
//! #[pin]
138+
//! _p: PhantomPinned,
139+
//! }
140+
//!
141+
//! impl RawFoo {
142+
//! pub fn new(flags: u32) -> impl PinInit<Self, Error> {
143+
//! // SAFETY:
144+
//! // - when the closure returns `Ok(())`, then it has successfully initialized and
145+
//! // enabled `foo`,
146+
//! // - when it returns `Err(e)`, then it has cleaned up before
147+
//! unsafe {
148+
//! init::pin_init_from_closure(move |slot: *mut Self| {
149+
//! // `slot` contains uninit memory, avoid creating a reference.
150+
//! let foo = addr_of_mut!((*slot).foo);
151+
//!
152+
//! // Initialize the `foo`
153+
//! bindings::init_foo(Opaque::raw_get(foo));
154+
//!
155+
//! // Try to enable it.
156+
//! let err = bindings::enable_foo(Opaque::raw_get(foo), flags);
157+
//! if err != 0 {
158+
//! // Enabling has failed, first clean up the foo and then return the error.
159+
//! bindings::destroy_foo(Opaque::raw_get(foo));
160+
//! return Err(Error::from_kernel_errno(err));
161+
//! }
162+
//!
163+
//! // All fields of `RawFoo` have been initialized, since `_p` is a ZST.
164+
//! Ok(())
165+
//! })
166+
//! }
167+
//! }
168+
//! }
169+
//!
170+
//! #[pinned_drop]
171+
//! impl PinnedDrop for RawFoo {
172+
//! fn drop(self: Pin<&mut Self>) {
173+
//! // SAFETY: Since `foo` is initialized, destroying is safe.
174+
//! unsafe { bindings::destroy_foo(self.foo.get()) };
175+
//! }
176+
//! }
177+
//! ```
178+
//!
107179
//! [`sync`]: kernel::sync
108180
//! [pinning]: https://doc.rust-lang.org/std/pin/index.html
109181
//! [structurally pinned fields]:
@@ -1084,3 +1156,42 @@ impl<T> InPlaceInit<T> for UniqueArc<T> {
10841156
Ok(unsafe { this.assume_init() })
10851157
}
10861158
}
1159+
1160+
/// Trait facilitating pinned destruction.
1161+
///
1162+
/// Use [`pinned_drop`] to implement this trait safely:
1163+
///
1164+
/// ```rust
1165+
/// # use kernel::sync::Mutex;
1166+
/// use kernel::macros::pinned_drop;
1167+
/// use core::pin::Pin;
1168+
/// #[pin_data(PinnedDrop)]
1169+
/// struct Foo {
1170+
/// #[pin]
1171+
/// mtx: Mutex<usize>,
1172+
/// }
1173+
///
1174+
/// #[pinned_drop]
1175+
/// impl PinnedDrop for Foo {
1176+
/// fn drop(self: Pin<&mut Self>) {
1177+
/// pr_info!("Foo is being dropped!");
1178+
/// }
1179+
/// }
1180+
/// ```
1181+
///
1182+
/// # Safety
1183+
///
1184+
/// This trait must be implemented via the [`pinned_drop`] proc-macro attribute on the impl.
1185+
///
1186+
/// [`pinned_drop`]: kernel::macros::pinned_drop
1187+
pub unsafe trait PinnedDrop: __internal::HasPinData {
1188+
/// Executes the pinned destructor of this type.
1189+
///
1190+
/// While this function is marked safe, it is actually unsafe to call it manually. For this
1191+
/// reason it takes an additional parameter. This type can only be constructed by `unsafe` code
1192+
/// and thus prevents this function from being called where it should not.
1193+
///
1194+
/// This extra parameter will be generated by the `#[pinned_drop]` proc-macro attribute
1195+
/// automatically.
1196+
fn drop(self: Pin<&mut Self>, only_call_from_drop: __internal::OnlyCallFromDrop);
1197+
}

rust/kernel/init/__internal.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,18 @@ impl<T: ?Sized> Drop for DropGuard<T> {
161161
}
162162
}
163163
}
164+
165+
/// Token used by `PinnedDrop` to prevent calling the function without creating this unsafely
166+
/// created struct. This is needed, because the `drop` function is safe, but should not be called
167+
/// manually.
168+
pub struct OnlyCallFromDrop(());
169+
170+
impl OnlyCallFromDrop {
171+
/// # Safety
172+
///
173+
/// This function should only be called from the [`Drop::drop`] function and only be used to
174+
/// delegate the destruction to the pinned destructor [`PinnedDrop::drop`] of the same type.
175+
pub unsafe fn new() -> Self {
176+
Self(())
177+
}
178+
}

0 commit comments

Comments
 (0)