Skip to content

Commit 9985762

Browse files
committed
rust: Added pinned-init API
This API is used to initialize pinned structs. Before we had to use `unsafe` to first call `Mutex::new` with the promise that we would call `Mutex::init` later (which also requires `unsafe`, because it first needs a pin-projection). This API merges those two functions into one such that it is now a safe operation for the user. It is implemented using a combination of things: - declarative macros used to create initializers (`pin_init!`/`init!`), - declarative macro used to inform about the pinned fields (`pin_project!`), - proc macro shim delegating to the previously mentioned declarative macro (the proc macro does a bit of generics parsing, it is `#[pin_project]`), - traits and a couple of functions to create basic initializers. For details, please read the documentation at [1]. Link: https://rust-for-linux.github.io/docs/kernel/init/index.html [1] Signed-off-by: Benno Lossin <[email protected]>
1 parent 2415d84 commit 9985762

File tree

10 files changed

+1614
-2
lines changed

10 files changed

+1614
-2
lines changed

rust/kernel/init.rs

Lines changed: 863 additions & 0 deletions
Large diffs are not rendered by default.

rust/kernel/init/__private.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Workaround for specialization
4+
5+
use super::*;
6+
use core::cell::Cell;
7+
8+
mod sealed {
9+
use super::*;
10+
pub trait Sealed {}
11+
12+
impl Sealed for Direct {}
13+
impl Sealed for Closure {}
14+
}
15+
16+
pub trait InitWay: sealed::Sealed {}
17+
18+
impl InitWay for Direct {}
19+
impl InitWay for Closure {}
20+
21+
pub struct Direct;
22+
pub struct Closure;
23+
24+
/// # Safety
25+
/// Same as [`PinInit`]
26+
pub unsafe trait __PinInitImpl<T: ?Sized, E, W: InitWay> {
27+
/// # Safety
28+
/// Same as [`PinInit::__pinned_init`]
29+
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>;
30+
}
31+
32+
/// # Safety
33+
/// Same as [`Init`]
34+
pub unsafe trait __InitImpl<T: ?Sized, E, W: InitWay>: __PinInitImpl<T, E, W> {
35+
/// # Safety
36+
/// Same as [`Init::__init`]
37+
unsafe fn __init(self, slot: *mut T) -> Result<(), E>;
38+
}
39+
40+
/// # Safety
41+
/// Only implemented by pin_data!
42+
pub unsafe trait __PinData {
43+
type __PinData;
44+
}
45+
46+
unsafe impl<T> __PinInitImpl<T, Infallible, Direct> for T {
47+
#[inline]
48+
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), Infallible> {
49+
// SAFETY: pointer valid as per function contract
50+
unsafe { slot.write(self) };
51+
Ok(())
52+
}
53+
}
54+
55+
unsafe impl<T> __InitImpl<T, Infallible, Direct> for T {
56+
#[inline]
57+
unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> {
58+
// SAFETY: pointer valid as per function contract
59+
unsafe { slot.write(self) };
60+
Ok(())
61+
}
62+
}
63+
64+
unsafe impl<I, T, E> __InitImpl<T, E, Closure> for I
65+
where
66+
I: Init<T, E>,
67+
{
68+
#[inline]
69+
unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
70+
unsafe { Init::__init(self, slot) }
71+
}
72+
}
73+
74+
unsafe impl<I, T, E> __PinInitImpl<T, E, Closure> for I
75+
where
76+
I: PinInit<T, E>,
77+
{
78+
#[inline]
79+
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
80+
unsafe { PinInit::__pinned_init(self, slot) }
81+
}
82+
}
83+
84+
/// When a value of this type is dropped, it drops something else.
85+
pub struct DropGuard<T: ?Sized>(*mut T, Cell<bool>);
86+
87+
impl<T: ?Sized> DropGuard<T> {
88+
/// Creates a new [`DropGuard<T>`]. It will [`ptr::drop_in_place`] `ptr` when it gets dropped.
89+
///
90+
/// # Safety
91+
/// `ptr` must be a valid poiner.
92+
///
93+
/// It is the callers responsibility that `self` will only get dropped if the pointee of `ptr`:
94+
/// - has not been dropped,
95+
/// - is not accesible by any other means,
96+
/// - will not be dropped by any other means.
97+
#[inline]
98+
pub unsafe fn new(ptr: *mut T) -> Self {
99+
Self(ptr, Cell::new(true))
100+
}
101+
102+
#[inline]
103+
pub unsafe fn forget(&self) {
104+
self.1.set(false);
105+
}
106+
}
107+
108+
impl<T: ?Sized> Drop for DropGuard<T> {
109+
#[inline]
110+
fn drop(&mut self) {
111+
if self.1.get() {
112+
// SAFETY: safe as a `DropGuard` can only be constructed using the unsafe new function.
113+
unsafe { ptr::drop_in_place(self.0) }
114+
}
115+
}
116+
}
117+
118+
/// Stack initializer helper type. See [`stack_init`].
119+
pub struct StackInit<T>(MaybeUninit<T>, bool);
120+
121+
impl<T> Drop for StackInit<T> {
122+
#[inline]
123+
fn drop(&mut self) {
124+
if self.1 {
125+
unsafe { self.0.assume_init_drop() };
126+
}
127+
}
128+
}
129+
impl<T> StackInit<T> {
130+
#[inline]
131+
pub fn uninit() -> Self {
132+
Self(MaybeUninit::uninit(), false)
133+
}
134+
135+
/// # Safety
136+
/// The caller ensures that `self` is on the stack and not accesible to **any** other code.
137+
#[inline]
138+
pub unsafe fn init<E>(&mut self, init: impl PinInit<T, E>) -> Result<Pin<&mut T>, E> {
139+
unsafe { init.__pinned_init(self.0.as_mut_ptr()) }?;
140+
self.1 = true;
141+
Ok(unsafe { Pin::new_unchecked(self.0.assume_init_mut()) })
142+
}
143+
}

0 commit comments

Comments
 (0)