summaryrefslogtreecommitdiff
path: root/rust/kernel/list/arc.rs
blob: 966076da4a755884a1b9ec83b7d6a87d210e36aa (plain)
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
340
341
342
343
344
345
346
347
348
349
350
351
352
// SPDX-License-Identifier: GPL-2.0

// Copyright (C) 2024 Google LLC.

//! A wrapper around `Arc` for linked lists.

use crate::alloc::{AllocError, Flags};
use crate::prelude::*;
use crate::sync::{Arc, ArcBorrow, UniqueArc};
use core::marker::Unsize;
use core::ops::Deref;
use core::pin::Pin;

/// Declares that this type has some way to ensure that there is exactly one `ListArc` instance for
/// this id.
///
/// Types that implement this trait should include some kind of logic for keeping track of whether
/// a [`ListArc`] exists or not. We refer to this logic as "the tracking inside `T`".
///
/// 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. Only the latter situation can lead to memory
/// safety issues.
///
/// A consequence of the above is that you may implement the tracking inside `T` by not actually
/// keeping track of anything. To do this, you always claim that a [`ListArc`] exists, even if
/// there isn't one. This implementation is allowed by the above rule, but it means that
/// [`ListArc`] references can only be created if you have ownership of *all* references to the
/// refcounted object, as you otherwise have no way of knowing whether a [`ListArc`] exists.
pub trait ListArcSafe<const ID: u64 = 0> {
    /// Informs the tracking inside this type that it now has a [`ListArc`] reference.
    ///
    /// This method may be called even if the tracking inside this type thinks that a `ListArc`
    /// reference exists. (But only if that's not actually the case.)
    ///
    /// # Safety
    ///
    /// Must not be called if a [`ListArc`] already exist for this value.
    unsafe fn on_create_list_arc_from_unique(self: Pin<&mut Self>);

    /// Informs the tracking inside this type that there is no [`ListArc`] reference anymore.
    ///
    /// # Safety
    ///
    /// Must only be called if there is no [`ListArc`] reference, but the tracking thinks there is.
    unsafe fn on_drop_list_arc(&self);
}

/// Declares that this type supports [`ListArc`].
///
/// When using this macro, it will only be possible to create a [`ListArc`] from a [`UniqueArc`].
#[macro_export]
macro_rules! impl_list_arc_safe {
    (impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty { untracked; } $($rest:tt)*) => {
        impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t {
            unsafe fn on_create_list_arc_from_unique(self: ::core::pin::Pin<&mut Self>) {}
            unsafe fn on_drop_list_arc(&self) {}
        }
        $crate::list::impl_list_arc_safe! { $($rest)* }
    };

    () => {};
}
pub use impl_list_arc_safe;

/// A wrapper around [`Arc`] that's guaranteed unique for the given id.
///
/// 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 to 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.
///
/// While this `ListArc` is unique for the given id, there still might exist normal `Arc`
/// references to the object.
///
/// # Invariants
///
/// * Each reference counted object has at most one `ListArc` for each value of `ID`.
/// * The tracking inside `T` is aware that a `ListArc` reference exists.
#[repr(transparent)]
pub struct ListArc<T, const ID: u64 = 0>
where
    T: ListArcSafe<ID> + ?Sized,
{
    arc: Arc<T>,
}

impl<T: ListArcSafe<ID>, const ID: u64> ListArc<T, ID> {
    /// Constructs a new reference counted instance of `T`.
    #[inline]
    pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
        Ok(Self::from(UniqueArc::new(contents, flags)?))
    }

    /// Use the given initializer to in-place initialize a `T`.
    ///
    /// If `T: !Unpin` it will not be able to move afterwards.
    // We don't implement `InPlaceInit` because `ListArc` is implicitly pinned. This is similar to
    // what we do for `Arc`.
    #[inline]
    pub fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self, E>
    where
        E: From<AllocError>,
    {
        Ok(Self::from(UniqueArc::try_pin_init(init, flags)?))
    }

    /// Use the given initializer to in-place initialize a `T`.
    ///
    /// This is equivalent to [`ListArc<T>::pin_init`], since a [`ListArc`] is always pinned.
    #[inline]
    pub fn init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
    where
        E: From<AllocError>,
    {
        Ok(Self::from(UniqueArc::try_init(init, flags)?))
    }
}

impl<T, const ID: u64> From<UniqueArc<T>> for ListArc<T, ID>
where
    T: ListArcSafe<ID> + ?Sized,
{
    /// Convert a [`UniqueArc`] into a [`ListArc`].
    #[inline]
    fn from(unique: UniqueArc<T>) -> Self {
        Self::from(Pin::from(unique))
    }
}

