Skip to content

Commit 114ca41

Browse files
y86-devojeda
authored andcommittedMar 16, 2025
rust: pin-init: move InPlaceInit and impls of InPlaceWrite into the kernel crate
In order to make pin-init a standalone crate, move kernel-specific code directly into the kernel crate. This includes the `InPlaceInit<T>` trait, its implementations and the implementations of `InPlaceWrite` for `Arc` and `UniqueArc`. All of these use the kernel's error type which will become unavailable in pin-init. Signed-off-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Fiona Behrens <me@kloenk.dev> Tested-by: Andreas Hindborg <a.hindborg@kernel.org> Link: https://lore.kernel.org/r/20250308110339.2997091-9-benno.lossin@proton.me Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent 578eb8b commit 114ca41

File tree

5 files changed

+127
-124
lines changed

5 files changed

+127
-124
lines changed
 

‎rust/kernel/alloc/kbox.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ use core::pin::Pin;
1515
use core::ptr::NonNull;
1616
use core::result::Result;
1717

18-
use crate::init::{InPlaceInit, InPlaceWrite, Init, PinInit};
18+
use crate::init::{InPlaceWrite, Init, PinInit};
19+
use crate::init_ext::InPlaceInit;
1920
use crate::types::ForeignOwnable;
2021

2122
/// The kernel's [`Box`] type -- a heap allocation for a single value of type `T`.

‎rust/kernel/init.rs

+55
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,61 @@
134134
//! }
135135
//! ```
136136
137+
use crate::{
138+
alloc::{AllocError, Flags},
139+
error::{self, Error},
140+
init::{init_from_closure, pin_init_from_closure, Init, PinInit},
141+
};
142+
143+
/// Smart pointer that can initialize memory in-place.
144+
pub trait InPlaceInit<T>: Sized {
145+
/// Pinned version of `Self`.
146+
///
147+
/// If a type already implicitly pins its pointee, `Pin<Self>` is unnecessary. In this case use
148+
/// `Self`, otherwise just use `Pin<Self>`.
149+
type PinnedSelf;
150+
151+
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
152+
/// type.
153+
///
154+
/// If `T: !Unpin` it will not be able to move afterwards.
155+
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
156+
where
157+
E: From<AllocError>;
158+
159+
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
160+
/// type.
161+
///
162+
/// If `T: !Unpin` it will not be able to move afterwards.
163+
fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Self::PinnedSelf>
164+
where
165+
Error: From<E>,
166+
{
167+
// SAFETY: We delegate to `init` and only change the error type.
168+
let init = unsafe {
169+
pin_init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
170+
};
171+
Self::try_pin_init(init, flags)
172+
}
173+
174+
/// Use the given initializer to in-place initialize a `T`.
175+
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
176+
where
177+
E: From<AllocError>;
178+
179+
/// Use the given initializer to in-place initialize a `T`.
180+
fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
181+
where
182+
Error: From<E>,
183+
{
184+
// SAFETY: We delegate to `init` and only change the error type.
185+
let init = unsafe {
186+
init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
187+
};
188+
Self::try_init(init, flags)
189+
}
190+
}
191+
137192
/// Construct an in-place fallible initializer for `struct`s.
138193
///
139194
/// This macro defaults the error to [`Error`]. If you need [`Infallible`], then use

‎rust/kernel/prelude.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub use super::error::{code::*, Error, Result};
3636

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

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

4142
pub use super::current;

‎rust/kernel/sync/arc.rs

+64-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
use crate::{
2020
alloc::{AllocError, Flags, KBox},
2121
bindings,
22-
init::{self, InPlaceInit, Init, PinInit},
22+
init::{self, InPlaceWrite, Init, PinInit},
23+
init_ext::InPlaceInit,
2324
try_init,
2425
types::{ForeignOwnable, Opaque},
2526
};
@@ -202,6 +203,26 @@ unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
202203
// the reference count reaches zero and `T` is dropped.
203204
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
204205

