All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gary Guo <gary@garyguo.net>
To: Wedson Almeida Filho <wedsonaf@gmail.com>
Cc: rust-for-linux@vger.kernel.org, "Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH 4/7] rust: sync: introduce `ArcBorrow`
Date: Sat, 31 Dec 2022 19:43:52 +0000	[thread overview]
Message-ID: <20221231194352.55cf0a26.gary@garyguo.net> (raw)
In-Reply-To: <20221228060346.352362-4-wedsonaf@gmail.com>

On Wed, 28 Dec 2022 06:03:43 +0000
Wedson Almeida Filho <wedsonaf@gmail.com> wrote:

> This allows us to create references to a ref-counted allocation without
> double-indirection and that still allow us to increment the refcount to
> a new `Arc<T>`.
> 
> Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
> ---
>  rust/kernel/sync.rs     |  2 +-
>  rust/kernel/sync/arc.rs | 97 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 98 insertions(+), 1 deletion(-)
> 
> diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
> index 39b379dd548f..5de03ea83ea1 100644
> --- a/rust/kernel/sync.rs
> +++ b/rust/kernel/sync.rs
> @@ -7,4 +7,4 @@
>  
>  mod arc;
>  
> -pub use arc::Arc;
> +pub use arc::{Arc, ArcBorrow};
> diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
> index dbc7596cc3ce..f68bfc02c81a 100644
> --- a/rust/kernel/sync/arc.rs
> +++ b/rust/kernel/sync/arc.rs
> @@ -19,6 +19,7 @@ use crate::{bindings, error::Result, types::Opaque};
>  use alloc::boxed::Box;
>  use core::{
>      marker::{PhantomData, Unsize},
> +    mem::ManuallyDrop,
>      ops::Deref,
>      ptr::NonNull,
>  };
> @@ -164,6 +165,18 @@ impl<T: ?Sized> Arc<T> {
>              _p: PhantomData,
>          }
>      }
> +
> +    /// Returns an [`ArcBorrow`] from the given [`Arc`].
> +    ///
> +    /// 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> {
> +        // SAFETY: The constraint that the lifetime of the shared reference must outlive that of
> +        // the returned `ArcBorrow` ensures that the object remains alive and that no mutable
> +        // reference can be created.
> +        unsafe { ArcBorrow::new(self.ptr) }
> +    }
>  }
>  
>  impl<T: ?Sized> Deref for Arc<T> {
> @@ -208,3 +221,87 @@ impl<T: ?Sized> Drop for Arc<T> {
>          }
>      }
>  }
> +
> +/// A borrowed reference to an [`Arc`] instance.
> +///
> +/// For cases when one doesn't ever need to increment the refcount on the allocation, it is simpler
> +/// to use just `&T`, which we can trivially get from an `Arc<T>` instance.
> +///
> +/// However, when one may need to increment the refcount, it is preferable to use an `ArcBorrow<T>`
> +/// over `&Arc<T>` because the latter results in a double-indirection: a pointer (shared reference)
> +/// to a pointer (`Arc<T>`) to the object (`T`). An [`ArcBorrow`] eliminates this double
> +/// indirection while still allowing one to increment the refcount and getting an `Arc<T>` when/if
> +/// needed.
> +///
> +/// # Invariants
> +///
> +/// There are no mutable references to the underlying [`Arc`], and it remains valid for the
> +/// lifetime of the [`ArcBorrow`] instance.
> +///
> +/// # Example
> +///
> +/// ```
> +/// use crate::sync::{Arc, ArcBorrow};
> +///
> +/// struct Example;
> +///
> +/// fn do_something(e: ArcBorrow<'_, Example>) -> Arc<Example> {
> +///     e.into()
> +/// }
> +///
> +/// let obj = Arc::try_new(Example)?;
> +/// let cloned = do_something(obj.as_arc_borrow());
> +///
> +/// // Assert that both `obj` and `cloned` point to the same underlying object.
> +/// assert!(core::ptr::eq(&*obj, &*cloned));
> +/// ```
> +pub struct ArcBorrow<'a, T: ?Sized + 'a> {
> +    inner: NonNull<ArcInner<T>>,
> +    _p: PhantomData<&'a ()>,
> +}
> +
> +impl<T: ?Sized> Clone for ArcBorrow<'_, T> {
> +    fn clone(&self) -> Self {
> +        *self
> +    }
> +}
> +
> +impl<T: ?Sized> Copy for ArcBorrow<'_, T> {}

Couldn't this just be derived `Clone` and `Copy`?

