Skip to content

Commit acd41dd

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 fd5a9cc commit acd41dd

File tree

10 files changed

+1573
-2
lines changed

10 files changed

+1573
-2
lines changed

rust/kernel/init.rs

+846
Large diffs are not rendered by default.

rust/kernel/init/__private.rs

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
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+
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), Infallible> {
48+
// SAFETY: pointer valid as per function contract
49+
unsafe { slot.write(self) };
50+
Ok(())
51+
}
52+
}
53+
54+
unsafe impl<T> __InitImpl<T, Infallible, Direct> for T {
55+
unsafe fn __init(self, slot: *mut T) -> Result<(), Infallible> {
56+
// SAFETY: pointer valid as per function contract
57+
unsafe { slot.write(self) };
58+
Ok(())
59+
}
60+
}
61+
62+
unsafe impl<I, T, E> __InitImpl<T, E, Closure> for I
63+
where
64+
I: Init<T, E>,
65+
{
66+
unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
67+
unsafe { Init::__init(self, slot) }
68+
}
69+
}
70+
71+
unsafe impl<I, T, E> __PinInitImpl<T, E, Closure> for I
72+
where
73+
I: PinInit<T, E>,
74+
{
75+
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
76+
unsafe { PinInit::__pinned_init(self, slot) }
77+
}
78+
}
79+
80+
/// When a value of this type is dropped, it drops something else.
81+
pub struct DropGuard<T: ?Sized>(*mut T, Cell<bool>);
82+
83+
impl<T: ?Sized> DropGuard<T> {
84+
/// Creates a new [`DropGuard<T>`]. It will [`ptr::drop_in_place`] `ptr` when it gets dropped.
85+
///
86+
/// # Safety
87+
/// `ptr` must be a valid poiner.
88+
///
89+
/// It is the callers responsibility that `self` will only get dropped if the pointee of `ptr`:
90+
/// - has not been dropped,
91+
/// - is not accesible by any other means,
92+
/// - will not be dropped by any other means.
93+
pub unsafe fn new(ptr: *mut T) -> Self {
94+
Self(ptr, Cell::new(true))
95+
}
96+
97+
pub unsafe fn forget(&self) {
98+
self.1.set(false);
99+
}
100+
}
101+
102+
impl<T: ?Sized> Drop for DropGuard<T> {
103+
fn drop(&mut self) {
104+
if self.1.get() {
105+
// SAFETY: safe as a `DropGuard` can only be constructed using the unsafe new function.
106+
unsafe { ptr::drop_in_place(self.0) }
107+
}
108+
}
109+
}
110+
111+
/// Stack initializer helper type. See [`stack_init`].
112+
pub struct StackInit<T>(MaybeUninit<T>, bool);
113+
114+
impl<T> Drop for StackInit<T> {
115+
fn drop(&mut self) {
116+
if self.1 {
117+
unsafe { self.0.assume_init_drop() };
118+
}
119+
}
120+
}
121+
impl<T> StackInit<T> {
122+
pub fn uninit() -> Self {
123+
Self(MaybeUninit::uninit(), false)
124+
}
125+
126+
/// # Safety
127+
/// The caller ensures that `self` is on the stack and not accesible to **any** other code.
128+
pub unsafe fn init<E>(&mut self, init: impl PinInit<T, E>) -> Result<Pin<&mut T>, E> {
129+
unsafe { init.__pinned_init(self.0.as_mut_ptr()) }?;
130+
self.1 = true;
131+
Ok(unsafe { Pin::new_unchecked(self.0.assume_init_mut()) })
132+
}
133+
}

0 commit comments

Comments
 (0)