Messages in this thread Patch in this message | | | Date | Thu, 25 Apr 2024 21:34:44 +0000 | From | Benno Lossin <> | Subject | [PATCH 2/2] rust: init: add re-initialization functions |
| |
Sometimes it is necessary to split allocation and initialization into two steps. One such situation is when reusing existing allocations obtained via `Box::drop_contents`. See [1] for an example. In order to support this use case add `re_[pin_]init` functions to the pin-init API. These functions operate on already allocated smart pointers that contain `MaybeUninit<T>`.
Signed-off-by: Benno Lossin <benno.lossin@proton.me> Link: https://lore.kernel.org/rust-for-linux/f026532f-8594-4f18-9aa5-57ad3f5bc592@proton.me/ [1] --- rust/kernel/init.rs | 88 ++++++++++++++++++++++++++++++------------ rust/kernel/prelude.rs | 2 +- 2 files changed, 65 insertions(+), 25 deletions(-)
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 9608f2bd2211..b37b23f07bf7 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -1159,13 +1159,8 @@ fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, where E: From<AllocError>, { - let mut this = <Box<_> as BoxExt<_>>::new_uninit(flags)?; - 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 we pin it later. - unsafe { init.__pinned_init(slot)? }; - // SAFETY: All fields have been initialized. - Ok(unsafe { this.assume_init() }.into()) + let this = <Box<_> as BoxExt<_>>::new_uninit(flags)?; + this.re_pin_init(init) } #[inline] @@ -1173,13 +1168,8 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E> where E: From<AllocError>, { - let mut this = <Box<_> as BoxExt<_>>::new_uninit(flags)?; - 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() }) + let this = <Box<_> as BoxExt<_>>::new_uninit(flags)?; + this.re_init(init) } } @@ -1189,13 +1179,8 @@ fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Pin<Self>, where E: From<AllocError>, { - let mut this = UniqueArc::new_uninit(flags)?; - 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 we pin it later. - unsafe { init.__pinned_init(slot)? }; - // SAFETY: All fields have been initialized. - Ok(unsafe { this.assume_init() }.into()) + let this = UniqueArc::new_uninit(flags)?; + this.re_pin_init(init) } #[inline] @@ -1203,13 +1188,68 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E> where E: From<AllocError>, { - let mut this = UniqueArc::new_uninit(flags)?; - let slot = this.as_mut_ptr(); + let this = UniqueArc::new_uninit(flags)?; + this.re_init(init) + } +} + +/// Smart pointer that can re-initialize its content. +pub trait InPlaceReInit<T> { + /// The type `Self` turns into when re-initialized. + type Initialized; + + /// Re-initializes `self` with the given initializer. + /// + /// Does not drop the current value and considers it as uninitialized memory. + fn re_init<E>(self, init: impl Init<T, E>) -> Result<Self::Initialized, E>; + + /// Re-initializes `self` with the given initializer. + /// + /// Does not drop the current value and considers it as uninitialized memory. + fn re_pin_init<E>(self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E>; +} + +impl<T> InPlaceReInit<T> for Box<MaybeUninit<T>> { + type Initialized = Box<T>; + + fn re_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> { + let slot = self.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() }) + Ok(unsafe { self.assume_init() }) + } + + fn re_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> { + let slot = self.as_mut_ptr(); + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, + // slot is valid and will not be moved, because we pin it later. + unsafe { init.__pinned_init(slot)? }; + // SAFETY: All fields have been initialized. + Ok(unsafe { self.assume_init() }.into()) + } +} + +impl<T> InPlaceReInit<T> for UniqueArc<MaybeUninit<T>> { + type Initialized = UniqueArc<T>; + + fn re_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> { + let slot = self.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 { self.assume_init() }) + } + + fn re_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> { + let slot = self.as_mut_ptr(); + // SAFETY: When init errors/panics, slot will get deallocated but not dropped, + // slot is valid and will not be moved, because we pin it later. + unsafe { init.__pinned_init(slot)? }; + // SAFETY: All fields have been initialized. + Ok(unsafe { self.assume_init() }.into()) } } diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index b37a0b3180fb..078b2b1d84ae 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -37,6 +37,6 @@ pub use super::{str::CStr, ThisModule}; -pub use super::init::{InPlaceInit, Init, PinInit}; +pub use super::init::{InPlaceInit, InPlaceReInit, Init, PinInit}; pub use super::current; -- 2.44.0
| |