> +
> +impl<T: ?Sized> ArcBorrow<'_, T> {
> +    /// Creates a new [`ArcBorrow`] instance.
> +    ///
> +    /// # Safety
> +    ///
> +    /// Callers must ensure the following for the lifetime of the returned [`ArcBorrow`] instance:
> +    /// 1. That `inner` remains valid;
> +    /// 2. That no mutable references to `inner` are created.
> +    unsafe fn new(inner: NonNull<ArcInner<T>>) -> Self {
> +        // INVARIANT: The safety requirements guarantee the invariants.
> +        Self {
> +            inner,
> +            _p: PhantomData,
> +        }
> +    }
> +}
> +
> +impl<T: ?Sized> From<ArcBorrow<'_, T>> for Arc<T> {
> +    fn from(b: ArcBorrow<'_, T>) -> Self {
> +        // SAFETY: The existence of `b` guarantees that the refcount is non-zero. `ManuallyDrop`
> +        // guarantees that `drop` isn't called, so it's ok that the temporary `Arc` doesn't own the
> +        // increment.
> +        ManuallyDrop::new(unsafe { Arc::from_inner(b.inner) })
> +            .deref()
> +            .clone()
> +    }
> +}

It might be easier to follow if this is jsut `bindings::refcount_inc`
followed by `Arc::from_inner`?

> +
> +impl<T: ?Sized> Deref for ArcBorrow<'_, T> {
> +    type Target = T;
> +
> +    fn deref(&self) -> &Self::Target {
> +        // SAFETY: By the type invariant, the underlying object is still alive with no mutable
> +        // references to it, so it is safe to create a shared reference.
> +        unsafe { &self.inner.as_ref().data }
> +    }
> +}

  parent reply	other threads:[~2022-12-31 19:43 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-28  6:03 [PATCH 1/7] rust: sync: add `Arc` for ref-counted allocations Wedson Almeida Filho
2022-12-28  6:03 ` [PATCH 2/7] rust: sync: allow type of `self` to be `Arc<T>` or variants Wedson Almeida Filho
2022-12-28 10:03   ` Alice Ryhl
2022-12-31 19:37   ` Gary Guo
2023-01-04 16:12   ` Vincenzo
2022-12-28  6:03 ` [PATCH 3/7] rust: sync: allow coercion from `Arc<T>` to `Arc<U>` Wedson Almeida Filho
2022-12-28 10:03   ` Alice Ryhl
2022-12-31 19:37   ` Gary Guo
2023-01-04 16:13   ` Vincenzo
2022-12-28  6:03 ` [PATCH 4/7] rust: sync: introduce `ArcBorrow` Wedson Almeida Filho
2022-12-28  7:15   ` Laine Taffin Altman
2022-12-28 10:03   ` Alice Ryhl
2022-12-31 19:43   ` Gary Guo [this message]
2023-01-04 15:29     ` Wedson Almeida Filho
2023-01-04 16:06       ` Emilio Cobos Álvarez
2023-01-04 17:52         ` Wedson Almeida Filho
2023-01-16 22:07         ` Gary Guo
2023-01-21  0:44           ` Boqun Feng
2023-01-16 22:42   ` Vincenzo Palazzo
2022-12-28  6:03 ` [PATCH 5/7] rust: sync: allow type of `self` to be `ArcBorrow<T>` Wedson Almeida Filho
2022-12-28 10:04   ` Alice Ryhl
2022-12-31 19:44   ` Gary Guo
2023-01-04 16:18   ` Vincenzo
2022-12-28  6:03 ` [PATCH 6/7] rust: sync: introduce `UniqueArc` Wedson Almeida Filho
2022-12-28  7:19   ` Laine Taffin Altman
2022-12-31 19:46     ` Gary Guo
2022-12-28 10:04   ` Alice Ryhl
2022-12-31 19:47   ` Gary Guo
2023-01-04 16:21   ` Vincenzo
2022-12-28  6:03 ` [PATCH 7/7] rust: sync: add support for dispatching on Arc and ArcBorrow Wedson Almeida Filho
2022-12-28  7:24   ` Laine Taffin Altman
2022-12-31 19:51     ` Gary Guo
2022-12-28 10:04   ` Alice Ryhl
2022-12-31 19:52   ` Gary Guo
2023-01-04 16:26   ` Vincenzo
2022-12-28  7:09 ` [PATCH 1/7] rust: sync: add `Arc` for ref-counted allocations Laine Taffin Altman
2022-12-28  7:27   ` Wedson Almeida Filho
2022-12-28  7:32     ` Laine Taffin Altman
2022-12-28 10:03 ` Alice Ryhl
2022-12-28 10:14   ` Wedson Almeida Filho
2022-12-28 10:38     ` Alice Ryhl
2022-12-31 19:55 ` Gary Guo
2023-01-04 16:08 ` Vincenzo
2023-01-10 20:22 ` Boqun Feng
2023-01-10 21:20   ` Peter Zijlstra
2023-01-10 21:36     ` Boqun Feng
2023-01-10 21:54       ` Peter Zijlstra
2023-01-16 21:06   ` Boqun Feng
2023-01-16 23:34 ` Miguel Ojeda

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=20221231194352.55cf0a26.gary@garyguo.net \
    --to=gary@garyguo.net \
    --cc=alex.gaynor@gmail.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=wedsonaf@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.