rust: list: add ListArc
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 for 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. Only the latter situation can lead to memory safety issues.
This patch introduces the `impl_list_arc_safe!` macro that allows you to
implement `ListArcSafe` for types using the strategy where a `ListArc`
can only be created from a `UniqueArc`. Other strategies are introduced
in later patches.
This is part of the linked list that Rust Binder will use for many
different things. The strategy where a `ListArc` can only be created
from a `UniqueArc` is actually sufficient for most of the objects that
Rust Binder needs to insert into linked lists. Usually, these are todo
items that are created and then immediately inserted into a queue.
The const generic ID allows objects to have several prev/next pointer
pairs so that the same object can be inserted into several different
lists. You are able to have several `ListArc` references as long as they
correspond to different pointer pairs. The ID itself is purely a
compile-time concept and will not be present in the final binary. Both
the `List` and the `ListArc` will need to agree on the ID for them to
work together. Rust Binder uses this in a few places (e.g. death
recipients) where the same object can be inserted into both generic todo
lists and some other lists for tracking the status of the object.
The ID is a const generic rather than a type parameter because the
`pair_from_unique` method needs to be able to assert that the two ids
are different. There's no easy way to assert that when using types
instead of integers.
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-2-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:21 +00:00
|
|
|
// 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};
|
rust: list: add tracking for ListArc
Add the ability to track whether a ListArc exists for a given value,
allowing for the creation of ListArcs without going through UniqueArc.
The `impl_list_arc_safe!` macro is extended with a `tracked_by` strategy
that defers the tracking of ListArcs to a field of the struct.
Additionally, the AtomicListArcTracker type is introduced, which can
track whether a ListArc exists using an atomic. By deferring the
tracking to a field of type AtomicListArcTracker, structs gain the
ability to create ListArcs without going through a UniqueArc.
Rust Binder uses this for some objects where we want to be able to
insert them into a linked list at any time. Using the
AtomicListArcTracker, we are able to check whether an item is already in
the list, and if not, we can create a `ListArc` and push it.
The macro has the ability to defer the tracking of ListArcs to a field,
using whatever strategy that field has. Since we don't add any
strategies other than AtomicListArcTracker, another similar option would
be to hard-code that the field should be an AtomicListArcTracker.
However, Rust Binder has a case where the AtomicListArcTracker is not
stored directly in the struct, but in a sub-struct. Furthermore, the
outer struct is generic:
struct Wrapper<T: ?Sized> {
links: ListLinks,
inner: T,
}
Here, the Wrapper struct implements ListArcSafe with `tracked_by inner`,
and then the various types used with `inner` also uses the macro to
implement ListArcSafe. Some of them use the untracked strategy, and some
of them use tracked_by with an AtomicListArcTracker. This way, Wrapper
just inherits whichever choice `inner` has made.
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-3-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:22 +00:00
|
|
|
use core::marker::{PhantomPinned, Unsize};
|
rust: list: add ListArc
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 for 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. Only the latter situation can lead to memory safety issues.
This patch introduces the `impl_list_arc_safe!` macro that allows you to
implement `ListArcSafe` for types using the strategy where a `ListArc`
can only be created from a `UniqueArc`. Other strategies are introduced
in later patches.
This is part of the linked list that Rust Binder will use for many
different things. The strategy where a `ListArc` can only be created
from a `UniqueArc` is actually sufficient for most of the objects that
Rust Binder needs to insert into linked lists. Usually, these are todo
items that are created and then immediately inserted into a queue.
The const generic ID allows objects to have several prev/next pointer
pairs so that the same object can be inserted into several different
lists. You are able to have several `ListArc` references as long as they
correspond to different pointer pairs. The ID itself is purely a
compile-time concept and will not be present in the final binary. Both
the `List` and the `ListArc` will need to agree on the ID for them to
work together. Rust Binder uses this in a few places (e.g. death
recipients) where the same object can be inserted into both generic todo
lists and some other lists for tracking the status of the object.
The ID is a const generic rather than a type parameter because the
`pair_from_unique` method needs to be able to assert that the two ids
are different. There's no easy way to assert that when using types
instead of integers.
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-2-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:21 +00:00
|
|
|
use core::ops::Deref;
|
|
|
|
use core::pin::Pin;
|
rust: list: add tracking for ListArc
Add the ability to track whether a ListArc exists for a given value,
allowing for the creation of ListArcs without going through UniqueArc.
The `impl_list_arc_safe!` macro is extended with a `tracked_by` strategy
that defers the tracking of ListArcs to a field of the struct.
Additionally, the AtomicListArcTracker type is introduced, which can
track whether a ListArc exists using an atomic. By deferring the
tracking to a field of type AtomicListArcTracker, structs gain the
ability to create ListArcs without going through a UniqueArc.
Rust Binder uses this for some objects where we want to be able to
insert them into a linked list at any time. Using the
AtomicListArcTracker, we are able to check whether an item is already in
the list, and if not, we can create a `ListArc` and push it.
The macro has the ability to defer the tracking of ListArcs to a field,
using whatever strategy that field has. Since we don't add any
strategies other than AtomicListArcTracker, another similar option would
be to hard-code that the field should be an AtomicListArcTracker.
However, Rust Binder has a case where the AtomicListArcTracker is not
stored directly in the struct, but in a sub-struct. Furthermore, the
outer struct is generic:
struct Wrapper<T: ?Sized> {
links: ListLinks,
inner: T,
}
Here, the Wrapper struct implements ListArcSafe with `tracked_by inner`,
and then the various types used with `inner` also uses the macro to
implement ListArcSafe. Some of them use the untracked strategy, and some
of them use tracked_by with an AtomicListArcTracker. This way, Wrapper
just inherits whichever choice `inner` has made.
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-3-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:22 +00:00
|
|
|
use core::sync::atomic::{AtomicBool, Ordering};
|
rust: list: add ListArc
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 for 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. Only the latter situation can lead to memory safety issues.
This patch introduces the `impl_list_arc_safe!` macro that allows you to
implement `ListArcSafe` for types using the strategy where a `ListArc`
can only be created from a `UniqueArc`. Other strategies are introduced
in later patches.
This is part of the linked list that Rust Binder will use for many
different things. The strategy where a `ListArc` can only be created
from a `UniqueArc` is actually sufficient for most of the objects that
Rust Binder needs to insert into linked lists. Usually, these are todo
items that are created and then immediately inserted into a queue.
The const generic ID allows objects to have several prev/next pointer
pairs so that the same object can be inserted into several different
lists. You are able to have several `ListArc` references as long as they
correspond to different pointer pairs. The ID itself is purely a
compile-time concept and will not be present in the final binary. Both
the `List` and the `ListArc` will need to agree on the ID for them to
work together. Rust Binder uses this in a few places (e.g. death
recipients) where the same object can be inserted into both generic todo
lists and some other lists for tracking the status of the object.
The ID is a const generic rather than a type parameter because the
`pair_from_unique` method needs to be able to assert that the two ids
are different. There's no easy way to assert that when using types
instead of integers.
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-2-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:21 +00:00
|
|
|
|
|
|
|
/// 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);
|
|
|
|
}
|
|
|
|
|
rust: list: add tracking for ListArc
Add the ability to track whether a ListArc exists for a given value,
allowing for the creation of ListArcs without going through UniqueArc.
The `impl_list_arc_safe!` macro is extended with a `tracked_by` strategy
that defers the tracking of ListArcs to a field of the struct.
Additionally, the AtomicListArcTracker type is introduced, which can
track whether a ListArc exists using an atomic. By deferring the
tracking to a field of type AtomicListArcTracker, structs gain the
ability to create ListArcs without going through a UniqueArc.
Rust Binder uses this for some objects where we want to be able to
insert them into a linked list at any time. Using the
AtomicListArcTracker, we are able to check whether an item is already in
the list, and if not, we can create a `ListArc` and push it.
The macro has the ability to defer the tracking of ListArcs to a field,
using whatever strategy that field has. Since we don't add any
strategies other than AtomicListArcTracker, another similar option would
be to hard-code that the field should be an AtomicListArcTracker.
However, Rust Binder has a case where the AtomicListArcTracker is not
stored directly in the struct, but in a sub-struct. Furthermore, the
outer struct is generic:
struct Wrapper<T: ?Sized> {
links: ListLinks,
inner: T,
}
Here, the Wrapper struct implements ListArcSafe with `tracked_by inner`,
and then the various types used with `inner` also uses the macro to
implement ListArcSafe. Some of them use the untracked strategy, and some
of them use tracked_by with an AtomicListArcTracker. This way, Wrapper
just inherits whichever choice `inner` has made.
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-3-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:22 +00:00
|
|
|
/// Declares that this type is able to safely attempt to create `ListArc`s at any time.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// The guarantees of `try_new_list_arc` must be upheld.
|
|
|
|
pub unsafe trait TryNewListArc<const ID: u64 = 0>: ListArcSafe<ID> {
|
|
|
|
/// Attempts to convert an `Arc<Self>` into an `ListArc<Self>`. Returns `true` if the
|
|
|
|
/// conversion was successful.
|
|
|
|
///
|
|
|
|
/// This method should not be called directly. Use [`ListArc::try_from_arc`] instead.
|
|
|
|
///
|
|
|
|
/// # Guarantees
|
|
|
|
///
|
|
|
|
/// If this call returns `true`, then there is no [`ListArc`] pointing to this value.
|
|
|
|
/// Additionally, this call will have transitioned the tracking inside `Self` from not thinking
|
|
|
|
/// that a [`ListArc`] exists, to thinking that a [`ListArc`] exists.
|
|
|
|
fn try_new_list_arc(&self) -> bool;
|
|
|
|
}
|
|
|
|
|
rust: list: add ListArc
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 for 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. Only the latter situation can lead to memory safety issues.
This patch introduces the `impl_list_arc_safe!` macro that allows you to
implement `ListArcSafe` for types using the strategy where a `ListArc`
can only be created from a `UniqueArc`. Other strategies are introduced
in later patches.
This is part of the linked list that Rust Binder will use for many
different things. The strategy where a `ListArc` can only be created
from a `UniqueArc` is actually sufficient for most of the objects that
Rust Binder needs to insert into linked lists. Usually, these are todo
items that are created and then immediately inserted into a queue.
The const generic ID allows objects to have several prev/next pointer
pairs so that the same object can be inserted into several different
lists. You are able to have several `ListArc` references as long as they
correspond to different pointer pairs. The ID itself is purely a
compile-time concept and will not be present in the final binary. Both
the `List` and the `ListArc` will need to agree on the ID for them to
work together. Rust Binder uses this in a few places (e.g. death
recipients) where the same object can be inserted into both generic todo
lists and some other lists for tracking the status of the object.
The ID is a const generic rather than a type parameter because the
`pair_from_unique` method needs to be able to assert that the two ids
are different. There's no easy way to assert that when using types
instead of integers.
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-2-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:21 +00:00
|
|
|
/// Declares that this type supports [`ListArc`].
|
|
|
|
///
|
rust: list: add tracking for ListArc
Add the ability to track whether a ListArc exists for a given value,
allowing for the creation of ListArcs without going through UniqueArc.
The `impl_list_arc_safe!` macro is extended with a `tracked_by` strategy
that defers the tracking of ListArcs to a field of the struct.
Additionally, the AtomicListArcTracker type is introduced, which can
track whether a ListArc exists using an atomic. By deferring the
tracking to a field of type AtomicListArcTracker, structs gain the
ability to create ListArcs without going through a UniqueArc.
Rust Binder uses this for some objects where we want to be able to
insert them into a linked list at any time. Using the
AtomicListArcTracker, we are able to check whether an item is already in
the list, and if not, we can create a `ListArc` and push it.
The macro has the ability to defer the tracking of ListArcs to a field,
using whatever strategy that field has. Since we don't add any
strategies other than AtomicListArcTracker, another similar option would
be to hard-code that the field should be an AtomicListArcTracker.
However, Rust Binder has a case where the AtomicListArcTracker is not
stored directly in the struct, but in a sub-struct. Furthermore, the
outer struct is generic:
struct Wrapper<T: ?Sized> {
links: ListLinks,
inner: T,
}
Here, the Wrapper struct implements ListArcSafe with `tracked_by inner`,
and then the various types used with `inner` also uses the macro to
implement ListArcSafe. Some of them use the untracked strategy, and some
of them use tracked_by with an AtomicListArcTracker. This way, Wrapper
just inherits whichever choice `inner` has made.
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-3-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:22 +00:00
|
|
|
/// This macro supports a few different strategies for implementing the tracking inside the type:
|
|
|
|
///
|
|
|
|
/// * The `untracked` strategy does not actually keep track of whether a [`ListArc`] exists. When
|
|
|
|
/// using this strategy, the only way to create a [`ListArc`] is using a [`UniqueArc`].
|
|
|
|
/// * The `tracked_by` strategy defers the tracking to a field of the struct. The user much specify
|
|
|
|
/// which field to defer the tracking to. The field must implement [`ListArcSafe`]. If the field
|
|
|
|
/// implements [`TryNewListArc`], then the type will also implement [`TryNewListArc`].
|
|
|
|
///
|
|
|
|
/// The `tracked_by` strategy is usually used by deferring to a field of type
|
|
|
|
/// [`AtomicTracker`]. However, it is also possible to defer the tracking to another struct
|
|
|
|
/// using also using this macro.
|
rust: list: add ListArc
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 for 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. Only the latter situation can lead to memory safety issues.
This patch introduces the `impl_list_arc_safe!` macro that allows you to
implement `ListArcSafe` for types using the strategy where a `ListArc`
can only be created from a `UniqueArc`. Other strategies are introduced
in later patches.
This is part of the linked list that Rust Binder will use for many
different things. The strategy where a `ListArc` can only be created
from a `UniqueArc` is actually sufficient for most of the objects that
Rust Binder needs to insert into linked lists. Usually, these are todo
items that are created and then immediately inserted into a queue.
The const generic ID allows objects to have several prev/next pointer
pairs so that the same object can be inserted into several different
lists. You are able to have several `ListArc` references as long as they
correspond to different pointer pairs. The ID itself is purely a
compile-time concept and will not be present in the final binary. Both
the `List` and the `ListArc` will need to agree on the ID for them to
work together. Rust Binder uses this in a few places (e.g. death
recipients) where the same object can be inserted into both generic todo
lists and some other lists for tracking the status of the object.
The ID is a const generic rather than a type parameter because the
`pair_from_unique` method needs to be able to assert that the two ids
are different. There's no easy way to assert that when using types
instead of integers.
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-2-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:21 +00:00
|
|
|
#[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)* }
|
|
|
|
};
|
|
|
|
|
rust: list: add tracking for ListArc
Add the ability to track whether a ListArc exists for a given value,
allowing for the creation of ListArcs without going through UniqueArc.
The `impl_list_arc_safe!` macro is extended with a `tracked_by` strategy
that defers the tracking of ListArcs to a field of the struct.
Additionally, the AtomicListArcTracker type is introduced, which can
track whether a ListArc exists using an atomic. By deferring the
tracking to a field of type AtomicListArcTracker, structs gain the
ability to create ListArcs without going through a UniqueArc.
Rust Binder uses this for some objects where we want to be able to
insert them into a linked list at any time. Using the
AtomicListArcTracker, we are able to check whether an item is already in
the list, and if not, we can create a `ListArc` and push it.
The macro has the ability to defer the tracking of ListArcs to a field,
using whatever strategy that field has. Since we don't add any
strategies other than AtomicListArcTracker, another similar option would
be to hard-code that the field should be an AtomicListArcTracker.
However, Rust Binder has a case where the AtomicListArcTracker is not
stored directly in the struct, but in a sub-struct. Furthermore, the
outer struct is generic:
struct Wrapper<T: ?Sized> {
links: ListLinks,
inner: T,
}
Here, the Wrapper struct implements ListArcSafe with `tracked_by inner`,
and then the various types used with `inner` also uses the macro to
implement ListArcSafe. Some of them use the untracked strategy, and some
of them use tracked_by with an AtomicListArcTracker. This way, Wrapper
just inherits whichever choice `inner` has made.
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-3-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:22 +00:00
|
|
|
(impl$({$($generics:tt)*})? ListArcSafe<$num:tt> for $t:ty {
|
|
|
|
tracked_by $field:ident : $fty:ty;
|
|
|
|
} $($rest:tt)*) => {
|
|
|
|
impl$(<$($generics)*>)? $crate::list::ListArcSafe<$num> for $t {
|
|
|
|
unsafe fn on_create_list_arc_from_unique(self: ::core::pin::Pin<&mut Self>) {
|
|
|
|
$crate::assert_pinned!($t, $field, $fty, inline);
|
|
|
|
|
|
|
|
// SAFETY: This field is structurally pinned as per the above assertion.
|
|
|
|
let field = unsafe {
|
|
|
|
::core::pin::Pin::map_unchecked_mut(self, |me| &mut me.$field)
|
|
|
|
};
|
|
|
|
// SAFETY: The caller promises that there is no `ListArc`.
|
|
|
|
unsafe {
|
|
|
|
<$fty as $crate::list::ListArcSafe<$num>>::on_create_list_arc_from_unique(field)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
unsafe fn on_drop_list_arc(&self) {
|
|
|
|
// SAFETY: The caller promises that there is no `ListArc` reference, and also
|
|
|
|
// promises that the tracking thinks there is a `ListArc` reference.
|
|
|
|
unsafe { <$fty as $crate::list::ListArcSafe<$num>>::on_drop_list_arc(&self.$field) };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unsafe impl$(<$($generics)*>)? $crate::list::TryNewListArc<$num> for $t
|
|
|
|
where
|
|
|
|
$fty: TryNewListArc<$num>,
|
|
|
|
{
|
|
|
|
fn try_new_list_arc(&self) -> bool {
|
|
|
|
<$fty as $crate::list::TryNewListArc<$num>>::try_new_list_arc(&self.$field)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$crate::list::impl_list_arc_safe! { $($rest)* }
|
|
|
|
};
|
|
|
|
|
rust: list: add ListArc
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 for 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. Only the latter situation can lead to memory safety issues.
This patch introduces the `impl_list_arc_safe!` macro that allows you to
implement `ListArcSafe` for types using the strategy where a `ListArc`
can only be created from a `UniqueArc`. Other strategies are introduced
in later patches.
This is part of the linked list that Rust Binder will use for many
different things. The strategy where a `ListArc` can only be created
from a `UniqueArc` is actually sufficient for most of the objects that
Rust Binder needs to insert into linked lists. Usually, these are todo
items that are created and then immediately inserted into a queue.
The const generic ID allows objects to have several prev/next pointer
pairs so that the same object can be inserted into several different
lists. You are able to have several `ListArc` references as long as they
correspond to different pointer pairs. The ID itself is purely a
compile-time concept and will not be present in the final binary. Both
the `List` and the `ListArc` will need to agree on the ID for them to
work together. Rust Binder uses this in a few places (e.g. death
recipients) where the same object can be inserted into both generic todo
lists and some other lists for tracking the status of the object.
The ID is a const generic rather than a type parameter because the
`pair_from_unique` method needs to be able to assert that the two ids
are different. There's no easy way to assert that when using types
instead of integers.
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-2-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:21 +00:00
|
|
|
() => {};
|
|
|
|
}
|
|
|
|
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),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
rust: list: add tracking for ListArc
Add the ability to track whether a ListArc exists for a given value,
allowing for the creation of ListArcs without going through UniqueArc.
The `impl_list_arc_safe!` macro is extended with a `tracked_by` strategy
that defers the tracking of ListArcs to a field of the struct.
Additionally, the AtomicListArcTracker type is introduced, which can
track whether a ListArc exists using an atomic. By deferring the
tracking to a field of type AtomicListArcTracker, structs gain the
ability to create ListArcs without going through a UniqueArc.
Rust Binder uses this for some objects where we want to be able to
insert them into a linked list at any time. Using the
AtomicListArcTracker, we are able to check whether an item is already in
the list, and if not, we can create a `ListArc` and push it.
The macro has the ability to defer the tracking of ListArcs to a field,
using whatever strategy that field has. Since we don't add any
strategies other than AtomicListArcTracker, another similar option would
be to hard-code that the field should be an AtomicListArcTracker.
However, Rust Binder has a case where the AtomicListArcTracker is not
stored directly in the struct, but in a sub-struct. Furthermore, the
outer struct is generic:
struct Wrapper<T: ?Sized> {
links: ListLinks,
inner: T,
}
Here, the Wrapper struct implements ListArcSafe with `tracked_by inner`,
and then the various types used with `inner` also uses the macro to
implement ListArcSafe. Some of them use the untracked strategy, and some
of them use tracked_by with an AtomicListArcTracker. This way, Wrapper
just inherits whichever choice `inner` has made.
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-3-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:22 +00:00
|
|
|
/// Try to create a new `ListArc`.
|
|
|
|
///
|
|
|
|
/// This fails if this value already has a `ListArc`.
|
|
|
|
pub fn try_from_arc(arc: Arc<T>) -> Result<Self, Arc<T>>
|
|
|
|
where
|
|
|
|
T: TryNewListArc<ID>,
|
|
|
|
{
|
|
|
|
if arc.try_new_list_arc() {
|
|
|
|
// SAFETY: The `try_new_list_arc` method returned true, so we made the tracking think
|
|
|
|
// that a `ListArc` exists. This lets us create a `ListArc`.
|
|
|
|
Ok(unsafe { Self::transmute_from_arc(arc) })
|
|
|
|
} else {
|
|
|
|
Err(arc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to create a new `ListArc`.
|
|
|
|
///
|
|
|
|
/// This fails if this value already has a `ListArc`.
|
|
|
|
pub fn try_from_arc_borrow(arc: ArcBorrow<'_, T>) -> Option<Self>
|
|
|
|
where
|
|
|
|
T: TryNewListArc<ID>,
|
|
|
|
{
|
|
|
|
if arc.try_new_list_arc() {
|
|
|
|
// SAFETY: The `try_new_list_arc` method returned true, so we made the tracking think
|
|
|
|
// that a `ListArc` exists. This lets us create a `ListArc`.
|
|
|
|
Some(unsafe { Self::transmute_from_arc(Arc::from(arc)) })
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to create a new `ListArc`.
|
|
|
|
///
|
|
|
|
/// If it's not possible to create a new `ListArc`, then the `Arc` is dropped. This will never
|
|
|
|
/// run the destructor of the value.
|
|
|
|
pub fn try_from_arc_or_drop(arc: Arc<T>) -> Option<Self>
|
|
|
|
where
|
|
|
|
T: TryNewListArc<ID>,
|
|
|
|
{
|
|
|
|
match Self::try_from_arc(arc) {
|
|
|
|
Ok(list_arc) => Some(list_arc),
|
|
|
|
Err(arc) => Arc::into_unique_or_drop(arc).map(Self::from),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
rust: list: add ListArc
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 for 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. Only the latter situation can lead to memory safety issues.
This patch introduces the `impl_list_arc_safe!` macro that allows you to
implement `ListArcSafe` for types using the strategy where a `ListArc`
can only be created from a `UniqueArc`. Other strategies are introduced
in later patches.
This is part of the linked list that Rust Binder will use for many
different things. The strategy where a `ListArc` can only be created
from a `UniqueArc` is actually sufficient for most of the objects that
Rust Binder needs to insert into linked lists. Usually, these are todo
items that are created and then immediately inserted into a queue.
The const generic ID allows objects to have several prev/next pointer
pairs so that the same object can be inserted into several different
lists. You are able to have several `ListArc` references as long as they
correspond to different pointer pairs. The ID itself is purely a
compile-time concept and will not be present in the final binary. Both
the `List` and the `ListArc` will need to agree on the ID for them to
work together. Rust Binder uses this in a few places (e.g. death
recipients) where the same object can be inserted into both generic todo
lists and some other lists for tracking the status of the object.
The ID is a const generic rather than a type parameter because the
`pair_from_unique` method needs to be able to assert that the two ids
are different. There's no easy way to assert that when using types
instead of integers.
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-2-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:21 +00:00
|
|
|
/// 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.arc
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns an [`ArcBorrow`] from the given [`ListArc`].
|
|
|
|
///
|
|
|
|
/// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method
|
|
|
|
/// receiver), but we have an [`Arc`] instead. Getting an [`ArcBorrow`] is free when optimised.
|
|
|
|
#[inline]
|
|
|
|
pub fn as_arc_borrow(&self) -> ArcBorrow<'_, T> {
|
|
|
|
self.arc.as_arc_borrow()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Compare whether two [`ListArc`] pointers reference the same underlying object.
|
|
|
|
#[inline]
|
|
|
|
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
|
|
|
|
Arc::ptr_eq(&this.arc, &other.arc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, const ID: u64> Deref for ListArc<T, ID>
|
|
|
|
where
|
|
|
|
T: ListArcSafe<ID> + ?Sized,
|
|
|
|
{
|
|
|
|
type Target = T;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
self.arc.deref()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, const ID: u64> Drop for ListArc<T, ID>
|
|
|
|
where
|
|
|
|
T: ListArcSafe<ID> + ?Sized,
|
|
|
|
{
|
|
|
|
#[inline]
|
|
|
|
fn drop(&mut self) {
|
|
|
|
// SAFETY: There is no longer a `ListArc`, but the tracking thinks there is by the type
|
|
|
|
// invariants on `Self`.
|
|
|
|
unsafe { T::on_drop_list_arc(&self.arc) };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T, const ID: u64> AsRef<Arc<T>> for ListArc<T, ID>
|
|
|
|
where
|
|
|
|
T: ListArcSafe<ID> + ?Sized,
|
|
|
|
{
|
|
|
|
#[inline]
|
|
|
|
fn as_ref(&self) -> &Arc<T> {
|
|
|
|
self.as_arc()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is to allow [`ListArc`] (and variants) to be used as the type of `self`.
|
|
|
|
impl<T, const ID: u64> core::ops::Receiver for ListArc<T, ID> where T: ListArcSafe<ID> + ?Sized {}
|
|
|
|
|
|
|
|
// This is to allow coercion from `ListArc<T>` to `ListArc<U>` if `T` can be converted to the
|
|
|
|
// dynamically-sized type (DST) `U`.
|
|
|
|
impl<T, U, const ID: u64> core::ops::CoerceUnsized<ListArc<U, ID>> for ListArc<T, ID>
|
|
|
|
where
|
|
|
|
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
|
|
|
|
U: ListArcSafe<ID> + ?Sized,
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is to allow `ListArc<U>` to be dispatched on when `ListArc<T>` can be coerced into
|
|
|
|
// `ListArc<U>`.
|
|
|
|
impl<T, U, const ID: u64> core::ops::DispatchFromDyn<ListArc<U, ID>> for ListArc<T, ID>
|
|
|
|
where
|
|
|
|
T: ListArcSafe<ID> + Unsize<U> + ?Sized,
|
|
|
|
U: ListArcSafe<ID> + ?Sized,
|
|
|
|
{
|
|
|
|
}
|
rust: list: add tracking for ListArc
Add the ability to track whether a ListArc exists for a given value,
allowing for the creation of ListArcs without going through UniqueArc.
The `impl_list_arc_safe!` macro is extended with a `tracked_by` strategy
that defers the tracking of ListArcs to a field of the struct.
Additionally, the AtomicListArcTracker type is introduced, which can
track whether a ListArc exists using an atomic. By deferring the
tracking to a field of type AtomicListArcTracker, structs gain the
ability to create ListArcs without going through a UniqueArc.
Rust Binder uses this for some objects where we want to be able to
insert them into a linked list at any time. Using the
AtomicListArcTracker, we are able to check whether an item is already in
the list, and if not, we can create a `ListArc` and push it.
The macro has the ability to defer the tracking of ListArcs to a field,
using whatever strategy that field has. Since we don't add any
strategies other than AtomicListArcTracker, another similar option would
be to hard-code that the field should be an AtomicListArcTracker.
However, Rust Binder has a case where the AtomicListArcTracker is not
stored directly in the struct, but in a sub-struct. Furthermore, the
outer struct is generic:
struct Wrapper<T: ?Sized> {
links: ListLinks,
inner: T,
}
Here, the Wrapper struct implements ListArcSafe with `tracked_by inner`,
and then the various types used with `inner` also uses the macro to
implement ListArcSafe. Some of them use the untracked strategy, and some
of them use tracked_by with an AtomicListArcTracker. This way, Wrapper
just inherits whichever choice `inner` has made.
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-3-f5f5e8075da0@google.com
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
2024-08-14 08:05:22 +00:00
|
|
|
|
|
|
|
/// A utility for tracking whether a [`ListArc`] exists using an atomic.
|
|
|
|
///
|
|
|
|
/// # Invariant
|
|
|
|
///
|
|
|
|
/// If the boolean is `false`, then there is no [`ListArc`] for this value.
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct AtomicTracker<const ID: u64 = 0> {
|
|
|
|
inner: AtomicBool,
|
|
|
|
// This value needs to be pinned to justify the INVARIANT: comment in `AtomicTracker::new`.
|
|
|
|
_pin: PhantomPinned,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<const ID: u64> AtomicTracker<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`.
|
|
|
|
Self {
|
|
|
|
inner: AtomicBool::new(false),
|
|
|
|
_pin: PhantomPinned,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn project_inner(self: Pin<&mut Self>) -> &mut AtomicBool {
|
|
|
|
// SAFETY: The `inner` field is not structurally pinned, so we may obtain a mutable
|
|
|
|
// reference to it even if we only have a pinned reference to `self`.
|
|
|
|
unsafe { &mut Pin::into_inner_unchecked(self).inner }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<const ID: u64> ListArcSafe<ID> for AtomicTracker<ID> {
|
|
|
|
unsafe fn on_create_list_arc_from_unique(self: Pin<&mut Self>) {
|
|
|
|
// INVARIANT: We just created a ListArc, so the boolean should be true.
|
|
|
|
*self.project_inner().get_mut() = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn on_drop_list_arc(&self) {
|
|
|
|
// INVARIANT: We just dropped a ListArc, so the boolean should be false.
|
|
|
|
self.inner.store(false, Ordering::Release);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SAFETY: If this method returns `true`, then by the type invariant there is no `ListArc` before
|
|
|
|
// this call, so it is okay to create a new `ListArc`.
|
|
|
|
//
|
|
|
|
// The acquire ordering will synchronize with the release store from the destruction of any
|
|
|
|
// previous `ListArc`, so if there was a previous `ListArc`, then the destruction of the previous
|
|
|
|
// `ListArc` happens-before the creation of the new `ListArc`.
|
|
|
|
unsafe impl<const ID: u64> TryNewListArc<ID> for AtomicTracker<ID> {
|
|
|
|
fn try_new_list_arc(&self) -> bool {
|
|
|
|
// INVARIANT: If this method returns true, then the boolean used to be false, and is no
|
|
|
|
// longer false, so it is okay for the caller to create a new [`ListArc`].
|
|
|
|
self.inner
|
|
|
|
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
|
|
|
|
.is_ok()
|
|
|
|
}
|
|
|
|
}
|