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>
This commit is contained in:
parent
a48026315c
commit
14176295fe
@ -4,5 +4,124 @@
|
|||||||
|
|
||||||
//! A linked list implementation.
|
//! A linked list implementation.
|
||||||
|
|
||||||
|
use crate::init::PinInit;
|
||||||
|
use crate::types::Opaque;
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
mod arc;
|
mod arc;
|
||||||
pub use self::arc::{impl_list_arc_safe, AtomicTracker, ListArc, ListArcSafe, TryNewListArc};
|
pub use self::arc::{impl_list_arc_safe, AtomicTracker, ListArc, ListArcSafe, TryNewListArc};
|
||||||
|
|
||||||
|
/// Implemented by types where a [`ListArc<Self>`] can be inserted into a `List`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Implementers must ensure that they provide the guarantees documented on methods provided by
|
||||||
|
/// this trait.
|
||||||
|
///
|
||||||
|
/// [`ListArc<Self>`]: ListArc
|
||||||
|
pub unsafe trait ListItem<const ID: u64 = 0>: ListArcSafe<ID> {
|
||||||
|
/// Views the [`ListLinks`] for this value.
|
||||||
|
///
|
||||||
|
/// # Guarantees
|
||||||
|
///
|
||||||
|
/// If there is a previous call to `prepare_to_insert` and there is no call to `post_remove`
|
||||||
|
/// since the most recent such call, then this returns the same pointer as the one returned by
|
||||||
|
/// the most recent call to `prepare_to_insert`.
|
||||||
|
///
|
||||||
|
/// Otherwise, the returned pointer points at a read-only [`ListLinks`] with two null pointers.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The provided pointer must point at a valid value. (It need not be in an `Arc`.)
|
||||||
|
unsafe fn view_links(me: *const Self) -> *mut ListLinks<ID>;
|
||||||
|
|
||||||
|
/// View the full value given its [`ListLinks`] field.
|
||||||
|
///
|
||||||
|
/// Can only be used when the value is in a list.
|
||||||
|
///
|
||||||
|
/// # Guarantees
|
||||||
|
///
|
||||||
|
/// * Returns the same pointer as the one passed to the most recent call to `prepare_to_insert`.
|
||||||
|
/// * The returned pointer is valid until the next call to `post_remove`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// * The provided pointer must originate from the most recent call to `prepare_to_insert`, or
|
||||||
|
/// from a call to `view_links` that happened after the most recent call to
|
||||||
|
/// `prepare_to_insert`.
|
||||||
|
/// * Since the most recent call to `prepare_to_insert`, the `post_remove` method must not have
|
||||||
|
/// been called.
|
||||||
|
unsafe fn view_value(me: *mut ListLinks<ID>) -> *const Self;
|
||||||
|
|
||||||
|
/// This is called when an item is inserted into a `List`.
|
||||||
|
///
|
||||||
|
/// # Guarantees
|
||||||
|
///
|
||||||
|
/// The caller is granted exclusive access to the returned [`ListLinks`] until `post_remove` is
|
||||||
|
/// called.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// * The provided pointer must point at a valid value in an [`Arc`].
|
||||||
|
/// * Calls to `prepare_to_insert` and `post_remove` on the same value must alternate.
|
||||||
|
/// * The caller must own the [`ListArc`] for this value.
|
||||||
|
/// * The caller must not give up ownership of the [`ListArc`] unless `post_remove` has been
|
||||||
|
/// called after this call to `prepare_to_insert`.
|
||||||
|
///
|
||||||
|
/// [`Arc`]: crate::sync::Arc
|
||||||
|
unsafe fn prepare_to_insert(me: *const Self) -> *mut ListLinks<ID>;
|
||||||
|
|
||||||
|
/// This undoes a previous call to `prepare_to_insert`.
|
||||||
|
///
|
||||||
|
/// # Guarantees
|
||||||
|
///
|
||||||
|
/// The returned pointer is the pointer that was originally passed to `prepare_to_insert`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The provided pointer must be the pointer returned by the most recent call to
|
||||||
|
/// `prepare_to_insert`.
|
||||||
|
unsafe fn post_remove(me: *mut ListLinks<ID>) -> *const Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct ListLinksFields {
|
||||||
|
next: *mut ListLinksFields,
|
||||||
|
prev: *mut ListLinksFields,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The prev/next pointers for an item in a linked list.
|
||||||
|
///
|
||||||
|
/// # Invariants
|
||||||
|
///
|
||||||
|
/// The fields are null if and only if this item is not in a list.
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct ListLinks<const ID: u64 = 0> {
|
||||||
|
// This type is `!Unpin` for aliasing reasons as the pointers are part of an intrusive linked
|
||||||
|
// list.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
inner: Opaque<ListLinksFields>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: The only way to access/modify the pointers inside of `ListLinks<ID>` is via holding the
|
||||||
|
// associated `ListArc<T, ID>`. Since that type correctly implements `Send`, it is impossible to
|
||||||
|
// move this an instance of this type to a different thread if the pointees are `!Send`.
|
||||||
|
unsafe impl<const ID: u64> Send for ListLinks<ID> {}
|
||||||
|
// SAFETY: The type is opaque so immutable references to a ListLinks are useless. Therefore, it's
|
||||||
|
// okay to have immutable access to a ListLinks from several threads at once.
|
||||||
|
unsafe impl<const ID: u64> Sync for ListLinks<ID> {}
|
||||||
|
|
||||||
|
impl<const ID: u64> ListLinks<ID> {
|
||||||
|
/// Creates a new initializer for this type.
|
||||||
|
pub fn new() -> impl PinInit<Self> {
|
||||||
|
// INVARIANT: Pin-init initializers can't be used on an existing `Arc`, so this value will
|
||||||
|
// not be constructed in an `Arc` that already has a `ListArc`.
|
||||||
|
ListLinks {
|
||||||
|
inner: Opaque::new(ListLinksFields {
|
||||||
|
prev: ptr::null_mut(),
|
||||||
|
next: ptr::null_mut(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user