Skip to content

Commit eeddb87

Browse files
committed
rust: experiment with #[derive(SmartPointer)]
I am sending this RFC patch to share my experience with using the new `#[derive(SmartPointer)]` feature [1] with our custom smart pointers. The feature is being added so that the kernel can stop using the unstable dispatch_from_dyn and unsize features. In general, the feature appears to work. As can be seen in the change to `rust_minimal.rs`, it is possible to use `Arc` together with a dynamic trait object, and the trait object is object safe even though it uses the custom smart pointer as a self parameter. I did run into one nit, which is that `Arc` requires the `#[pointee]` annotation even though there's only one generic paramter. I filed an issue [2] about this. Link: https://rust-lang.github.io/rfcs/3621-derive-smart-pointer.html [1] Link: rust-lang/rust#129465 [2] Signed-off-by: Alice Ryhl <[email protected]>
1 parent b204bbc commit eeddb87

File tree

4 files changed

+26
-39
lines changed

4 files changed

+26
-39
lines changed

rust/kernel/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@
1313
1414
#![no_std]
1515
#![feature(coerce_unsized)]
16-
#![feature(dispatch_from_dyn)]
16+
#![feature(derive_smart_pointer)]
1717
#![feature(new_uninit)]
1818
#![feature(receiver_trait)]
19-
#![feature(unsize)]
2019

2120
// Ensure conditional compilation based on the kernel configuration works;
2221
// otherwise we may silently break things like initcall handling.

rust/kernel/list/arc.rs

