Skip to content

Commit 405ef19

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 7f2f384 commit 405ef19

File tree

2 files changed

+61
-25
lines changed

2 files changed

+61
-25
lines changed

rust/kernel/init.rs

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

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

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

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

rust/kernel/prelude.rs

+1-1
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)