From: Benno Lossin <benno.lossin@proton.me>
To: Danilo Krummrich <dakr@redhat.com>,
ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com,
boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com,
a.hindborg@samsung.com, aliceryhl@google.com
Cc: daniel.almeida@collabora.com, faith.ekstrand@collabora.com,
boris.brezillon@collabora.com, lina@asahilina.net,
mcanal@igalia.com, zhiw@nvidia.com, acurrid@nvidia.com,
cjia@nvidia.com, jhubbard@nvidia.com, airlied@redhat.com,
ajanulgu@redhat.com, lyude@redhat.com,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org
Subject: Re: [PATCH 09/20] rust: types: implement `Unique<T>`
Date: Sat, 06 Jul 2024 10:59:09 +0000 [thread overview]
Message-ID: <fa6d6c0a-17eb-4280-baa3-df5f97e58497@proton.me> (raw)
In-Reply-To: <20240704170738.3621-10-dakr@redhat.com>
On 04.07.24 19:06, Danilo Krummrich wrote:
> Implement the `Unique` type as a prerequisite for `KBox` and `Kvec`
> introduced in subsequent patches.
>
> `Unique` serves as wrapper around a `NonNull`, but indicates that the
> possessor of this wrapper owns the referent.
>
> This type already exists in Rust's core library, but, unfortunately, is
> exposed as unstable API and hence shouldn't be used in the kernel.
It's not really exposed, as the feature (ptr_internals) is an internal
unstable feature and thus probably perma-unstable.
(but your argument still holds, this just means that we *really* should
not be using it)
> This implementation of `Unique` is almost identical, but mostly stripped
> down to the functionality we need for `KBox` and `KVec`. Additionally,
> all unstable features are removed and / or replaced by stable ones.
>
> Signed-off-by: Danilo Krummrich <dakr@redhat.com>
> ---
> rust/kernel/types.rs | 176 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 176 insertions(+)
>
> diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
> index 2e7c9008621f..281327ea2932 100644
> --- a/rust/kernel/types.rs
> +++ b/rust/kernel/types.rs
> @@ -409,3 +409,179 @@ pub enum Either<L, R> {
> /// Constructs an instance of [`Either`] containing a value of type `R`.
> Right(R),
> }
> +
> +/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
> +/// of this wrapper owns the referent. Useful for building abstractions like
> +/// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`.
> +///
> +/// Unlike `*mut T`, `Unique<T>` behaves "as if" it were an instance of `T`.
> +/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies
> +/// the kind of strong aliasing guarantees an instance of `T` can expect:
> +/// the referent of the pointer should not be modified without a unique path to
> +/// its owning Unique.
> +///
> +/// If you're uncertain of whether it's correct to use `Unique` for your purposes,
> +/// consider using `NonNull`, which has weaker semantics.
> +///
> +/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
> +/// is never dereferenced. This is so that enums may use this forbidden value
> +/// as a discriminant -- `Option<Unique<T>>` has the same size as `Unique<T>`.
> +/// However the pointer may still dangle if it isn't dereferenced.
> +///
> +/// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct
> +/// for any type which upholds Unique's aliasing requirements.
Since you copied this directly from the stdlib, should this be citing
it?
> +#[repr(transparent)]
> +pub struct Unique<T: ?Sized> {
> + pointer: NonNull<T>,
Gary and I already mentioned this in the meeting, but I will put it here
for the record:
The `Unique` from std is special, in the sense that the Rust compiler
will emit the `noalias` LLVM attribute.
This gives std's `Box` type a possible performance advantage (IIRC Gary
had a compiler explorer example that showed different instruction
count).
I thought that we could mimic this behavior if we would change the type
of `pointer` to `ManuallyDrop<Box<T>>`. But that only works if the
pointer is always valid, since otherwise we can't call `Box::from_raw`.
So currently I don't see a workaround that would give us the noalias
attribute back.
It would be a good idea to get some benchmarks on how this affects
performance, Andreas or Alice do you think you can give a bit of compute
time, once this patchset is more mature?
> + // NOTE: this marker has no consequences for variance, but is necessary
> + // for dropck to understand that we logically own a `T`.
> + //
> + // For details, see:
> + // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
> + _marker: PhantomData<T>,
> +}
> +
> +/// `Unique` pointers are `Send` if `T` is `Send` because the data they
> +/// reference is unaliased. Note that this aliasing invariant is
> +/// unenforced by the type system; the abstraction using the
> +/// `Unique` must enforce it.
> +unsafe impl<T: Send + ?Sized> Send for Unique<T> {}
> +
> +/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
> +/// reference is unaliased. Note that this aliasing invariant is
> +/// unenforced by the type system; the abstraction using the
> +/// `Unique` must enforce it.
> +unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}
> +
> +impl<T: Sized> Unique<T> {
> + /// Creates a new `Unique` that is dangling, but well-aligned.
> + ///
> + /// This is useful for initializing types which lazily allocate, like
> + /// `Vec::new` does.
> + ///
> + /// Note that the pointer value may potentially represent a valid pointer to
> + /// a `T`, which means this must not be used as a "not yet initialized"
> + /// sentinel value. Types that lazily allocate must track initialization by
> + /// some other means.
> + #[must_use]
> + #[inline]
> + pub const fn dangling() -> Self {
> + Unique {
> + pointer: NonNull::dangling(),
> + _marker: PhantomData,
> + }
> + }
> +}
> +
> +impl<T: ?Sized> Unique<T> {
> + /// Creates a new `Unique`.
> + ///
> + /// # Safety
> + ///
> + /// `ptr` must be non-null.
> + #[inline]
> + pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
> + // SAFETY: the caller must guarantee that `ptr` is non-null.
> + unsafe {
> + Unique {
> + pointer: NonNull::new_unchecked(ptr),
> + _marker: PhantomData,
> + }
> + }
> + }
> +
> + /// Creates a new `Unique` if `ptr` is non-null.
> + #[allow(clippy::manual_map)]
> + #[inline]
> + pub fn new(ptr: *mut T) -> Option<Self> {
I think we should give `Unique` the invariant that it is unique, making
this function `unsafe`, since the caller must ensure that only this
unique has access to the pointee.
---
Cheers,
Benno
> + if let Some(pointer) = NonNull::new(ptr) {
> + Some(Unique {
> + pointer,
> + _marker: PhantomData,
> + })
> + } else {
> + None
> + }
> + }
next prev parent reply other threads:[~2024-07-06 10:59 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-04 17:06 [PATCH 00/20] Generic `Allocator` support for Rust Danilo Krummrich
2024-07-04 17:06 ` [PATCH 01/20] rust: alloc: add `Allocator` trait Danilo Krummrich
2024-07-06 10:33 ` Benno Lossin
2024-07-06 11:05 ` Danilo Krummrich
2024-07-06 13:17 ` Benno Lossin
2024-07-06 15:11 ` Danilo Krummrich
2024-07-06 17:08 ` Benno Lossin
2024-07-06 18:47 ` Danilo Krummrich
2024-07-08 8:12 ` Benno Lossin
2024-07-08 23:12 ` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 02/20] rust: alloc: separate `aligned_size` from `krealloc_aligned` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 03/20] rust: alloc: rename `KernelAllocator` to `Kmalloc` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 04/20] rust: alloc: implement `Allocator` for `Kmalloc` Danilo Krummrich
2024-07-06 10:37 ` Benno Lossin
2024-07-06 11:08 ` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 05/20] rust: alloc: add module `allocator_test` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 06/20] rust: alloc: remove `krealloc_aligned` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 07/20] rust: alloc: implement `Vmalloc` allocator Danilo Krummrich
2024-07-06 10:41 ` Benno Lossin
2024-07-06 11:13 ` Danilo Krummrich
2024-07-06 13:21 ` Benno Lossin
2024-07-06 15:16 ` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 08/20] rust: alloc: implement `KVmalloc` allocator Danilo Krummrich
2024-07-04 17:06 ` [PATCH 09/20] rust: types: implement `Unique<T>` Danilo Krummrich
2024-07-06 10:59 ` Benno Lossin [this message]
2024-07-06 12:40 ` Miguel Ojeda
2024-07-06 13:37 ` Benno Lossin
2024-07-04 17:06 ` [PATCH 10/20] rust: alloc: implement `KBox` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 11/20] rust: treewide: switch to `KBox` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 12/20] rust: alloc: remove `BoxExt` extension Danilo Krummrich
2024-07-04 17:06 ` [PATCH 13/20] rust: alloc: implement `KVec` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 14/20] rust: alloc: implement `IntoIterator` for `KVec` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 15/20] rust: alloc: implement `collect` for `IntoIter` Danilo Krummrich
2024-07-04 23:27 ` Boqun Feng
2024-07-05 1:23 ` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 16/20] rust: treewide: switch to `KVec` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 17/20] rust: alloc: remove `VecExt` extension Danilo Krummrich
2024-07-04 17:06 ` [PATCH 18/20] rust: error: use `core::alloc::LayoutError` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 19/20] rust: str: test: replace `alloc::format` Danilo Krummrich
2024-07-04 17:06 ` [PATCH 20/20] kbuild: rust: remove the `alloc` crate Danilo Krummrich
2024-07-06 3:59 ` kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fa6d6c0a-17eb-4280-baa3-df5f97e58497@proton.me \
--to=benno.lossin@proton.me \
--cc=a.hindborg@samsung.com \
--cc=acurrid@nvidia.com \
--cc=airlied@redhat.com \
--cc=ajanulgu@redhat.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=boris.brezillon@collabora.com \
--cc=cjia@nvidia.com \
--cc=dakr@redhat.com \
--cc=daniel.almeida@collabora.com \
--cc=faith.ekstrand@collabora.com \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=lina@asahilina.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lyude@redhat.com \
--cc=mcanal@igalia.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=wedsonaf@gmail.com \
--cc=zhiw@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).