Skip to content

Commit 1417629

Browse files
Darksonnojeda
authored andcommitted
rust: list: add struct with prev/next pointers
Define the ListLinks struct, which wraps the prev/next pointers that will be used to insert values into a List in a future patch. Also define the ListItem trait, which is implemented by structs that have a ListLinks field. The ListItem trait provides four different methods that are all essentially container_of or the reverse of container_of. Two of them are used before inserting/after removing an item from the list, and the two others are used when looking at a value without changing whether it is in a list. This distinction is introduced because it is needed for the patch that adds support for heterogeneous lists, which are implemented by adding a third pointer field with a fat pointer to the full struct. When inserting into the heterogeneous list, the pointer-to-self is updated to have the right vtable, and the container_of operation is implemented by just returning that pointer instead of using the real container_of operation. Reviewed-by: Benno Lossin <benno.lossin@proton.me> Signed-off-by: Alice Ryhl <aliceryhl@google.com> Link: https://lore.kernel.org/r/20240814-linked-list-v5-4-f5f5e8075da0@google.com Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
1 parent a480263 commit 1417629

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

rust/kernel/list.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,124 @@
44

55
//! A linked list implementation.
66
7+
use crate::init::PinInit;
8+
use crate::types::Opaque;
9+
use core::ptr;
10+
711
mod arc;
812
pub use self::arc::{impl_list_arc_safe, AtomicTracker, ListArc, ListArcSafe, TryNewListArc};
13+
14+
/// Implemented by types where a [`ListArc<Self>`] can be inserted into a `List`.
15+
///
16+
/// # Safety
17+
///
18+
/// Implementers must ensure that they provide the guarantees documented on methods provided by
19+
/// this trait.
20+
///
21+
/// [`ListArc<Self>`]: ListArc
22+
pub unsafe trait ListItem<const ID: u64 = 0>: ListArcSafe<ID> {
23+
/// Views the [`ListLinks`] for this value.
24+
///
25+
/// # Guarantees
26+
///
27+
/// If there is a previous call to `prepare_to_insert` and there is no call to `post_remove`
28+
/// since the most recent such call, then this returns the same pointer as the one returned by
29+
/// the most recent call to `prepare_to_insert`.
30+
///
31+
/// Otherwise, the returned pointer points at a read-only [`ListLinks`] with two null pointers.
32+
///
33+
/// # Safety
34+
///
35+
/// The provided pointer must point at a valid value. (It need not be in an `Arc`.)
36+
unsafe fn view_links(me: *const Self) -> *mut ListLinks<ID>;
37+
38+
/// View the full value given its [`ListLinks`] field.
39+
///
40+
/// Can only be used when the value is in a list.
41+
///
42+
/// # Guarantees
43+
///
44+
/// * Returns the same pointer as the one passed to the most recent call to `prepare_to_insert`.
45+
/// * The returned pointer is valid until the next call to `post_remove`.
46+
///
47+
/// # Safety
48+
///
49+
/// * The provided pointer must originate from the most recent call to `prepare_to_insert`, or
50+
/// from a call to `view_links` that happened after the most recent call to
51+
/// `prepare_to_insert`.
52+
/// * Since the most recent call to `prepare_to_insert`, the `post_remove` method must not have
53+
/// been called.
54+
unsafe fn view_value(me: *mut ListLinks<ID>) -> *const Self;
55+
56+
/// This is called when an item is inserted into a `List`.
57+
///
58+
/// # Guarantees
59+
///
60+
/// The caller is granted exclusive access to the returned [`ListLinks`] until `post_remove` is
61+
/// called.
62+
///
63+
/// # Safety
64+
///
65+
/// * The provided pointer must point at a valid value in an [`Arc`].
66+
/// * Calls to `prepare_to_insert` and `post_remove` on the same value must alternate.
67+
/// * The caller must own the [`ListArc`] for this value.
68+
/// * The caller must not give up ownership of the [`ListArc`] unless `post_remove` has been
69+
/// called after this call to `prepare_to_insert`.
70+
///
71+
/// [`Arc`]: crate::sync::Arc
72+
unsafe fn prepare_to_insert(me: *const Self) -> *mut ListLinks<ID>;
73+
74+
/// This undoes a previous call to `prepare_to_insert`.
75+
///
76+
/// # Guarantees
77+
///
78+
/// The returned pointer is the pointer that was originally passed to `prepare_to_insert`.
79+
///
80+
/// # Safety
81+
///
82+
/// The provided pointer must be the pointer returned by the most recent call to
83+
/// `prepare_to_insert`.
84+
unsafe fn post_remove(me: *mut ListLinks<ID>) -> *const Self;
85+
}
86+
87+
#[repr(C)]
88+
#[derive(Copy, Clone)]
89+
struct ListLinksFields {
90+
next: *mut ListLinksFields,
91+
prev: *mut ListLinksFields,
92+
}
93+
94+
/// The prev/next pointers for an item in a linked list.
95+
///
96+
/// # Invariants
97+
///
98+
/// The fields are null if and only if this item is not in a list.
99+
#[repr(transparent)]
100+
pub struct ListLinks<const ID: u64 = 0> {
101+
// This type is `!Unpin` for aliasing reasons as the pointers are part of an intrusive linked
102+
// list.
103+
#[allow(dead_code)]
104+
inner: Opaque<ListLinksFields>,
105+
}
106+
107+
// SAFETY: The only way to access/modify the pointers inside of `ListLinks<ID>` is via holding the
108+
// associated `ListArc<T, ID>`. Since that type correctly implements `Send`, it is impossible to
109+
// move this an instance of this type to a different thread if the pointees are `!Send`.
110+
unsafe impl<const ID: u64> Send for ListLinks<ID> {}
111+
// SAFETY: The type is opaque so immutable references to a ListLinks are useless. Therefore, it's
112+
// okay to have immutable access to a ListLinks from several threads at once.
113+
unsafe impl<const ID: u64> Sync for ListLinks<ID> {}
114+
115+
impl<const ID: u64> ListLinks<ID> {
116+
/// Creates a new initializer for this type.
117+
pub fn new() -> impl PinInit<Self> {
118+
// INVARIANT: Pin-init initializers can't be used on an existing `Arc`, so this value will
119+
// not be constructed in an `Arc` that already has a `ListArc`.
120+
ListLinks {
121+
inner: Opaque::new(ListLinksFields {
122+
prev: ptr::null_mut(),
123+
next: ptr::null_mut(),
124+
}),
125+
}
126+
}
127+
}

0 commit comments

Comments
 (0)