mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	rust: list: add macro for implementing ListItem
Adds a macro for safely implementing the ListItem trait. As part of the implementation of the macro, we also provide a HasListLinks trait similar to the workqueue's HasWorkItem trait. The HasListLinks trait is only necessary if you are implementing ListItem using the impl_list_item macro. 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-5-f5f5e8075da0@google.com Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
		
							parent
							
								
									14176295fe
								
							
						
					
					
						commit
						40c5329459
					
				
					 2 changed files with 146 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -8,6 +8,9 @@
 | 
			
		|||
use crate::types::Opaque;
 | 
			
		||||
use core::ptr;
 | 
			
		||||
 | 
			
		||||
mod impl_list_item_mod;
 | 
			
		||||
pub use self::impl_list_item_mod::{impl_has_list_links, impl_list_item, HasListLinks};
 | 
			
		||||
 | 
			
		||||
mod arc;
 | 
			
		||||
pub use self::arc::{impl_list_arc_safe, AtomicTracker, ListArc, ListArcSafe, TryNewListArc};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										143
									
								
								rust/kernel/list/impl_list_item_mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								rust/kernel/list/impl_list_item_mod.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,143 @@
 | 
			
		|||
// SPDX-License-Identifier: GPL-2.0
 | 
			
		||||
 | 
			
		||||
// Copyright (C) 2024 Google LLC.
 | 
			
		||||
 | 
			
		||||
//! Helpers for implementing list traits safely.
 | 
			
		||||
 | 
			
		||||
use crate::list::ListLinks;
 | 
			
		||||
 | 
			
		||||
/// Declares that this type has a `ListLinks<ID>` field at a fixed offset.
 | 
			
		||||
///
 | 
			
		||||
/// This trait is only used to help implement `ListItem` safely. If `ListItem` is implemented
 | 
			
		||||
/// manually, then this trait is not needed. Use the [`impl_has_list_links!`] macro to implement
 | 
			
		||||
/// this trait.
 | 
			
		||||
///
 | 
			
		||||
/// # Safety
 | 
			
		||||
///
 | 
			
		||||
/// All values of this type must have a `ListLinks<ID>` field at the given offset.
 | 
			
		||||
///
 | 
			
		||||
/// The behavior of `raw_get_list_links` must not be changed.
 | 
			
		||||
pub unsafe trait HasListLinks<const ID: u64 = 0> {
 | 
			
		||||
    /// The offset of the `ListLinks` field.
 | 
			
		||||
    const OFFSET: usize;
 | 
			
		||||
 | 
			
		||||
    /// Returns a pointer to the [`ListLinks<T, ID>`] field.
 | 
			
		||||
    ///
 | 
			
		||||
    /// # Safety
 | 
			
		||||
    ///
 | 
			
		||||
    /// The provided pointer must point at a valid struct of type `Self`.
 | 
			
		||||
    ///
 | 
			
		||||
    /// [`ListLinks<T, ID>`]: ListLinks
 | 
			
		||||
    // We don't really need this method, but it's necessary for the implementation of
 | 
			
		||||
    // `impl_has_list_links!` to be correct.
 | 
			
		||||
    #[inline]
 | 
			
