|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 2 | + |
| 3 | +// Copyright (C) 2024 Google LLC. |
| 4 | + |
| 5 | +//! A wrapper around `Arc` for linked lists. |
| 6 | +
|
| 7 | +use crate::alloc::{AllocError, Flags}; |
| 8 | +use crate::prelude::*; |
| 9 | +use crate::sync::{Arc, ArcBorrow, UniqueArc}; |
| 10 | +use core::marker::Unsize; |
| 11 | +use core::ops::Deref; |
| 12 | +use core::pin::Pin; |
| 13 | + |
| 14 | +/// Declares that this type has some way to ensure that there is exactly one `ListArc` instance for |
| 15 | +/// this id. |
| 16 | +/// |
| 17 | +/// Types that implement this trait should include some kind of logic for keeping track of whether |
| 18 | +/// a [`ListArc`] exists or not. We refer to this logic as "the tracking inside `T`". |
| 19 | +/// |
| 20 | +/// We allow the case where the tracking inside `T` thinks that a [`ListArc`] exists, but actually, |
| 21 | +/// there isn't a [`ListArc`]. However, we do not allow the opposite situation where a [`ListArc`] |
| 22 | +/// exists, but the tracking thinks it doesn't. This is because the former can at most result in us |
| 23 | +/// failing to create a [`ListArc`] when the operation could succeed, whereas the latter can result |
| 24 | +/// in the creation of two [`ListArc`] references. Only the latter situation can lead to memory |
| 25 | +/// safety issues. |
| 26 | +/// |
| 27 | +/// A consequence of the above is that you may implement the tracking inside `T` by not actually |
| 28 | +/// keeping track of anything. To do this, you always claim that a [`ListArc`] exists, even if |
| 29 | +/// there isn't one. This implementation is allowed by the above rule, but it means that |
| 30 | +/// [`ListArc`] references can only be created if you have ownership of *all* references to the |
| 31 | +/// refcounted object, as you otherwise have no way of knowing whether a [`ListArc`] exists. |
| 32 | +pub trait ListArcSafe<const ID: u64 = 0> { |
| 33 | + /// Informs the tracking inside this type that it now has a [`ListArc`] reference. |
| 34 | + /// |
| 35 | + /// This method may be called even if the tracking inside this type thinks that a `ListArc` |
| 36 | + /// reference exists. (But only if that's not actually the case.) |
| 37 | + /// |
| 38 | + /// # Safety |
| 39 | + /// |
| 40 | + /// Must not be called if a [`ListArc`] already exist for this value. |
| 41 | + unsafe fn on_create_list_arc_from_unique(self: Pin<&mut Self>); |
| 42 | + |
| 43 | + /// Informs the tracking inside this type that there is no [`ListArc`] reference anymore. |
| 44 | + /// |
| 45 | + /// # Safety |
| 46 | + /// |
| 47 | + /// Must only be called if there is no [`ListArc`] reference, but the tracking thinks there is. |
| 48 | + unsafe fn on_drop_list_arc(&self); |
| 49 | +} |
| 50 | + |
| 51 | +/// Declares that this type supports [`ListArc`]. |
| 52 | +/// |
| 53 | +/// When using this macro, it will only be possible to create a [`ListArc`] from a [`UniqueArc`]. |
| 54 | +#[macro_export] |
| 55 | +macro_rules! impl_list_arc_safe { |
| 56 | + (impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty { untracked; } $($rest:tt)*) => { |
| 57 | + impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t { |
| 58 | + unsafe fn on_create_list_arc_from_unique(self: ::core::pin::Pin<&mut Self>) {} |
| 59 | + unsafe fn on_drop_list_arc(&self) {} |
| 60 | + } |
| 61 | + $crate::list::impl_list_arc_safe! { $($rest)* } |
| 62 | + }; |
| 63 | + |
| 64 | + () => {}; |
| 65 | +} |
| 66 | +pub use impl_list_arc_safe; |
| 67 | + |
| 68 | +/// A wrapper around [`Arc`] that's guaranteed unique for the given id. |
| 69 | +/// |
| 70 | +/// The `ListArc` type can be thought of as a special reference to a refcounted object that owns the |
| 71 | +/// permission to manipulate the `next`/`prev` pointers stored in the refcounted object. By ensuring |
| 72 | +/// that each object has only one `ListArc` reference, the owner of that reference is assured |
| 73 | +/// exclusive access to the `next`/`prev` pointers. When a `ListArc` is inserted into a `List`, the |
| 74 | +/// `List` takes ownership of the `ListArc` reference. |
| 75 | +/// |
| 76 | +/// There are various strategies to ensuring that a value has only one `ListArc` reference. The |
| 77 | +/// simplest is to convert a [`UniqueArc`] into a `ListArc`. However, the refcounted object could |
| 78 | +/// also keep track of whether a `ListArc` exists using a boolean, which could allow for the |
| 79 | +/// creation of new `ListArc` references from an [`Arc`] reference. Whatever strategy is used, the |
| 80 | +/// relevant tracking is referred to as "the tracking inside `T`", and the [`ListArcSafe`] trait |
| 81 | +/// (and its subtraits) are used to update the tracking when a `ListArc` is created or destroyed. |
| 82 | +/// |
| 83 | +/// Note that we allow the case where the tracking inside `T` thinks that a `ListArc` exists, but |
| 84 | +/// actually, there isn't a `ListArc`. However, we do not allow the opposite situation where a |
| 85 | +/// `ListArc` exists, but the tracking thinks it doesn't. This is because the former can at most |
| 86 | +/// result in us failing to create a `ListArc` when the operation could succeed, whereas the latter |
| 87 | +/// can result in the creation of two `ListArc` references. |
| 88 | +/// |
| 89 | +/// While this `ListArc` is unique for the given id, there still might exist normal `Arc` |
| 90 | +/// references to the object. |
| 91 | +/// |
| 92 | +/// # Invariants |
| 93 | +/// |
| 94 | +/// * Each reference counted object has at most one `ListArc` for each value of `ID`. |
| 95 | +/// * The tracking inside `T` is aware that a `ListArc` reference exists. |
| 96 | +#[repr(transparent)] |
| 97 | +pub struct ListArc<T, const ID: u64 = 0> |
| 98 | +where |
| 99 | + T: ListArcSafe<ID> + ?Sized, |
| 100 | +{ |
| 101 | + arc: Arc<T>, |
| 102 | +} |
| 103 | + |
| 104 | +impl<T: ListArcSafe<ID>, const ID: u64> ListArc<T, ID> { |
| 105 | + /// Constructs a new reference counted instance of `T`. |
| 106 | + #[inline] |
| 107 | + pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> { |
| 108 | + Ok(Self::from(UniqueArc::new(contents, flags)?)) |
| 109 | + } |
| 110 | + |
| 111 | + /// Use the given initializer to in-place initialize a `T`. |
| 112 | + /// |
| 113 | + /// If `T: !Unpin` it will not be able to move afterwards. |
| 114 | + // We don't implement `InPlaceInit` because `ListArc` is implicitly pinned. This is similar to |
| 115 | + // what we do for `Arc`. |
| 116 | + #[inline] |
| 117 | + pub fn pin_init<E>(init: impl PinInit<T, E>, flags: Flags) -> Result<Self, E> |
| 118 | + where |
| 119 | + E: From<AllocError>, |
| 120 | + { |
| 121 | + Ok(Self::from(UniqueArc::try_pin_init(init, flags)?)) |
| 122 | + } |
| 123 | + |
| 124 | + /// Use the given initializer to in-place initialize a `T`. |
| 125 | + /// |
| 126 | + /// This is equivalent to [`ListArc<T>::pin_init`], since a [`ListArc`] is always pinned. |
| 127 | + #[inline] |
| 128 | + pub fn init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E> |
| 129 | + where |
| 130 | + E: From<AllocError>, |
| 131 | + { |
| 132 | + Ok(Self::from(UniqueArc::try_init(init, flags)?)) |
| 133 | + } |
| 134 | +} |
| 135 | + |
| 136 | +impl<T, const ID: u64> From<UniqueArc<T>> for ListArc<T, ID> |
| 137 | +where |
| 138 | + T: ListArcSafe<ID> + ?Sized, |
| 139 | +{ |
| 140 | + /// Convert a [`UniqueArc`] into a [`ListArc`]. |
| 141 | + #[inline] |
| 142 | + fn from(unique: UniqueArc<T>) -> Self { |
| 143 | + Self::from(Pin::from(unique)) |
| 144 | + } |
| 145 | +} |
| 146 | + |
| 147 | +impl<T, const ID: u64> From<Pin<UniqueArc<T>>> for ListArc<T, ID> |
| 148 | +where |
| 149 | + T: ListArcSafe<ID> + ?Sized, |
| 150 | +{ |
| 151 | + /// Convert a pinned [`UniqueArc`] into a [`ListArc`]. |
| 152 | + #[inline] |
| 153 | + fn from(mut unique: Pin<UniqueArc<T>>) -> Self { |
| 154 | + // SAFETY: We have a `UniqueArc`, so there is no `ListArc`. |
| 155 | + unsafe { T::on_create_list_arc_from_unique(unique.as_mut()) }; |
| 156 | + let arc = Arc::from(unique); |
| 157 | + // SAFETY: We just called `on_create_list_arc_from_unique` on an arc without a `ListArc`, |
| 158 | + // so we can create a `ListArc`. |
| 159 | + unsafe { Self::transmute_from_arc(arc) } |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +impl<T, const ID: u64> ListArc<T, ID> |
| 164 | +where |
| 165 | + T: ListArcSafe<ID> + ?Sized, |
| 166 | +{ |
| 167 | + /// Creates two `ListArc`s from a [`UniqueArc`]. |
| 168 | + /// |
| 169 | + /// The two ids must be different. |
| 170 | + #[inline] |
| 171 | + pub fn pair_from_unique<const ID2: u64>(unique: UniqueArc<T>) -> (Self, ListArc<T, ID2>) |
| 172 | + where |
| 173 | + T: ListArcSafe<ID2>, |
| 174 | + { |
| 175 | + Self::pair_from_pin_unique(Pin::from(unique)) |
| 176 | + } |
| 177 | + |
| 178 | + /// Creates two `ListArc`s from a pinned [`UniqueArc`]. |
| 179 | + /// |
| 180 | + /// The two ids must be different. |
| 181 | + #[inline] |
| 182 | + pub fn pair_from_pin_unique<const ID2: u64>( |
| 183 | + mut unique: Pin<UniqueArc<T>>, |
| 184 | + ) -> (Self, ListArc<T, ID2>) |
| 185 | + where |
| 186 | + T: ListArcSafe<ID2>, |
| 187 | + { |
| 188 | + build_assert!(ID != ID2); |
| 189 | + |
| 190 | + // SAFETY: We have a `UniqueArc`, so there is no `ListArc`. |
| 191 | + unsafe { <T as ListArcSafe<ID>>::on_create_list_arc_from_unique(unique.as_mut()) }; |
| 192 | + // SAFETY: We have a `UniqueArc`, so there is no `ListArc`. |
| 193 | + unsafe { <T as ListArcSafe<ID2>>::on_create_list_arc_from_unique(unique.as_mut()) }; |
| 194 | + |
| 195 | + let arc1 = Arc::from(unique); |
| 196 | + let arc2 = Arc::clone(&arc1); |
| 197 | + |
| 198 | + // SAFETY: We just called `on_create_list_arc_from_unique` on an arc without a `ListArc` |
| 199 | + // for both IDs (which are different), so we can create two `ListArc`s. |
| 200 | + unsafe { |
| 201 | + ( |
| 202 | + Self::transmute_from_arc(arc1), |
| 203 | + ListArc::transmute_from_arc(arc2), |
| 204 | + ) |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + /// Transmutes an [`Arc`] into a `ListArc` without updating the tracking inside `T`. |
| 209 | + /// |
| 210 | + /// # Safety |
| 211 | + /// |
| 212 | + /// * The value must not already have a `ListArc` reference. |
| 213 | + /// * The tracking inside `T` must think that there is a `ListArc` reference. |
| 214 | + #[inline] |
| 215 | + unsafe fn transmute_from_arc(arc: Arc<T>) -> Self { |
| 216 | + // INVARIANT: By the safety requirements, the invariants on `ListArc` are satisfied. |
| 217 | + Self { arc } |
| 218 | + } |
| 219 | + |
| 220 | + /// Transmutes a `ListArc` into an [`Arc`] without updating the tracking inside `T`. |
| 221 | + /// |
| 222 | + /// After this call, the tracking inside `T` will still think that there is a `ListArc` |
| 223 | + /// reference. |
| 224 | + #[inline] |
| 225 | + fn transmute_to_arc(self) -> Arc<T> { |
| 226 | + // Use a transmute to skip destructor. |
| 227 | + // |
| 228 | + // SAFETY: ListArc is repr(transparent). |
| 229 | + unsafe { core::mem::transmute(self) } |
| 230 | + } |
| 231 | + |
| 232 | + /// Convert ownership of this `ListArc` into a raw pointer. |
| 233 | + /// |
| 234 | + /// The returned pointer is indistinguishable from pointers returned by [`Arc::into_raw`]. The |
| 235 | + /// tracking inside `T` will still think that a `ListArc` exists after this call. |
| 236 | + #[inline] |
| 237 | + pub fn into_raw(self) -> *const T { |
| 238 | + Arc::into_raw(Self::transmute_to_arc(self)) |
| 239 | + } |
| 240 | + |
| 241 | + /// Take ownership of the `ListArc` from a raw pointer. |
| 242 | + /// |
| 243 | + /// # Safety |
| 244 | + /// |
| 245 | + /// * `ptr` must satisfy the safety requirements of [`Arc::from_raw`]. |
| 246 | + /// * The value must not already have a `ListArc` reference. |
| 247 | + /// * The tracking inside `T` must think that there is a `ListArc` reference. |
| 248 | + #[inline] |
| 249 | + pub unsafe fn from_raw(ptr: *const T) -> Self { |
| 250 | + // SAFETY: The pointer satisfies the safety requirements for `Arc::from_raw`. |
| 251 | + let arc = unsafe { Arc::from_raw(ptr) }; |
| 252 | + // SAFETY: The value doesn't already have a `ListArc` reference, but the tracking thinks it |
| 253 | + // does. |
| 254 | + unsafe { Self::transmute_from_arc(arc) } |
| 255 | + } |
| 256 | + |
| 257 | + /// Converts the `ListArc` into an [`Arc`]. |
| 258 | + #[inline] |
| 259 | + pub fn into_arc(self) -> Arc<T> { |
| 260 | + let arc = Self::transmute_to_arc(self); |
| 261 | + // SAFETY: There is no longer a `ListArc`, but the tracking thinks there is. |
| 262 | + unsafe { T::on_drop_list_arc(&arc) }; |
| 263 | + arc |
| 264 | + } |
| 265 | + |
| 266 | + /// Clone a `ListArc` into an [`Arc`]. |
| 267 | + #[inline] |
| 268 | + pub fn clone_arc(&self) -> Arc<T> { |
| 269 | + self.arc.clone() |
| 270 | + } |
| 271 | + |
| 272 | + /// Returns a reference to an [`Arc`] from the given [`ListArc`]. |
| 273 | + /// |
| 274 | + /// This is useful when the argument of a function call is an [`&Arc`] (e.g., in a method |
| 275 | + /// receiver), but we have a [`ListArc`] instead. |
| 276 | + /// |
| 277 | + /// [`&Arc`]: Arc |
| 278 | + #[inline] |
| 279 | + pub fn as_arc(&self) -> &Arc<T> { |
| 280 | + &self.arc |
| 281 | + } |
| 282 | + |
| 283 | + /// Returns an [`ArcBorrow`] from the given [`ListArc`]. |
| 284 | + /// |
| 285 | + /// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method |
| 286 | + /// receiver), but we have an [`Arc`] instead. Getting an [`ArcBorrow`] is free when optimised. |
| 287 | + #[inline] |
| 288 | + pub fn as_arc_borrow(&self) -> ArcBorrow<'_, T> { |
| 289 | + self.arc.as_arc_borrow() |
| 290 | + } |
| 291 | + |
| 292 | + /// Compare whether two [`ListArc`] pointers reference the same underlying object. |
| 293 | + #[inline] |
| 294 | + pub fn ptr_eq(this: &Self, other: &Self) -> bool { |
| 295 | + Arc::ptr_eq(&this.arc, &other.arc) |
| 296 | + } |
| 297 | +} |
| 298 | + |
| 299 | +impl<T, const ID: u64> Deref for ListArc<T, ID> |
| 300 | +where |
| 301 | + T: ListArcSafe<ID> + ?Sized, |
| 302 | +{ |
| 303 | + type Target = T; |
| 304 | + |
| 305 | + #[inline] |
| 306 | + fn deref(&self) -> &Self::Target { |
| 307 | + self.arc.deref() |
| 308 | + } |
| 309 | +} |
| 310 | + |
| 311 | +impl<T, const ID: u64> Drop for ListArc<T, ID> |
| 312 | +where |
| 313 | + T: ListArcSafe<ID> + ?Sized, |
| 314 | +{ |
| 315 | + #[inline] |
| 316 | + fn drop(&mut self) { |
| 317 | + // SAFETY: There is no longer a `ListArc`, but the tracking thinks there is by the type |
| 318 | + // invariants on `Self`. |
| 319 | + unsafe { T::on_drop_list_arc(&self.arc) }; |
| 320 | + } |
| 321 | +} |
| 322 | + |
| 323 | +impl<T, const ID: u64> AsRef<Arc<T>> for ListArc<T, ID> |
| 324 | +where |
| 325 | + T: ListArcSafe<ID> + ?Sized, |
| 326 | +{ |
| 327 | + #[inline] |
| 328 | + fn as_ref(&self) -> &Arc<T> { |
| 329 | + self.as_arc() |
| 330 | + } |
| 331 | +} |
| 332 | + |
| 333 | +// This is to allow [`ListArc`] (and variants) to be used as the type of `self`. |
| 334 | +impl<T, const ID: u64> core::ops::Receiver for ListArc<T, ID> where T: ListArcSafe<ID> + ?Sized {} |
| 335 | + |
| 336 | +// This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the |
| 337 | +// dynamically-sized type (DST) `U`. |
| 338 | +impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID> |
| 339 | +where |
| 340 | + T: ListArcSafe<ID> + Unsize<U> + ?Sized, |
| 341 | + U: ListArcSafe<ID> + ?Sized, |
| 342 | +{ |
| 343 | +} |
| 344 | + |
| 345 | +// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into |
| 346 | +// `ListArc<U>`. |
| 347 | +impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID> |
| 348 | +where |
| 349 | + T: ListArcSafe<ID> + Unsize<U> + ?Sized, |
| 350 | + U: ListArcSafe<ID> + ?Sized, |
| 351 | +{ |
| 352 | +} |
0 commit comments