Skip to content

Commit a7b2873

Browse files
committed
rust: list: add ListArc
The `ListArc` type can be thought of as a special reference to a refcounted object that owns the permission to manipulate the `next`/`prev` pointers stored in the refcounted object. By ensuring that each object has only one `ListArc` reference, the owner of that reference is assured exclusive access to the `next`/`prev` pointers. When a `ListArc` is inserted into a `List`, the `List` takes ownership of the `ListArc` reference. There are various strategies for ensuring that a value has only one `ListArc` reference. The simplest is to convert a `UniqueArc` into a `ListArc`. However, the refcounted object could also keep track of whether a `ListArc` exists using a boolean, which could allow for the creation of new `ListArc` references from an `Arc` reference. Whatever strategy is used, the relevant tracking is referred to as "the tracking inside `T`", and the `ListArcSafe` trait (and its subtraits) are used to update the tracking when a `ListArc` is created or destroyed. Note that we allow the case where the tracking inside `T` thinks that a `ListArc` exists, but actually, there isn't a `ListArc`. However, we do not allow the opposite situation where a `ListArc` exists, but the tracking thinks it doesn't. This is because the former can at most result in us failing to create a `ListArc` when the operation could succeed, whereas the latter can result in the creation of two `ListArc` references. This patch introduces the `impl_list_arc_safe!` macro that allows you to implement `ListArcSafe` for types using the strategy where a `ListArc` can only be created from a `UniqueArc`. Other strategies are introduced in later patches. This is part of the linked list that Rust Binder will use for many different things. The strategy where a `ListArc` can only be created from a `UniqueArc` is actually sufficient for most of the objects that Rust Binder needs to insert into linked lists. Usually, these are todo items that are created and then immediately inserted into a queue. The const generic ID allows objects to have several prev/next pointer pairs so that the same object can be inserted into several different lists. You are able to have several `ListArc` references as long as they correspond to different pointer pairs. The ID itself is purely a compile-time concept and will not be present in the final binary. Both the `List` and the `ListArc` will need to agree on the ID for them to work together. Rust Binder uses this in a few places (e.g. death recipients) where the same object can be inserted into both generic todo lists and some other lists for tracking the status of the object. The ID is a const generic rather than a type parameter because the `pair_from_unique` method needs to be able to assert that the two ids are different. There's no easy way to assert that when using types instead of integers. Signed-off-by: Alice Ryhl <[email protected]>
1 parent c61cdbc commit a7b2873

File tree

3 files changed

+324
-0
lines changed

3 files changed

+324
-0
lines changed

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub mod init;
3333
pub mod ioctl;
3434
#[cfg(CONFIG_KUNIT)]
3535
pub mod kunit;
36+
pub mod list;
3637
#[cfg(CONFIG_NET)]
3738
pub mod net;
3839
pub mod prelude;

rust/kernel/list.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
// Copyright (C) 2024 Google LLC.
4+
5+
//! A linked list implementation.
6+
7+
mod arc;
8+
pub use self::arc::{impl_list_arc_safe, ListArc, ListArcSafe};

