Skip to content

Commit 9df2572

Browse files
y86-devfbq
authored andcommitted
rust: init: add write_[pin_]init 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 `write_[pin_]init` functions to the pin-init API. These functions operate on already allocated smart pointers that wrap `MaybeUninit<T>`. Signed-off-by: Benno Lossin <[email protected]> Link: https://lore.kernel.org/rust-for-linux/[email protected]/ [1] Link: https://lore.kernel.org/r/[email protected]
1 parent 306bd17 commit 9df2572

File tree

2 files changed

+61
-25
lines changed

2 files changed

+61
-25
lines changed

rust/kernel/init.rs

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,27 +1154,15 @@ impl<T> InPlaceInit<T> for Box<T> {
11541154
where
11551155
E: From<AllocError>,
11561156
{
1157-
let mut this = <Box<_> as BoxExt<_>>::new_uninit(flags)?;
1158-
let slot = this.as_mut_ptr();
1159-
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1160-
// slot is valid and will not be moved, because we pin it later.
1161-
unsafe { init.__pinned_init(slot)? };
1162-
// SAFETY: All fields have been initialized.
1163-
Ok(unsafe { this.assume_init() }.into())
1157+
<Box<_> as BoxExt<_>>::new_uninit(flags)?.write_pin_init(init)
11641158
}
11651159

11661160
#[inline]
11671161
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
11681162
where
11691163
E: From<AllocError>,
11701164
{
1171-
let mut this = <Box<_> as BoxExt<_>>::new_uninit(flags)?;
1172-
let slot = this.as_mut_ptr();
1173-
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1174-
// slot is valid.
1175-
unsafe { init.__init(slot)? };
1176-
// SAFETY: All fields have been initialized.
1177-
Ok(unsafe { this.assume_init() })
1165+
<Box<_> as BoxExt<_>>::new_uninit(flags)?.write_init(init)
11781166
}
11791167
}
11801168

@@ -1184,27 +1172,75 @@ impl<T> InPlaceInit<T> for UniqueArc<T> {
11841172
where
11851173
E: From<AllocError>,
11861174
{
1187-
let mut this = UniqueArc::new_uninit(flags)?;
1188-
let slot = this.as_mut_ptr();
1189-
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1190-
// slot is valid and will not be moved, because we pin it later.
1191-
unsafe { init.__pinned_init(slot)? };
1192-
// SAFETY: All fields have been initialized.
1193-
Ok(unsafe { this.assume_init() }.into())
1175+
UniqueArc::new_uninit(flags)?.write_pin_init(init)
11941176
}
11951177

11961178
#[inline]
11971179
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
11981180
where
11991181
E: From<AllocError>,
12001182
{
1201-
let mut this = UniqueArc::new_uninit(flags)?;
1202-
let slot = this.as_mut_ptr();
1183+
UniqueArc::new_uninit(flags)?.write_init(init)
1184+
}
1185+
}
1186+
1187+
/// Smart pointer containing uninitialized memory and that can write a value.
1188+
pub trait InPlaceWrite<T> {
1189+
/// The type `Self` turns into when the contents are initialized.
1190+
type Initialized;
1191+
1192+
/// Use the given initializer to write a value into `self`.
1193+
///
1194+
/// Does not drop the current value and considers it as uninitialized memory.
1195+
fn write_init<E>(self, init: impl Init<T, E>) -> Result<Self::Initialized, E>;
1196+
1197+
/// Use the given pin-initializer to write a value into `self`.
1198+
///
1199+
/// Does not drop the current value and considers it as uninitialized memory.
1200+
fn write_pin_init<E>(self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E>;
1201+
}
1202+
1203+
impl<T> InPlaceWrite<T> for Box<MaybeUninit<T>> {
1204+
type Initialized = Box<T>;
1205+
1206+
fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
1207+
let slot = self.as_mut_ptr();
12031208
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
12041209
// slot is valid.
12051210
unsafe { init.__init(slot)? };
12061211
// SAFETY: All fields have been initialized.
1207-
Ok(unsafe { this.assume_init() })
1212+
Ok(unsafe { self.assume_init() })
1213+
}
1214+
1215+
fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
1216+
let slot = self.as_mut_ptr();
1217+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1218+
// slot is valid and will not be moved, because we pin it later.
1219+
unsafe { init.__pinned_init(slot)? };
1220+
// SAFETY: All fields have been initialized.
1221+
Ok(unsafe { self.assume_init() }.into())
1222+
}
1223+
}
1224+
1225+
impl<T> InPlaceWrite<T> for UniqueArc<MaybeUninit<T>> {
1226+
type Initialized = UniqueArc<T>;
1227+
1228+
fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
1229+
let slot = self.as_mut_ptr();
1230+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1231+
// slot is valid.
1232+
unsafe { init.__init(slot)? };
1233+
// SAFETY: All fields have been initialized.
1234+
Ok(unsafe { self.assume_init() })
1235+
}
1236+
1237+
fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
1238+
let slot = self.as_mut_ptr();
1239+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1240+
// slot is valid and will not be moved, because we pin it later.
1241+
unsafe { init.__pinned_init(slot)? };
1242+
// SAFETY: All fields have been initialized.
1243+
Ok(unsafe { self.assume_init() }.into())
12081244
}
12091245
}
12101246

rust/kernel/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ pub use super::error::{code::*, Error, Result};
3737

3838
pub use super::{str::CStr, ThisModule};
3939

40-
pub use super::init::{InPlaceInit, Init, PinInit};
40+
pub use super::init::{InPlaceInit, InPlaceWrite, Init, PinInit};
4141

4242
pub use super::current;

0 commit comments

Comments
 (0)