summaryrefslogtreecommitdiff
path: root/rust/kernel/interop/list.rs
blob: 54265ea036bb666f19acd7c799d66600a6434b17 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
// SPDX-License-Identifier: GPL-2.0

//! Rust interface for C doubly circular intrusive linked lists.
//!
//! This module provides Rust abstractions for iterating over C `list_head`-based
//! linked lists. It should only be used for cases where C and Rust code share
//! direct access to the same linked list through a C interop interface.
//!
//! Note: This *must not* be used by Rust components that just need a linked list
//! primitive. Use [`kernel::list::List`] instead.
//!
//! # Examples
//!
//! ```
//! use kernel::{
//!     bindings,
//!     interop::list::clist_create,
//!     types::Opaque,
//! };
//! # // Create test list with values (0, 10, 20) - normally done by C code but it is
//! # // emulated here for doctests using the C bindings.
//! # use core::mem::MaybeUninit;
//! #
//! # /// C struct with embedded `list_head` (typically will be allocated by C code).
//! # #[repr(C)]
//! # pub struct SampleItemC {
//! #     pub value: i32,
//! #     pub link: bindings::list_head,
//! # }
//! #
//! # let mut head = MaybeUninit::<bindings::list_head>::uninit();
//! #
//! # let head = head.as_mut_ptr();
//! # // SAFETY: `head` and all the items are test objects allocated in this scope.
//! # unsafe { bindings::INIT_LIST_HEAD(head) };
//! #
//! # let mut items = [
//! #     MaybeUninit::<SampleItemC>::uninit(),
//! #     MaybeUninit::<SampleItemC>::uninit(),
//! #     MaybeUninit::<SampleItemC>::uninit(),
//! # ];
//! #
//! # for (i, item) in items.iter_mut().enumerate() {
//! #     let ptr = item.as_mut_ptr();
//! #     // SAFETY: `ptr` points to a valid `MaybeUninit<SampleItemC>`.
//! #     unsafe { (*ptr).value = i as i32 * 10 };
//! #     // SAFETY: `&raw mut` creates a pointer valid for `INIT_LIST_HEAD`.
//! #     unsafe { bindings::INIT_LIST_HEAD(&raw mut (*ptr).link) };
//! #     // SAFETY: `link` was just initialized and `head` is a valid list head.
//! #     unsafe { bindings::list_add_tail(&mut (*ptr).link, head) };
//! # }
//!
//! /// Rust wrapper for the C struct.
//! ///
//! /// The list item struct in this example is defined in C code as:
//! ///
//! /// ```c
//! /// struct SampleItemC {
//! ///     int value;
//! ///     struct list_head link;
//! /// };
//! /// ```
//! #[repr(transparent)]
//! pub struct Item(Opaque<SampleItemC>);
//!
//! impl Item {
//!     pub fn value(&self) -> i32 {
//!         // SAFETY: `Item` has the same layout as `SampleItemC`.
//!         unsafe { (*self.0.get()).value }
//!     }
//! }
//!
//! // Create typed [`CList`] from sentinel head.
//! // SAFETY: `head` is valid and initialized, items are `SampleItemC` with
//! // embedded `link` field, and `Item` is `#[repr(transparent)]` over `SampleItemC`.
//! let list = unsafe { clist_create!(head, Item, SampleItemC, link) };
//!
//! // Iterate directly over typed items.
//! let mut found_0 = false;
//! let mut found_10 = false;
//! let mut found_20 = false;
//!
//! for item in list.iter() {
//!     let val = item.value();
//!     if val == 0 { found_0 = true; }
//!     if val == 10 { found_10 = true; }
//!     if val == 20 { found_20 = true; }
//! }
//!
//! assert!(found_0 && found_10 && found_20);
//! ```

use core::{
    iter::FusedIterator,
    marker::PhantomData, //
};

use crate::{
    bindings,
    types::Opaque, //
};

use pin_init::{
    pin_data,
    pin_init,
    PinInit, //
};