206+
impl<T> InPlaceInit<T> for Arc<T> {
207+
type PinnedSelf = Self;
208+
209+
#[inline]
210+
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
211+
where
212+
E: From<AllocError>,
213+
{
214+
UniqueArc::try_pin_init(init, flags).map(|u| u.into())
215+
}
216+
217+
#[inline]
218+
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
219+
where
220+
E: From<AllocError>,
221+
{
222+
UniqueArc::try_init(init, flags).map(|u| u.into())
223+
}
224+
}
225+
205226
impl<T> Arc<T> {
206227
/// Constructs a new reference counted instance of `T`.
207228
pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
@@ -659,6 +680,48 @@ pub struct UniqueArc<T: ?Sized> {
659680
inner: Arc<T>,
660681
}
661682

683+
impl<T> InPlaceInit<T> for UniqueArc<T> {
684+
type PinnedSelf = Pin<Self>;
685+
686+
#[inline]
687+
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
688+
where
689+
E: From<AllocError>,
690+
{
691+
UniqueArc::new_uninit(flags)?.write_pin_init(init)
692+
}
693+
694+
#[inline]
695+
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
696+
where
697+
E: From<AllocError>,
698+
{
699+
UniqueArc::new_uninit(flags)?.write_init(init)
700+
}
701+
}
702+
703+
impl<T> InPlaceWrite<T> for UniqueArc<MaybeUninit<T>> {
704+
type Initialized = UniqueArc<T>;
705+
706+
fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
707+
let slot = self.as_mut_ptr();
708+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
709+
// slot is valid.
710+
unsafe { init.__init(slot)? };
711+
// SAFETY: All fields have been initialized.
712+
Ok(unsafe { self.assume_init() })
713+
}
714+
715+
fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
716+
let slot = self.as_mut_ptr();
717+
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
718+
// slot is valid and will not be moved, because we pin it later.
719+
unsafe { init.__pinned_init(slot)? };
720+
// SAFETY: All fields have been initialized.
721+
Ok(unsafe { self.assume_init() }.into())
722+
}
723+
}
724+
662725
impl<T> UniqueArc<T> {
663726
/// Tries to allocate a new [`UniqueArc`] instance.
664727
pub fn new(value: T, flags: Flags) -> Result<Self, AllocError> {

‎rust/pin-init/src/lib.rs

+4-121
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//! To initialize a `struct` with an in-place constructor you will need two things:
1111
//! - an in-place constructor,
1212
//! - a memory location that can hold your `struct` (this can be the [stack], an [`Arc<T>`],
13-
//! [`UniqueArc<T>`], [`KBox<T>`] or any other smart pointer that implements [`InPlaceInit`]).
13+
//! [`KBox<T>`] or any other smart pointer that supports this library).
1414
//!
1515
//! To get an in-place constructor there are generally three options:
1616
//! - directly creating an in-place constructor using the [`pin_init!`] macro,
@@ -212,10 +212,7 @@
212212
//! [`pin_init!`]: crate::pin_init!
213213
214214
use crate::{
215-
alloc::{AllocError, Flags, KBox},
216-
error::{self, Error},
217-
sync::Arc,
218-
sync::UniqueArc,
215+
alloc::KBox,
219216
types::{Opaque, ScopeGuard},
220217
};
221218
use core::{
@@ -891,8 +888,7 @@ macro_rules! assert_pinned {
891888
/// A pin-initializer for the type `T`.
892889
///
893890
/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
894-
/// be [`KBox<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use
895-
/// the [`InPlaceInit::pin_init`] function of a smart pointer like [`Arc<T>`] on this.
891+
/// be [`KBox<T>`], [`Arc<T>`] or even the stack (see [`stack_pin_init!`]).
896892
///
897893
/// Also see the [module description](self).
898894
///
@@ -910,7 +906,6 @@ macro_rules! assert_pinned {
910906
/// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`.
911907
///
912908
/// [`Arc<T>`]: crate::sync::Arc
913-
/// [`Arc::pin_init`]: crate::sync::Arc::pin_init
914909
#[must_use = "An initializer must be used in order to create its value."]
915910
pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized {
916911
/// Initializes `slot`.
@@ -976,8 +971,7 @@ where
976971
/// An initializer for `T`.
977972
///
978973
/// To use this initializer, you will need a suitable memory location that can hold a `T`. This can
979-
/// be [`KBox<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use
980-
/// the [`InPlaceInit::init`] function of a smart pointer like [`Arc<T>`] on this. Because
974+
/// be [`KBox<T>`], [`Arc<T>`] or even the stack (see [`stack_pin_init!`]). Because
981975
/// [`PinInit<T, E>`] is a super trait, you can use every function that takes it as well.
982976
///
983977
/// Also see the [module description](self).
@@ -1238,95 +1232,6 @@ unsafe impl<T, E> PinInit<T, E> for T {
12381232
}
12391233
}
12401234

1241-
/// Smart pointer that can initialize memory in-place.
1242-
pub trait InPlaceInit<T>: Sized {
1243-
/// Pinned version of `Self`.
1244-
///
1245-
/// If a type already implicitly pins its pointee, `Pin<Self>` is unnecessary. In this case use
1246-
/// `Self`, otherwise just use `Pin<Self>`.
1247-
type PinnedSelf;
1248-
1249-
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
1250-
/// type.
1251-
///
1252-
/// If `T: !Unpin` it will not be able to move afterwards.
1253-
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
1254-
where
1255-
E: From<AllocError>;
1256-
1257-
/// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this
1258-
/// type.
1259-
///
1260-
/// If `T: !Unpin` it will not be able to move afterwards.
1261-
fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> error::Result<Self::PinnedSelf>
1262-
where
1263-
Error: From<E>,
1264-
{
1265-
// SAFETY: We delegate to `init` and only change the error type.
1266-
let init = unsafe {
1267-
pin_init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
1268-
};
1269-
Self::try_pin_init(init, flags)
1270-
}
1271-
1272-
/// Use the given initializer to in-place initialize a `T`.
1273-
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
1274-
where
1275-
E: From<AllocError>;
1276-
1277-
/// Use the given initializer to in-place initialize a `T`.
1278-
fn init<E>(init: impl Init<T, E>, flags: Flags) -> error::Result<Self>
1279-
where
1280-
Error: From<E>,
1281-
{
1282-
// SAFETY: We delegate to `init` and only change the error type.
1283-
let init = unsafe {
1284-
init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e)))
1285-
};
1286-
Self::try_init(init, flags)
1287-
}
1288-
}
1289-
1290-
impl<T> InPlaceInit<T> for Arc<T> {
1291-
type PinnedSelf = Self;
1292-
1293-
#[inline]
1294-
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
1295-
where
1296-
E: From<AllocError>,
1297-
{
1298-
UniqueArc::try_pin_init(init, flags).map(|u| u.into())
1299-
}
1300-
1301-
#[inline]
1302-
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
1303-
where
1304-
E: From<AllocError>,
1305-
{
1306-
UniqueArc::try_init(init, flags).map(|u| u.into())
1307-
}
1308-
}
1309-
1310-
impl<T> InPlaceInit<T> for UniqueArc<T> {
1311-
type PinnedSelf = Pin<Self>;
1312-
1313-
#[inline]
1314-
fn try_pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self::PinnedSelf, E>
1315-
where
1316-
E: From<AllocError>,
1317-
{
1318-
UniqueArc::new_uninit(flags)?.write_pin_init(init)
1319-
}
1320-
1321-
#[inline]
1322-
fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
1323-
where
1324-
E: From<AllocError>,
1325-
{
1326-
UniqueArc::new_uninit(flags)?.write_init(init)
1327-
}
1328-
}
1329-
13301235
/// Smart pointer containing uninitialized memory and that can write a value.
13311236
pub trait InPlaceWrite<T> {
13321237
/// The type `Self` turns into when the contents are initialized.
@@ -1343,28 +1248,6 @@ pub trait InPlaceWrite<T> {
13431248
fn write_pin_init<E>(self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E>;
13441249
}
13451250

1346-
impl<T> InPlaceWrite<T> for UniqueArc<MaybeUninit<T>> {
1347-
type Initialized = UniqueArc<T>;
1348-
1349-
fn write_init<E>(mut self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
1350-
let slot = self.as_mut_ptr();
1351-
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1352-
// slot is valid.
1353-
unsafe { init.__init(slot)? };
1354-
// SAFETY: All fields have been initialized.
1355-
Ok(unsafe { self.assume_init() })
1356-
}
1357-
1358-
fn write_pin_init<E>(mut self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
1359-
let slot = self.as_mut_ptr();
1360-
// SAFETY: When init errors/panics, slot will get deallocated but not dropped,
1361-
// slot is valid and will not be moved, because we pin it later.
1362-
unsafe { init.__pinned_init(slot)? };
1363-
// SAFETY: All fields have been initialized.
1364-
Ok(unsafe { self.assume_init() }.into())
1365-
}
1366-
}
1367-
13681251
/// Trait facilitating pinned destruction.
13691252
///
13701253
/// Use [`pinned_drop`] to implement this trait safely:

0 commit comments

Comments
 (0)
Please sign in to comment.