		||||
    unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut ListLinks<ID> {
 | 
			
		||||
        // SAFETY: The caller promises that the pointer is valid. The implementer promises that the
 | 
			
		||||
        // `OFFSET` constant is correct.
 | 
			
		||||
        unsafe { (ptr as *mut u8).add(Self::OFFSET) as *mut ListLinks<ID> }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Implements the [`HasListLinks`] trait for the given type.
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! impl_has_list_links {
 | 
			
		||||
    ($(impl$(<$($implarg:ident),*>)?
 | 
			
		||||
       HasListLinks$(<$id:tt>)?
 | 
			
		||||
       for $self:ident $(<$($selfarg:ty),*>)?
 | 
			
		||||
       { self$(.$field:ident)* }
 | 
			
		||||
    )*) => {$(
 | 
			
		||||
        // SAFETY: The implementation of `raw_get_list_links` only compiles if the field has the
 | 
			
		||||
        // right type.
 | 
			
		||||
        //
 | 
			
		||||
        // The behavior of `raw_get_list_links` is not changed since the `addr_of_mut!` macro is
 | 
			
		||||
        // equivalent to the pointer offset operation in the trait definition.
 | 
			
		||||
        unsafe impl$(<$($implarg),*>)? $crate::list::HasListLinks$(<$id>)? for
 | 
			
		||||
            $self $(<$($selfarg),*>)?
 | 
			
		||||
        {
 | 
			
		||||
            const OFFSET: usize = ::core::mem::offset_of!(Self, $($field).*) as usize;
 | 
			
		||||
 | 
			
		||||
            #[inline]
 | 
			
		||||
            unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$id>)? {
 | 
			
		||||
                // SAFETY: The caller promises that the pointer is not dangling. We know that this
 | 
			
		||||
                // expression doesn't follow any pointers, as the `offset_of!` invocation above
 | 
			
		||||
                // would otherwise not compile.
 | 
			
		||||
                unsafe { ::core::ptr::addr_of_mut!((*ptr)$(.$field)*) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )*};
 | 
			
		||||
}
 | 
			
		||||
pub use impl_has_list_links;
 | 
			
		||||
 | 
			
		||||
/// Implements the [`ListItem`] trait for the given type.
 | 
			
		||||
///
 | 
			
		||||
/// Requires that the type implements [`HasListLinks`]. Use the [`impl_has_list_links!`] macro to
 | 
			
		||||
/// implement that trait.
 | 
			
		||||
///
 | 
			
		||||
/// [`ListItem`]: crate::list::ListItem
 | 
			
		||||
#[macro_export]
 | 
			
		||||
macro_rules! impl_list_item {
 | 
			
		||||
    (
 | 
			
		||||
        $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $t:ty {
 | 
			
		||||
            using ListLinks;
 | 
			
		||||
        })*
 | 
			
		||||
    ) => {$(
 | 
			
		||||
        // SAFETY: See GUARANTEES comment on each method.
 | 
			
		||||
        unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $t {
 | 
			
		||||
            // GUARANTEES:
 | 
			
		||||
            // * This returns the same pointer as `prepare_to_insert` because `prepare_to_insert`
 | 
			
		||||
            //   is implemented in terms of `view_links`.
 | 
			
		||||
            // * By the type invariants of `ListLinks`, the `ListLinks` has two null pointers when
 | 
			
		||||
            //   this value is not in a list.
 | 
			
		||||
            unsafe fn view_links(me: *const Self) -> *mut $crate::list::ListLinks<$num> {
 | 
			
		||||
                // SAFETY: The caller guarantees that `me` points at a valid value of type `Self`.
 | 
			
		||||
                unsafe {
 | 
			
		||||
                    <Self as $crate::list::HasListLinks<$num>>::raw_get_list_links(me.cast_mut())
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // GUARANTEES:
 | 
			
		||||
            // * `me` originates from the most recent call to `prepare_to_insert`, which just added
 | 
			
		||||
            //   `offset` to the pointer passed to `prepare_to_insert`. This method subtracts
 | 
			
		||||
            //   `offset` from `me` so it returns the pointer originally passed to
 | 
			
		||||
            //   `prepare_to_insert`.
 | 
			
		||||
            // * The pointer remains valid until the next call to `post_remove` because the caller
 | 
			
		||||
            //   of the most recent call to `prepare_to_insert` promised to retain ownership of the
 | 
			
		||||
            //   `ListArc` containing `Self` until the next call to `post_remove`. The value cannot
 | 
			
		||||
            //   be destroyed while a `ListArc` reference exists.
 | 
			
		||||
            unsafe fn view_value(me: *mut $crate::list::ListLinks<$num>) -> *const Self {
 | 
			
		||||
                let offset = <Self as $crate::list::HasListLinks<$num>>::OFFSET;
 | 
			
		||||
                // SAFETY: `me` originates from the most recent call to `prepare_to_insert`, so it
 | 
			
		||||
                // points at the field at offset `offset` in a value of type `Self`. Thus,
 | 
			
		||||
                // subtracting `offset` from `me` is still in-bounds of the allocation.
 | 
			
		||||
                unsafe { (me as *const u8).sub(offset) as *const Self }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // GUARANTEES:
 | 
			
		||||
            // This implementation of `ListItem` will not give out exclusive access to the same
 | 
			
		||||
            // `ListLinks` several times because calls to `prepare_to_insert` and `post_remove`
 | 
			
		||||
            // must alternate and exclusive access is given up when `post_remove` is called.
 | 
			
		||||
            //
 | 
			
		||||
            // Other invocations of `impl_list_item!` also cannot give out exclusive access to the
 | 
			
		||||
            // same `ListLinks` because you can only implement `ListItem` once for each value of
 | 
			
		||||
            // `ID`, and the `ListLinks` fields only work with the specified `ID`.
 | 
			
		||||
            unsafe fn prepare_to_insert(me: *const Self) -> *mut $crate::list::ListLinks<$num> {
 | 
			
		||||
                // SAFETY: The caller promises that `me` points at a valid value.
 | 
			
		||||
                unsafe { <Self as $crate::list::ListItem<$num>>::view_links(me) }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // GUARANTEES:
 | 
			
		||||
            // * `me` originates from the most recent call to `prepare_to_insert`, which just added
 | 
			
		||||
            //   `offset` to the pointer passed to `prepare_to_insert`. This method subtracts
 | 
			
		||||
            //   `offset` from `me` so it returns the pointer originally passed to
 | 
			
		||||
            //   `prepare_to_insert`.
 | 
			
		||||
            unsafe fn post_remove(me: *mut $crate::list::ListLinks<$num>) -> *const Self {
 | 
			
		||||
                let offset = <Self as $crate::list::HasListLinks<$num>>::OFFSET;
 | 
			
		||||
                // SAFETY: `me` originates from the most recent call to `prepare_to_insert`, so it
 | 
			
		||||
                // points at the field at offset `offset` in a value of type `Self`. Thus,
 | 
			
		||||
                // subtracting `offset` from `me` is still in-bounds of the allocation.
 | 
			
		||||
                unsafe { (me as *const u8).sub(offset) as *const Self }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )*};
 | 
			
		||||
}
 | 
			
		||||
pub use impl_list_item;
 | 
			
		||||
		Loading…
	
		Reference in a new issue