/// FFI wrapper for a C `list_head` object used in intrusive linked lists.
///
/// # Invariants
///
/// - The underlying `list_head` is initialized with valid non-`NULL` `next`/`prev` pointers.
#[pin_data]
#[repr(transparent)]
pub struct CListHead {
    #[pin]
    inner: Opaque<bindings::list_head>,
}

impl CListHead {
    /// Create a `&CListHead` reference from a raw `list_head` pointer.
    ///
    /// # Safety
    ///
    /// - `ptr` must be a valid pointer to an initialized `list_head` (e.g. via
    ///   `INIT_LIST_HEAD()`), with valid non-`NULL` `next`/`prev` pointers.
    /// - `ptr` must remain valid for the lifetime `'a`.
    /// - The list and all linked `list_head` nodes must not be modified from
    ///   anywhere for the lifetime `'a`, unless done so via any [`CListHead`] APIs.
    #[inline]
    pub unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self {
        // SAFETY:
        // - `CListHead` has the same layout as `list_head`.
        // - `ptr` is valid and unmodified for `'a` per caller guarantees.
        unsafe { &*ptr.cast() }
    }

    /// Get the raw `list_head` pointer.
    #[inline]
    pub fn as_raw(&self) -> *mut bindings::list_head {
        self.inner.get()
    }

    /// Get the next [`CListHead`] in the list.
    #[inline]
    pub fn next(&self) -> &Self {
        let raw = self.as_raw();
        // SAFETY:
        // - `self.as_raw()` is valid and initialized per type invariants.
        // - The `next` pointer is valid and non-`NULL` per type invariants
        //   (initialized via `INIT_LIST_HEAD()` or equivalent).
        unsafe { Self::from_raw((*raw).next) }
    }

    /// Check if this node is linked in a list (not isolated).
    #[inline]
    pub fn is_linked(&self) -> bool {
        let raw = self.as_raw();
        // SAFETY: `self.as_raw()` is valid per type invariants.
        unsafe { (*raw).next != raw && (*raw).prev != raw }
    }

    /// Returns a pin-initializer for the list head.
    pub fn new() -> impl PinInit<Self> {
        pin_init!(Self {
            // SAFETY: `INIT_LIST_HEAD` initializes `slot` to a valid empty list.
            inner <- Opaque::ffi_init(|slot| unsafe { bindings::INIT_LIST_HEAD(slot) }),
        })
    }
}

// SAFETY: `list_head` contains no thread-bound state; it only holds
// `next`/`prev` pointers.
unsafe impl Send for CListHead {}

// SAFETY: `CListHead` can be shared among threads as modifications are
// not allowed at the moment.
unsafe impl Sync for CListHead {}

impl PartialEq for CListHead {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        core::ptr::eq(self, other)
    }
}

impl Eq for CListHead {}

/// Low-level iterator over `list_head` nodes.
///
/// An iterator used to iterate over a C intrusive linked list (`list_head`). The caller has to
/// perform conversion of returned [`CListHead`] to an item (using [`container_of`] or similar).
///
/// # Invariants
///
/// `current` and `sentinel` are valid references into an initialized linked list.
struct CListHeadIter<'a> {
    /// Current position in the list.
    current: &'a CListHead,
    /// The sentinel head (used to detect end of iteration).
    sentinel: &'a CListHead,
}

impl<'a> Iterator for CListHeadIter<'a> {
    type Item = &'a CListHead;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        // Check if we've reached the sentinel (end of list).
        if self.current == self.sentinel {
            return None;
        }

        let item = self.current;
        self.current = item.next();
        Some(item)
    }
}

impl<'a> FusedIterator for CListHeadIter<'a> {}

/// A typed C linked list with a sentinel head intended for FFI use-cases where
/// a C subsystem manages a linked list that Rust code needs to read. Generally
/// required only for special cases.
///
/// A sentinel head [`CListHead`] represents the entire linked list and can be used
/// for iteration over items of type `T`; it is not associated with a specific item.
///
/// The const generic `OFFSET` specifies the byte offset of the `list_head` field within
/// the struct that `T` wraps.
///
/// # Invariants
///
/// - The sentinel [`CListHead`] has valid non-`NULL` `next`/`prev` pointers.
/// - `OFFSET` is the byte offset of the `list_head` field within the struct that `T` wraps.
/// - All the list's `list_head` nodes have valid non-`NULL` `next`/`prev` pointers.
#[repr(transparent)]
pub struct CList<T, const OFFSET: usize>(CListHead, PhantomData<T>);