impl<T, const ID: u64> From<Pin<UniqueArc<T>>> for ListArc<T, ID>
where
    T: ListArcSafe<ID> + ?Sized,
{
    /// Convert a pinned [`UniqueArc`] into a [`ListArc`].
    #[inline]
    fn from(mut unique: Pin<UniqueArc<T>>) -> Self {
        // SAFETY: We have a `UniqueArc`, so there is no `ListArc`.
        unsafe { T::on_create_list_arc_from_unique(unique.as_mut()) };
        let arc = Arc::from(unique);
        // SAFETY: We just called `on_create_list_arc_from_unique` on an arc without a `ListArc`,
        // so we can create a `ListArc`.
        unsafe { Self::transmute_from_arc(arc) }
    }
}

impl<T, const ID: u64> ListArc<T, ID>
where
    T: ListArcSafe<ID> + ?Sized,
{
    /// Creates two `ListArc`s from a [`UniqueArc`].
    ///
    /// The two ids must be different.
    #[inline]
    pub fn pair_from_unique<const ID2: u64>(unique: UniqueArc<T>) -> (Self, ListArc<T, ID2>)
    where
        T: ListArcSafe<ID2>,
    {
        Self::pair_from_pin_unique(Pin::from(unique))
    }

    /// Creates two `ListArc`s from a pinned [`UniqueArc`].
    ///
    /// The two ids must be different.
    #[inline]
    pub fn pair_from_pin_unique<const ID2: u64>(
        mut unique: Pin<UniqueArc<T>>,
    ) -> (Self, ListArc<T, ID2>)
    where
        T: ListArcSafe<ID2>,
    {
        build_assert!(ID != ID2);

        // SAFETY: We have a `UniqueArc`, so there is no `ListArc`.
        unsafe { <T as ListArcSafe<ID>>::on_create_list_arc_from_unique(unique.as_mut()) };
        // SAFETY: We have a `UniqueArc`, so there is no `ListArc`.
        unsafe { <T as ListArcSafe<ID2>>::on_create_list_arc_from_unique(unique.as_mut()) };

        let arc1 = Arc::from(unique);
        let arc2 = Arc::clone(&arc1);

        // SAFETY: We just called `on_create_list_arc_from_unique` on an arc without a `ListArc`
        // for both IDs (which are different), so we can create two `ListArc`s.
        unsafe {
            (
                Self::transmute_from_arc(arc1),
                ListArc::transmute_from_arc(arc2),
            )
        }
    }

    /// Transmutes an [`Arc`] into a `ListArc` without updating the tracking inside `T`.
    ///
    /// # Safety
    ///
    /// * The value must not already have a `ListArc` reference.
    /// * The tracking inside `T` must think that there is a `ListArc` reference.
    #[inline]
    unsafe fn transmute_from_arc(arc: Arc<T>) -> Self {
        // INVARIANT: By the safety requirements, the invariants on `ListArc` are satisfied.
        Self { arc }
    }

    /// Transmutes a `ListArc` into an [`Arc`] without updating the tracking inside `T`.
    ///
    /// After this call, the tracking inside `T` will still think that there is a `ListArc`
    /// reference.
    #[inline]
    fn transmute_to_arc(self) -> Arc<T> {
        // Use a transmute to skip destructor.
        //
        // SAFETY: ListArc is repr(transparent).
        unsafe { core::mem::transmute(self) }
    }

    /// Convert ownership of this `ListArc` into a raw pointer.
    ///
    /// The returned pointer is indistinguishable from pointers returned by [`Arc::into_raw`]. The
    /// tracking inside `T` will still think that a `ListArc` exists after this call.
    #[inline]
    pub fn into_raw(self) -> *const T {
        Arc::into_raw(Self::transmute_to_arc(self))
    }

    /// Take ownership of the `ListArc` from a raw pointer.
    ///
    /// # Safety
    ///
    /// * `ptr` must satisfy the safety requirements of [`Arc::from_raw`].
    /// * The value must not already have a `ListArc` reference.
    /// * The tracking inside `T` must think that there is a `ListArc` reference.
    #[inline]
    pub unsafe fn from_raw(ptr: *const T) -> Self {
        // SAFETY: The pointer satisfies the safety requirements for `Arc::from_raw`.
        let arc = unsafe { Arc::from_raw(ptr) };
        // SAFETY: The value doesn't already have a `ListArc` reference, but the tracking thinks it
        // does.
        unsafe { Self::transmute_from_arc(arc) }
    }

    /// Converts the `ListArc` into an [`Arc`].
    #[inline]
    pub fn into_arc(self) -> Arc<T> {
        let arc = Self::transmute_to_arc(self);
        // SAFETY: There is no longer a `ListArc`, but the tracking thinks there is.
        unsafe { T::on_drop_list_arc(&arc) };
        arc
    }

    /// Clone a `ListArc` into an [`Arc`].
    #[inline]
    pub fn clone_arc(&self) -> Arc<T> {
        self.arc.clone()
    }

    /// Returns a reference to an [`Arc`] from the given [`ListArc`].
    ///
    /// This is useful when the argument of a function call is an [`&Arc`] (e.g., in a method
    /// receiver), but we have a [`ListArc`] instead.
    ///
    /// [`&Arc`]: Arc
    #[inline]
    pub fn as_arc(&self) -> &Arc<T> {
        &self