Skip to content

Commit 92c4a1e

Browse files
y86-devojeda
authored andcommitted
rust: init/sync: add InPlaceInit trait to pin-initialize smart pointers
The `InPlaceInit` trait that provides two functions, for initializing using `PinInit<T, E>` and `Init<T>`. It is implemented by `Arc<T>`, `UniqueArc<T>` and `Box<T>`. Signed-off-by: Benno Lossin <[email protected]> Reviewed-by: Alice Ryhl <[email protected]> Reviewed-by: Gary Guo <[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 fc6c6ba commit 92c4a1e

File tree

2 files changed

+139
-13
lines changed

2 files changed

+139
-13
lines changed

rust/kernel/init.rs

+115-13
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,16 @@
114114
//! [`impl Init<T, E>`]: Init
115115
//! [`Opaque`]: kernel::types::Opaque
116116
//! [`pin_data`]: ::macros::pin_data
117-
//! [`UniqueArc<T>`]: kernel::sync::UniqueArc
118117
118+
use crate::{
119+
error::{self, Error},
120+
sync::UniqueArc,
121+
};
119122
use alloc::boxed::Box;
120-
use core::{cell::Cell, convert::Infallible, marker::PhantomData, mem::MaybeUninit, ptr};
123+
use core::{
124+
alloc::AllocError, cell::Cell, convert::Infallible, marker::PhantomData, mem::MaybeUninit,
125+
pin::Pin, ptr,
126+
};
121127

122128
#[doc(hidden)]
123129
pub mod __internal;
@@ -309,7 +315,6 @@ pub mod macros;
309315
///
310316
/// [`try_pin_init!`]: kernel::try_pin_init
311317
/// [`NonNull<Self>`]: core::ptr::NonNull
312-
/// [`Error`]: kernel::error::Error
313318
// For a detailed example of how this macro works, see the module documentation of the hidden
314319
// module `__internal` inside of `init/__internal.rs`.
315320
#[macro_export]
@@ -363,8 +368,6 @@ macro_rules! pin_init {
363368
/// }
364369
/// }
365370
/// ```
366-
///
367-
/// [`Error`]: kernel::error::Error
368371
// For a detailed example of how this macro works, see the module documentation of the hidden
369372
// module `__internal` inside of `init/__internal.rs`.
370373
#[macro_export]
@@ -586,8 +589,6 @@ macro_rules! try_pin_init {
586589
///
587590
/// This initializer is for initializing data in-place that might later be moved. If you want to
588591
/// pin-initialize, use [`pin_init!`].
589-
///
590-
/// [`Error`]: kernel::error::Error
591592
// For a detailed example of how this macro works, see the module documentation of the hidden
592593
// module `__internal` inside of `init/__internal.rs`.
593594
#[macro_export]
@@ -635,8 +636,6 @@ macro_rules! init {
635636
/// }
636637
/// }
637638
/// ```
638-
///
639-
/// [`Error`]: kernel::error::Error
640639
// For a detailed example of how this macro works, see the module documentation of the hidden
641640
// module `__internal` inside of `init/__internal.rs`.
642641
#[macro_export]
@@ -842,7 +841,8 @@ macro_rules! try_init {
842841
/// A pin-initializer for the type `T`.
843842
///
844843
/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
845-
/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`].
844+
/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Use the [`InPlaceInit::pin_init`] function of a
845+
/// smart pointer like [`Arc<T>`] on this.
846846
///
847847
/// Also see the [module description](self).
848848
///
@@ -861,7 +861,6 @@ macro_rules! try_init {
861861
///
862862
/// [`Arc<T>`]: crate::sync::Arc
863863
/// [`Arc::pin_init`]: crate::sync::Arc::pin_init
864-
/// [`UniqueArc<T>`]: kernel::sync::UniqueArc
865864
#[must_use = "An initializer must be used in order to create its value."]
866865
pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
867866
/// Initializes `slot`.
@@ -878,7 +877,8 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
878877
/// An initializer for `T`.
879878
///
880879
/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
881-
/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Because [`PinInit<T, E>`] is a super trait, you can
880+
/// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`]. Use the [`InPlaceInit::init`] function of a smart
881+
/// pointer like [`Arc<T>`] on this. Because [`PinInit<T, E>`] is a super trait, you can
882882
/// use every function that takes it as well.
883883
///
884884
/// Also see the [module description](self).
@@ -903,7 +903,6 @@ pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
903903
/// move the pointee after initialization.
904904
///
905905
/// [`Arc<T>`]: crate::sync::Arc
906-
/// [`UniqueArc<T>`]: kernel::sync::UniqueArc
907906
#[must_use = "An initializer must be used in order to create its value."]
908907
pub unsafe trait Init<T: ?Sized, E = Infallible>: Sized {
909908
/// Initializes `slot`.
@@ -982,3 +981,106 @@ unsafe impl<T> Init<T> for T {
982981
Ok(())
983982
}
984983
}
984+
985+
/// Smart pointer that can initialize memory in-place.
986+
pub trait InPlaceInit<T>: Sized {
987+
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
988+
/// type.
989+
///
990+
/// If `T: !Unpin` it will not be able to move afterwards.
991+
fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
992+
where
993+
E: From<AllocError>;
994+
995+
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
996+
/// type.
997+
///
998+
/// If `T: !Unpin` it will not be able to move afterwards.
999+
fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Pin<Self>>
1000+
where
1001+
Error: From<E>,
1002+
{
1003+
// SAFETY: We delegate to `init` and only change the error type.
1004+
let init = unsafe {
1005+
pin_init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
1006+
};
1007+
Self::try_pin_init(init)
1008+
}
1009+
1010+
/// Use the given initializer to in-place initialize a `T`.
1011+
fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E>
1012+
where
1013+
E: From<AllocError>;
1014+
1015+
/// Use the given initializer to in-place initialize a `T`.
1016+
fn init<E>(init: impl Init<T, E>) -> error::Result<Self>
1017+
where
1018+
Error: From<E>,
1019+
{
1020+
// SAFETY: We delegate to `init` and only change the error type.
1021+
let init = unsafe {
1022+
init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
1023+
};
1024+
Self::try_init(init)
1025+
}
1026+
}
1027+
1028+
impl<T> InPlaceInit<T> for Box<T> {
1029+
#[inline]
1030+
fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
1031+
where
1032+
E: From<AllocError>,
1033+
{
1034+
let mut this = Box::try_new_uninit()?;
1035+
let slot = this.as_mut_ptr();
1036+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1037+
// slot is valid and will not be moved, because we pin it later.
1038+
unsafe { init.__pinned_init(slot)? };
1039+
// SAFETY: All fields have been initialized.
1040+
Ok(unsafe { this.assume_init() }.into())
1041+
}
1042+
1043+
#[inline]
1044+
fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E>
1045+
where
1046+
E: From<AllocError>,
1047+
{
1048+
let mut this = Box::try_new_uninit()?;
1049+
let slot = this.as_mut_ptr();
1050+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1051+
// slot is valid.
1052+
unsafe { init.__init(slot)? };
1053+
// SAFETY: All fields have been initialized.
1054+
Ok(unsafe { this.assume_init() })
1055+
}
1056+
}
1057+
1058+
impl<T> InPlaceInit<T> for UniqueArc<T> {
1059+
#[inline]
1060+
fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E>
1061+
where
1062+
E: From<AllocError>,
1063+
{
1064+
let mut this = UniqueArc::try_new_uninit()?;
1065+
let slot = this.as_mut_ptr();
1066+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1067+
// slot is valid and will not be moved, because we pin it later.
1068+
unsafe { init.__pinned_init(slot)? };
1069+
// SAFETY: All fields have been initialized.
1070+
Ok(unsafe { this.assume_init() }.into())
1071+
}
1072+
1073+
#[inline]
1074+
fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E>
1075+
where
1076+
E: From<AllocError>,
1077+
{
1078+
let mut this = UniqueArc::try_new_uninit()?;
1079+
let slot = this.as_mut_ptr();
1080+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1081+
// slot is valid.
1082+
unsafe { init.__init(slot)? };
1083+
// SAFETY: All fields have been initialized.
1084+
Ok(unsafe { this.assume_init() })
1085+
}
1086+
}

rust/kernel/sync/arc.rs

+24
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
1818
use crate::{
1919
bindings,
20+
error::{self, Error},
21+
init::{InPlaceInit, Init, PinInit},
2022
types::{ForeignOwnable, Opaque},
2123
};
2224
use alloc::boxed::Box;
@@ -166,6 +168,28 @@ impl<T> Arc<T> {
166168
// `Arc` object.
167169
Ok(unsafe { Self::from_inner(Box::leak(inner).into()) })
168170
}
171+
172+
/// Use the given initializer to in-place initialize a `T`.
173+
///
174+
/// If `T: !Unpin` it will not be able to move afterwards.
175+
#[inline]
176+
pub fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Self>
177+
where
178+
Error: From<E>,
179+
{
180+
UniqueArc::pin_init(init).map(|u| u.into())
181+
}
182+
183+
/// Use the given initializer to in-place initialize a `T`.
184+
///
185+
/// This is equivalent to [`pin_init`], since an [`Arc`] is always pinned.
186+
#[inline]
187+
pub fn init<E>(init: impl Init<T, E>) -> error::Result<Self>
188+
where
189+
Error: From<E>,
190+
{
191+
UniqueArc::init(init).map(|u| u.into())
192+
}
169193
}
170194

171195
impl<T: ?Sized> Arc<T> {

0 commit comments

Comments
 (0)