+3-20
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::alloc::{AllocError, Flags};
88
use crate::prelude::*;
99
use crate::sync::{Arc, ArcBorrow, UniqueArc};
10-
use core::marker::{PhantomPinned, Unsize};
10+
use core::marker::{PhantomPinned, SmartPointer};
1111
use core::ops::Deref;
1212
use core::pin::Pin;
1313
use core::sync::atomic::{AtomicBool, Ordering};
@@ -158,8 +158,9 @@ pub use impl_list_arc_safe;
158158
/// * The tracking inside `T` is aware that a `ListArc` reference exists.
159159
///
160160
/// [`List`]: crate::list::List
161+
#[derive(SmartPointer)]
161162
#[repr(transparent)]
162-
pub struct ListArc<T, const ID: u64 = 0>
163+
pub struct ListArc<#[pointee] T, const ID: u64 = 0>
163164
where
164165
T: ListArcSafe<ID> + ?Sized,
165166
{
@@ -444,24 +445,6 @@ where
444445
// This is to allow [`ListArc`] (and variants) to be used as the type of `self`.
445446
impl<T, const ID: u64> core::ops::Receiver for ListArc<T, ID> where T: ListArcSafe<ID> + ?Sized {}
446447

447-
// This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the
448-
// dynamically-sized type (DST) `U`.
449-
impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID>
450-
where
451-
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
452-
U: ListArcSafe<ID> + ?Sized,
453-
{
454-
}
455-
456-
// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into
457-
// `ListArc<U>`.
458-
impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID>
459-
where
460-
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
461-
U: ListArcSafe<ID> + ?Sized,
462-
{
463-
}
464-
465448
/// A utility for tracking whether a [`ListArc`] exists using an atomic.
466449
///
467450
/// # Invariant

rust/kernel/sync/arc.rs

+7-17
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use alloc::boxed::Box;
2727
use core::{
2828
alloc::Layout,
2929
fmt,
30-
marker::{PhantomData, Unsize},
30+
marker::{PhantomData, SmartPointer},
3131
mem::{ManuallyDrop, MaybeUninit},
3232
ops::{Deref, DerefMut},
3333
pin::Pin,
@@ -126,7 +126,9 @@ mod std_vendor;
126126
/// let coerced: Arc<dyn MyTrait> = obj;
127127
/// # Ok::<(), Error>(())
128128
/// ```
129-
pub struct Arc<T: ?Sized> {
129+
#[derive(SmartPointer)]
130+
#[repr(transparent)]
131+
pub struct Arc<#[pointee] T: ?Sized> {
130132
ptr: NonNull<ArcInner<T>>,
131133
_p: PhantomData<ArcInner<T>>,
132134
}
@@ -174,13 +176,6 @@ impl<T: ?Sized> ArcInner<T> {
174176
// This is to allow [`Arc`] (and variants) to be used as the type of `self`.
175177
impl<T: ?Sized> core::ops::Receiver for Arc<T> {}
176178

177-
// This is to allow coercion from `Arc<T>` to `Arc<U>` if `T` can be converted to the
178-
// dynamically-sized type (DST) `U`.
179-
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::CoerceUnsized<Arc<U>> for Arc<T> {}
180-
181-
// This is to allow `Arc<U>` to be dispatched on when `Arc<T>` can be coerced into `Arc<U>`.
182-
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<Arc<U>> for Arc<T> {}
183-
184179
// SAFETY: It is safe to send `Arc<T>` to another thread when the underlying `T` is `Sync` because
185180
// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
186181
// `T` to be `Send` because any thread that has an `Arc<T>` may ultimately access `T` using a
@@ -475,21 +470,16 @@ impl<T: ?Sized> From<Pin<UniqueArc<T>>> for Arc<T> {
475470
/// obj.as_arc_borrow().use_reference();
476471
/// # Ok::<(), Error>(())
477472
/// ```
478-
pub struct ArcBorrow<'a, T: ?Sized + 'a> {
473+
#[derive(SmartPointer)]
474+
#[repr(transparent)]
475+
pub struct ArcBorrow<'a, #[pointee] T: ?Sized + 'a> {
479476
inner: NonNull<ArcInner<T>>,
480477
_p: PhantomData<&'a ()>,
481478
}
482479

483480
// This is to allow [`ArcBorrow`] (and variants) to be used as the type of `self`.
484481
impl<T: ?Sized> core::ops::Receiver for ArcBorrow<'_, T> {}
485482

486-
// This is to allow `ArcBorrow<U>` to be dispatched on when `ArcBorrow<T>` can be coerced into
487-
// `ArcBorrow<U>`.
488-
impl<T: ?Sized + Unsize<U>, U: ?Sized> core::ops::DispatchFromDyn<ArcBorrow<'_, U>>
489-
for ArcBorrow<'_, T>
490-
{
491-
}
492-
493483
impl<T: ?Sized> Clone for ArcBorrow<'_, T> {
494484
fn clone(&self) -> Self {
495485
*self

samples/rust/rust_minimal.rs

+15
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! Rust minimal sample.
44
55
use kernel::prelude::*;
6+
use kernel::sync::Arc;
67

78
module! {
89
type: RustMinimal,
@@ -16,6 +17,15 @@ struct RustMinimal {
1617
numbers: Vec<i32>,
1718
}
1819

20+
trait MyTrait {
21+
fn my_fn(self: Arc<Self>);
22+
}
23+
impl MyTrait for Vec<i32> {
24+
fn my_fn(self: Arc<Self>) {
25+
pr_info!("{:?}", self.as_slice());
26+
}
27+
}
28+
1929
impl kernel::Module for RustMinimal {
2030
fn init(_module: &'static ThisModule) -> Result<Self> {
2131
pr_info!("Rust minimal sample (init)\n");
@@ -26,6 +36,11 @@ impl kernel::Module for RustMinimal {
2636
numbers.push(108, GFP_KERNEL)?;
2737
numbers.push(200, GFP_KERNEL)?;
2838

39+
let in_arc = kernel::sync::Arc::new(numbers)?;
40+
in_arc.my_fn();
41+
let arc_dyn: Arc<dyn MyTrait> = in_arc;
42+
arc_dyn.my_fn();
43+
2944
Ok(RustMinimal { numbers })
3045
}
3146
}

0 commit comments

Comments
 (0)