rust/kernel/list/arc.rs

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
// Copyright (C) 2024 Google LLC.
4+
5+
//! A wrapper around `Arc` for linked lists.
6+
7+
use crate::alloc::{AllocError, Flags};
8+
use crate::prelude::*;
9+
use crate::sync::{Arc, ArcBorrow, UniqueArc};
10+
use core::marker::Unsize;
11+
use core::ops::Deref;
12+
use core::pin::Pin;
13+
14+
/// Declares that this type has some way to ensure that there is exactly one `ListArc` instance for
15+
/// this id.
16+
pub trait ListArcSafe<const ID: u64 = 0> {
17+
/// Informs the tracking inside this type that it now has a [`ListArc`] reference.
18+
///
19+
/// This method may be called even if the tracking inside this type thinks that a `ListArc`
20+
/// reference exists. (But only if that's not actually the case.)
21+
///
22+
/// # Safety
23+
///
24+
/// Must not be called if a [`ListArc`] already exist for this value.
25+
unsafe fn on_create_list_arc_from_unique(self: Pin<&mut Self>);
26+
27+
/// Informs the tracking inside this type that there is no [`ListArc`] reference anymore.
28+
///
29+
/// # Safety
30+
///
31+
/// Must only be called if there is no [`ListArc`] reference, but the tracking thinks there is.
32+
unsafe fn on_drop_list_arc(&self);
33+
}
34+
35+
/// Declares that this type supports [`ListArc`].
36+
///
37+
/// When using this macro, it will only be possible to create a [`ListArc`] from a [`UniqueArc`].
38+
#[macro_export]
39+
macro_rules! impl_list_arc_safe {
40+
(impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty { untracked; } $($rest:tt)*) => {
41+
impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t {
42+
unsafe fn on_create_list_arc_from_unique(self: ::core::pin::Pin<&mut Self>) {}
43+
unsafe fn on_drop_list_arc(&self) {}
44+
}
45+
$crate::list::impl_list_arc_safe! { $($rest)* }
46+
};
47+
48+
() => {};
49+
}
50+
pub use impl_list_arc_safe;
51+
52+
/// A wrapper around [`Arc`] that's guaranteed unique for the given id.
53+
///
54+
/// The `ListArc` type can be thought of as a special reference to a refcounted object that owns the
55+
/// permission to manipulate the `next`/`prev` pointers stored in the refcounted object. By ensuring
56+
/// that each object has only one `ListArc` reference, the owner of that reference is assured
57+
/// exclusive access to the `next`/`prev` pointers. When a `ListArc` is inserted into a `List`, the
58+
/// `List` takes ownership of the `ListArc` reference.
59+
///
60+
/// There are various strategies to ensuring that a value has only one `ListArc` reference. The
61+
/// simplest is to convert a [`UniqueArc`] into a `ListArc`. However, the refcounted object could
62+
/// also keep track of whether a `ListArc` exists using a boolean, which could allow for the
63+
/// creation of new `ListArc` references from an [`Arc`] reference. Whatever strategy is used, the
64+
/// relevant tracking is referred to as "the tracking inside `T`", and the [`ListArcSafe`] trait
65+
/// (and its subtraits) are used to update the tracking when a `ListArc` is created or destroyed.
66+
///
67+
/// Note that we allow the case where the tracking inside `T` thinks that a `ListArc` exists, but
68+
/// actually, there isn't a `ListArc`. However, we do not allow the opposite situation where a
69+
/// `ListArc` exists, but the tracking thinks it doesn't. This is because the former can at most
70+
/// result in us failing to create a `ListArc` when the operation could succeed, whereas the latter
71+
/// can result in the creation of two `ListArc` references.
72+
///
73+
/// # Invariants
74+
///
75+
/// * Each reference counted object has at most one `ListArc` for each value of `ID`.
76+
/// * The tracking inside `T` is aware that a `ListArc` reference exists.
77+
#[repr(transparent)]
78+
pub struct ListArc<T, const ID: u64 = 0>
79+
where
80+
T: ListArcSafe<ID> + ?Sized,
81+
{
82+
arc: Arc<T>,
83+
}
84+
85+
impl<T: ListArcSafe<ID>, const ID: u64> ListArc<T, ID> {
86+
/// Constructs a new reference counted instance of `T`.
87+
#[inline]
88+
pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
89+
Ok(Self::from_unique(UniqueArc::new(contents, flags)?))
90+
}
91+
92+
/// Use the given initializer to in-place initialize a `T`.
93+
///
94+
/// If `T: !Unpin` it will not be able to move afterwards.
95+
// We don't implement `InPlaceInit` because `ListArc` is implicitly pinned. This is similar to
96+
// what we do for `Arc`.
97+
#[inline]
98+
pub fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self, E>
99+
where
100+
E: From<AllocError>,
101+
{
102+
Ok(Self::from_pin_unique(UniqueArc::try_pin_init(init, flags)?))
103+
}
104+
105+
/// Use the given initializer to in-place initialize a `T`.
106+
///
107+
/// This is equivalent to [`ListArc<T>::pin_init`], since a [`ListArc`] is always pinned.
108+
#[inline]
109+
pub fn init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
110+
where
111+
E: From<AllocError>,
112+
{
113+
Ok(Self::from_unique(UniqueArc::try_init(init, flags)?))
114+
}
115+
}
116+
117+
impl<T, const ID: u64> ListArc<T, ID>
118+
where
119+
T: ListArcSafe<ID> + ?Sized,
120+
{
121+
/// Convert a [`UniqueArc`] into a [`ListArc`].
122+
#[inline]
123+
pub fn from_unique(unique: UniqueArc<T>) -> Self {
124+
Self::from_pin_unique(Pin::from(unique))
125+
}
126+
127+
/// Convert a pinned [`UniqueArc`] into a [`ListArc`].
128+
#[inline]
129+
pub fn from_pin_unique(mut unique: Pin<UniqueArc<T>>) -> Self {
130+
// SAFETY: We have a `UniqueArc`, so there is no `ListArc`.
131+
unsafe { T::on_create_list_arc_from_unique(unique.as_mut()) };
132+
let arc = Arc::from(unique);
133+
// SAFETY: We just called `on_create_list_arc_from_unique` on an arc without a `ListArc`,
134+
// so we can create a `ListArc`.
135+
unsafe { Self::transmute_from_arc(arc) }
136+
}
137+
138+
/// Like [`from_unique`], but creates two `ListArcs`.
139+
///
140+
/// The two ids must be different.
141+
///
142+
/// [`from_unique`]: ListArc::from_unique
143+
#[inline]
144+
pub fn pair_from_unique<const ID2: u64>(unique: UniqueArc<T>) -> (Self, ListArc<T, ID2>)
145+
where
146+
T: ListArcSafe<ID2>,
147+
{
148+
Self::pair_from_pin_unique(Pin::from(unique))
149+
}
150+
151+
/// Like [`pair_from_unique`], but uses a pinned arc.
152+
///
153+
/// The two ids must be different.
154+
///
155+
/// [`pair_from_unique`]: ListArc::pair_from_unique
156+
#[inline]
157+
pub fn pair_from_pin_unique<const ID2: u64>(
158+
mut unique: Pin<UniqueArc<T>>,
159+
) -> (Self, ListArc<T, ID2>)
160+
where
161+
T: ListArcSafe<ID2>,
162+
{
163+
build_assert!(ID != ID2);
164+
165+
// SAFETY: We have a `UniqueArc`, so there is no `ListArc`.
166+
unsafe { <T as ListArcSafe<ID>>::on_create_list_arc_from_unique(unique.as_mut()) };
167+
// SAFETY: We have a `UniqueArc`, so there is no `ListArc`.
168+
unsafe { <T as ListArcSafe<ID2>>::on_create_list_arc_from_unique(unique.as_mut()) };
169+
170+
let arc1 = Arc::from(unique);
171+
let arc2 = Arc::clone(&arc1);
172+
173+
// SAFETY: We just called `on_create_list_arc_from_unique` on an arc without a `ListArc`
174+
// for both IDs (which are different), so we can create two `ListArc`s.
175+
unsafe {
176+
(
177+
Self::transmute_from_arc(arc1),
178+
ListArc::transmute_from_arc(arc2),
179+
)
180+
}
181+
}
182+
183+
/// Transmutes an [`Arc`] into a `ListArc` without updating the tracking inside `T`.
184+
///
185+
/// # Safety
186+
///
187+
/// * The value must not already have a `ListArc` reference.
188+
/// * The tracking inside `T` must think that there is a `ListArc` reference.
189+
#[inline]
190+
unsafe fn transmute_from_arc(arc: Arc<T>) -> Self {
191+
// INVARIANT: By the safety requirements, the invariants on `ListArc` are satisfied.
192+
Self { arc }
193+
}
194+
195+
/// Transmutes a `ListArc` into an [`Arc`] without updating the tracking inside `T`.
196+
///
197+
/// After this call, the tracking inside `T` will still think that there is a `ListArc`
198+
/// reference.
199+
#[inline]
200+
fn transmute_to_arc(self) -> Arc<T> {
201+
// SAFETY: ListArc is repr(transparent).
202+
unsafe { core::mem::transmute(self) }
203+
}
204+
205+
/// Convert ownership of this `ListArc` into a raw pointer.
206+
///
207+
/// The returned pointer is indistinguishable from pointers returned by [`Arc::into_raw`]. The
208+
/// tracking inside `T` will still think that a `ListArc` exists after this call.
209+
#[inline]
210+
pub fn into_raw(self) -> *const T {
211+
Arc::into_raw(Self::transmute_to_arc(self))
212+
}
213+
214+
/// Take ownership of the `ListArc` from a raw pointer.
215+
///
216+
/// # Safety
217+
///
218+
/// * `ptr` must satisfy the safety requirements of [`Arc::from_raw`].
219+
/// * The value must not already have a `ListArc` reference.
220+
/// * The tracking inside `T` must think that there is a `ListArc` reference.
221+
#[inline]
222+
pub unsafe fn from_raw(ptr: *const T) -> Self {
223+
// SAFETY: The pointer satisfies the safety requirements for `Arc::from_raw`.
224+
let arc = unsafe { Arc::from_raw(ptr) };
225+
// SAFETY: The value doesn't already have a `ListArc` reference, but the tracking thinks it
226+
// does.
227+
unsafe { Self::transmute_from_arc(arc) }
228+
}
229+
230+
/// Converts the `ListArc` into an [`Arc`].
231+
#[inline]
232+
pub fn into_arc(self) -> Arc<T> {
233+
let arc = Self::transmute_to_arc(self);
234+
// SAFETY: There is no longer a `ListArc`, but the tracking thinks there is.
235+
unsafe { T::on_drop_list_arc(&arc) };
236+
arc
237+
}
238+
239+
/// Clone a `ListArc` into an [`Arc`].
240+
#[inline]
241+
pub fn clone_arc(&self) -> Arc<T> {
242+
self.arc.clone()
243+
}
244+
245+
/// Returns a reference to an [`Arc`] from the given [`ListArc`].
246+
///
247+
/// This is useful when the argument of a function call is an [`&Arc`] (e.g., in a method
248+
/// receiver), but we have a [`ListArc`] instead.
249+
///
250+
/// [`&Arc`]: Arc
251+
#[inline]
252+
pub fn as_arc(&self) -> &Arc<T> {
253+
&self.arc
254+
}
255+
256+
/// Returns an [`ArcBorrow`] from the given [`ListArc`].
257+
///
258+
/// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method
259+
/// receiver), but we have an [`Arc`] instead. Getting an [`ArcBorrow`] is free when optimised.
260+
#[inline]
261+
pub fn as_arc_borrow(&self) -> ArcBorrow<'_, T> {
262+
self.arc.as_arc_borrow()
263+
}
264+
265+
/// Compare whether two [`ListArc`] pointers reference the same underlying object.
266+
#[inline]
267+
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
268+
Arc::ptr_eq(&this.arc, &other.arc)
269+
}
270+
}
271+
272+
impl<T, const ID: u64> Deref for ListArc<T, ID>
273+
where
274+
T: ListArcSafe<ID> + ?Sized,
275+
{
276+
type Target = T;
277+
278+
#[inline]
279+
fn deref(&self) -> &Self::Target {
280+
self.arc.deref()
281+
}
282+
}
283+
284+
impl<T, const ID: u64> Drop for ListArc<T, ID>
285+
where
286+
T: ListArcSafe<ID> + ?Sized,
287+
{
288+
#[inline]
289+
fn drop(&mut self) {
290+
// SAFETY: There is no longer a `ListArc`, but the tracking thinks there is by the type
291+
// invariants on `Self`.
292+
unsafe { T::on_drop_list_arc(&self.arc) };
293+
}
294+
}
295+
296+
// This is to allow [`ListArc`] (and variants) to be used as the type of `self`.
297+
impl<T, const ID: u64> core::ops::Receiver for ListArc<T, ID> where T: ListArcSafe<ID> + ?Sized {}
298+
299+
// This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the
300+
// dynamically-sized type (DST) `U`.
301+
impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID>
302+
where
303+
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
304+
U: ListArcSafe<ID> + ?Sized,
305+
{
306+
}
307+
308+
// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into
309+
// `ListArc<U>`.
310+
impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID>
311+
where
312+
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
313+
U: ListArcSafe<ID> + ?Sized,
314+
{
315+
}

0 commit comments

Comments
 (0)