impl<T, const OFFSET: usize> CList<T, OFFSET> {
    /// Create a typed [`CList`] reference from a raw sentinel `list_head` pointer.
    ///
    /// # Safety
    ///
    /// - `ptr` must be a valid pointer to an initialized sentinel `list_head` (e.g. via
    ///   `INIT_LIST_HEAD()`), with valid non-`NULL` `next`/`prev` pointers.
    /// - `ptr` must remain valid for the lifetime `'a`.
    /// - The list and all linked nodes must not be concurrently modified for the lifetime `'a`.
    /// - The list must contain items where the `list_head` field is at byte offset `OFFSET`.
    /// - `T` must be `#[repr(transparent)]` over the C struct.
    #[inline]
    pub unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self {
        // SAFETY:
        // - `CList` has the same layout as `CListHead` due to `#[repr(transparent)]`.
        // - Caller guarantees `ptr` is a valid, sentinel `list_head` object.
        unsafe { &*ptr.cast() }
    }

    /// Check if the list is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        !self.0.is_linked()
    }

    /// Create an iterator over typed items.
    #[inline]
    pub fn iter(&self) -> CListIter<'_, T, OFFSET> {
        let head = &self.0;
        CListIter {
            head_iter: CListHeadIter {
                current: head.next(),
                sentinel: head,
            },
            _phantom: PhantomData,
        }
    }
}

/// High-level iterator over typed list items.
pub struct CListIter<'a, T, const OFFSET: usize> {
    head_iter: CListHeadIter<'a>,
    _phantom: PhantomData<&'a T>,
}

impl<'a, T, const OFFSET: usize> Iterator for CListIter<'a, T, OFFSET> {
    type Item = &'a T;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        let head = self.head_iter.next()?;

        // Convert to item using `OFFSET`.
        //
        // SAFETY: The pointer calculation is valid because `OFFSET` is derived
        // from `offset_of!` per type invariants.
        Some(unsafe { &*head.as_raw().byte_sub(OFFSET).cast::<T>() })
    }
}

impl<'a, T, const OFFSET: usize> FusedIterator for CListIter<'a, T, OFFSET> {}

/// Create a C doubly-circular linked list interface [`CList`] from a raw `list_head` pointer.
///
/// This macro creates a `CList<T, OFFSET>` that can iterate over items of type `$rust_type`
/// linked via the `$field` field in the underlying C struct `$c_type`.
///
/// # Arguments
///
/// - `$head`: Raw pointer to the sentinel `list_head` object (`*mut bindings::list_head`).
/// - `$rust_type`: Each item's Rust wrapper type.
/// - `$c_type`: Each item's C struct type that contains the embedded `list_head`.
/// - `$field`: The name of the `list_head` field within the C struct.
///
/// # Safety
///
/// The caller must ensure:
///
/// - `$head` is a valid, initialized sentinel `list_head` (e.g. via `INIT_LIST_HEAD()`)
///   pointing to a list that is not concurrently modified for the lifetime of the [`CList`].
/// - The list contains items of type `$c_type` linked via an embedded `$field`.
/// - `$rust_type` is `#[repr(transparent)]` over `$c_type` or has compatible layout.
///
/// # Examples
///
/// Refer to the examples in the [`crate::interop::list`] module documentation.
#[macro_export]
macro_rules! clist_create {
    ($head:expr, $rust_type:ty, $c_type:ty, $($field:tt).+) => {{
        // Compile-time check that field path is a `list_head`.
        let _: fn(*const $c_type) -> *const $crate::bindings::list_head =
            |p| &raw const (*p).$($field).+;

        // Calculate offset and create `CList`.
        const OFFSET: usize = ::core::mem::offset_of!($c_type, $($field).+);
        $crate::interop::list::CList::<$rust_type, OFFSET>::from_raw($head)
    }};
}
pub use clist_create;