From nobody Sun Feb 8 02:56:17 2026 Received: from mail-40134.protonmail.ch (mail-40134.protonmail.ch [185.70.40.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4C7CE1C84B5; Fri, 7 Mar 2025 10:04:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.70.40.134 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741341858; cv=none; b=jrbl6sIL/VZpJXCi+W1ByC38GH3WBiNkfxiVCyiZKrdRBOHel14Kt07az2bRlpD0h+0bsIujilhLmbjLkOLWeoDeekB007WBjWr+qhYMuf/EpJfd/oVglciLj7P4jWXnAabLLYBdfc0V6wPAF39mJ1E3S8cTqOWUkZdyJzMenGg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741341858; c=relaxed/simple; bh=vUYJIpzrPPNsd45VqzFVWUJNCTyAKU0dXIDQudSDGKU=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=j+KbHRlvLW64syfBSxr7w7CDuz4dFsCmYd5SQQOx9+JeM+a0Vy03BlzofGbFaCQCvgXxCtcaC6uSdaRL3Ga7vnBge3bbGLLMYm11tAcadIX0teJVCX+VuuspRsprtK2D6OhkE4h7sJ36iHnwruGpIUl0F6y34TdOFORIz+k3ve0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=L2Wdp+g8; arc=none smtp.client-ip=185.70.40.134 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="L2Wdp+g8" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1741341853; x=1741601053; bh=2Zpu6E3/Y16UltqXkAaLIudQV1ASZITnWKAwSutW1Y8=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=L2Wdp+g8AQLlqdlfTxkjFb+QkKuQ8r4HpikKK7oR615X7CAkQCIG0r0+rWJgdawSa iZ2D9DuOgAwiVdg7S3/o2E1o9jMsQPOu4Re5/m6mR7AJWt9gq8QoaLqVUWnGO3Isf9 /cMlGga2GqW0AyJG+BElasQN7F2wY9uz2rfzNBCRDAz2TZ7zOrR/MVz7DQwiNqPkNj aSpCFH0OMf+PgH+CtgVdLKeByHLZkvz1EypDSnVRMUMbHUa0vPN1WYSlq0V0miCXFs ISTSEv8rUHEFyHgtS3PBjtrGzNEnCe/dPE0ib4PizNg5Xcb3hjd45bWZ6Nd2cMEWdJ bADZod7BjhJ/Q== Date: Fri, 07 Mar 2025 10:04:09 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v5 1/4] rust: types: Add Ownable/Owned types Message-ID: <20250307-unique-ref-v5-1-bffeb633277e@pm.me> In-Reply-To: <20250307-unique-ref-v5-0-bffeb633277e@pm.me> References: <20250307-unique-ref-v5-0-bffeb633277e@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 2fb0fc540ab07853945857e8c687b233bec6e4ac Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Asahi Lina By analogy to AlwaysRefCounted and ARef, an Ownable type is a (typically C FFI) type that *may* be owned by Rust, but need not be. Unlike AlwaysRefCounted, this mechanism expects the reference to be unique within Rust, and does not allow cloning. Conceptually, this is similar to a KBox, except that it delegates resource management to the T instead of using a generic allocator. Signed-off-by: Asahi Lina --- rust/kernel/types.rs | 110 +++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 110 insertions(+) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 55ddd50e8aaa075ac33d5f1088a7f72df05f74f4..0cae5ba6607f0a86d2f0e3494f9= 56f6daad78067 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -551,6 +551,116 @@ fn drop(&mut self) { } } =20 +/// Types that may be owned by Rust code or borrowed, but have a lifetime = managed by C code. +/// +/// It allows such types to define their own custom destructor function to= be called when +/// a Rust-owned reference is dropped. +/// +/// This is usually implemented by wrappers to existing structures on the = C side of the code. +/// +/// # Safety +/// +/// Implementers must ensure that any objects borrowed directly as `&T` st= ay alive for the duration +/// of the lifetime, and that any objects owned by Rust as `Owned`) sta= y alive while that owned +/// reference exists, until the [`Ownable::release()`] trait method is cal= led. +pub unsafe trait Ownable { + /// Releases the object (frees it or returns it to foreign ownership). + /// + /// # Safety + /// + /// Callers must ensure that the object is no longer referenced after = this call. + unsafe fn release(this: NonNull); +} + +/// A subtrait of Ownable that asserts that an `Owned` Rust reference i= s not only unique +/// within Rust and keeps the `T` alive, but also guarantees that the C co= de follows the +/// usual mutable reference requirements. That is, the kernel will never m= utate the +/// `T` (excluding internal mutability that follows the usual rules) while= Rust owns it. +/// +/// When this type is implemented for an [`Ownable`] type, it allows `Owne= d` to be +/// dereferenced into a &mut T. +/// +/// # Safety +/// +/// Implementers must ensure that the kernel never mutates the underlying = type while +/// Rust owns it. +pub unsafe trait OwnableMut: Ownable {} + +/// An owned reference to an ownable kernel object. +/// +/// The object is automatically freed or released when an instance of [`Ow= ned`] is +/// dropped. +/// +/// # Invariants +/// +/// The pointer stored in `ptr` is non-null and valid for the lifetime of = the [`Owned`] instance. +pub struct Owned { + ptr: NonNull, + _p: PhantomData, +} + +// SAFETY: It is safe to send `Owned` to another thread when the underl= ying `T` is `Send` because +// it effectively means sending a unique `&mut T` pointer (which is safe b= ecause `T` is `Send`). +unsafe impl Send for Owned {} + +// SAFETY: It is safe to send `&Owned` to another thread when the under= lying `T` is `Sync` +// because it effectively means sharing `&T` (which is safe because `T` is= `Sync`). +unsafe impl Sync for Owned {} + +impl Owned { + /// Creates a new instance of [`Owned`]. + /// + /// It takes over ownership of the underlying object. + /// + /// # Safety + /// + /// Callers must ensure that the underlying object is acquired and can= be considered owned by + /// Rust. + pub(crate) unsafe fn from_raw(ptr: NonNull) -> Self { + // INVARIANT: The safety requirements guarantee that the new insta= nce now owns the + // reference. + Self { + ptr, + _p: PhantomData, + } + } + + /// Consumes the `Owned`, returning a raw pointer. + /// + /// This function does not actually relinquish ownership of the object. + /// After calling this function, the caller is responsible for ownersh= ip previously managed + /// by the `Owned`. + #[allow(dead_code)] + pub(crate) fn into_raw(me: Self) -> NonNull { + ManuallyDrop::new(me).ptr + } +} + +impl Deref for Owned { + type Target =3D T; + + fn deref(&self) -> &Self::Target { + // SAFETY: The type invariants guarantee that the object is valid. + unsafe { self.ptr.as_ref() } + } +} + +impl DerefMut for Owned { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: The type invariants guarantee that the object is valid, + // and that we can safely return a mutable reference to it. + unsafe { self.ptr.as_mut() } + } +} + +impl Drop for Owned { + fn drop(&mut self) { + // SAFETY: The type invariants guarantee that the `Owned` owns the= object we're about to + // release. + unsafe { T::release(self.ptr) }; + } +} + /// A sum type that always holds either a value of type `L` or `R`. /// /// # Examples --=20 2.48.1 From nobody Sun Feb 8 02:56:17 2026 Received: from mail-10631.protonmail.ch (mail-10631.protonmail.ch [79.135.106.31]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2CDC520CCCD; Fri, 7 Mar 2025 10:04:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.31 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741341872; cv=none; b=VUJvX2fnOAsvFXQhOjYqWgti2OWqPqCgZsuC9UCuopurWh0YTq/4uZE9aEyqWnzbu2taWA5xhYB2rUdCHK9yy2x3GcteujExQ1nb4Aaj4Wyx+4UZMd67XZcz9Yt0qXfut/sH4JmUXpN03rQZmSTo6GMN66/3rCvNmz3Jd6sx63Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741341872; c=relaxed/simple; bh=egRFo9NMAA9KzbtxdSxLFxMjKPYWVfG5kJB14HxMM+o=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=aUmEOJnsKvxqKXBCS0jgE/ObC5P5rDiuXhlJxrtgzT9xIfMfeJHGLyr0MVS1kL9agtY50EDKYdbCDqqpLcyALkoJUvYYD2SHUBHgHBbJOPNvjGrmExdj1JHQ7dnPTWVOWulQqvdPbYVvs5GtuTe2boDmr4kApl81BvJUhkxLeao= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=DRnKGxWz; arc=none smtp.client-ip=79.135.106.31 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="DRnKGxWz" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1741341862; x=1741601062; bh=tHRq3IPn0p6dHilslzS4AMRjsMeM5Fcpnj4lA9LQfdc=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=DRnKGxWzrMepMTjOrUleGXgezlfqzRZCFPPhtjnVaImi3GZP7QeQKStImPnHcDr4o GF9bqm9tx5nJvR/c+ScRlum4+iyjB5vnE3MhGqZ7Y4XTd9hf5PToAhM3+JDcg00oFX TN/fOKft2L2KfJZXbkUGbN2IiCZ7jzMPQcDyhnOKUgMhK295Eh0eqWP51qcBHcFA40 pCjBeycwRMBzAPh5MONtJ5I3RlS6F4RAMNIRTNQXBfILHbjWMSHgsSfDC4EDpR/dxq x8Tpt1MZ0tNFCsPhJWoDzazrXWihqC4tKOczPp7G9LZOhAPKop2+nQLuuhkbHr/Q2K tuMg1vtwyW26Q== Date: Fri, 07 Mar 2025 10:04:16 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v5 2/4] rust: make Owned::into_raw() and Owned::from_raw() public Message-ID: <20250307-unique-ref-v5-2-bffeb633277e@pm.me> In-Reply-To: <20250307-unique-ref-v5-0-bffeb633277e@pm.me> References: <20250307-unique-ref-v5-0-bffeb633277e@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 4da456a556aebaee80d18f19a13684450dff6f0a Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" It might be necessary to be used from some drivers Signed-off-by: Oliver Mangold --- rust/kernel/types.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 0cae5ba6607f0a86d2f0e3494f956f6daad78067..e0ce3646a4d3b70c069322a9b0f= 25c00265a2af8 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -616,7 +616,7 @@ impl Owned { /// /// Callers must ensure that the underlying object is acquired and can= be considered owned by /// Rust. - pub(crate) unsafe fn from_raw(ptr: NonNull) -> Self { + pub unsafe fn from_raw(ptr: NonNull) -> Self { // INVARIANT: The safety requirements guarantee that the new insta= nce now owns the // reference. Self { @@ -630,8 +630,7 @@ pub(crate) unsafe fn from_raw(ptr: NonNull) -> Self { /// This function does not actually relinquish ownership of the object. /// After calling this function, the caller is responsible for ownersh= ip previously managed /// by the `Owned`. - #[allow(dead_code)] - pub(crate) fn into_raw(me: Self) -> NonNull { + pub fn into_raw(me: Self) -> NonNull { ManuallyDrop::new(me).ptr } } --=20 2.48.1 From nobody Sun Feb 8 02:56:17 2026 Received: from mail-10628.protonmail.ch (mail-10628.protonmail.ch [79.135.106.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3201B20D513 for ; Fri, 7 Mar 2025 10:04:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.28 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741341881; cv=none; b=XWbD3ixEW44jdqvGLHQ27URX/mM5KDIn2cX0D8ic43JeLQLRpXar0zffwnODSuKuIeiwhJvDRKnYWzyBygLeX4rSP0LXdZ76JbT1sc9ha7DDyibmXO3zNscqegghn/eYls2oV4wjNM8nHYnnt9kAHOThLBLAju/Gn58wNfy4HmI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741341881; c=relaxed/simple; bh=/9o/X1cJm34Juz19eFTwL2Ugzvou1XZ8SfCT41kGLYY=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=W2wzL7m1uSRNg/Vp3805vYrWZFjiOMa83DKrizv4xIXPaJ8DA5KzV/VfpyqAjko1+mmm516QWo/mPCnYwW81AFiYu53m6B0PvG0QQlTGA6tyA2gazfqmTGt0Nc345Vmxmun+MXRQRq6paDqDNCI1ZMqseC+YPApBIeRySv5JYYA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=TblQefML; arc=none smtp.client-ip=79.135.106.28 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="TblQefML" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1741341869; x=1741601069; bh=TaqflF0ER0lMKKW/mpqz+EK620J9MuGeJhj0ZuW2g1Y=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=TblQefMLT5boa+luHi58Xflmx14QVW7iJfMx1Z9SZ5PktksQRBV+F7QD7ldJtpHqi VSfEn9fm9LFm+CGDWISHrx87Cqxe9/5dS336ncshCUW+iuuzlsbzvvcK1dem5G6OPm 2AopyMfmVGzPXCby3q4mXycSkUFseDy1nFl1XTyXmU1uqwGoHbOAq4tGKI5q0e4mDP 81d71D0ZLD9kvuEtflakOcA4I0O3awmIwe+/fER9OGtSy5KjpJBlaa7vO8/YxDZiUI SwGoNd0UEbpN0BjzxD6gyPlOywQcUVEsfRA942WPgHWN8ECFye2PanMU9XRKpng0Ab 8JGoaHuLfb/7g== Date: Fri, 07 Mar 2025 10:04:24 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v5 3/4] rust: rename AlwaysRefCounted to RefCounted Message-ID: <20250307-unique-ref-v5-3-bffeb633277e@pm.me> In-Reply-To: <20250307-unique-ref-v5-0-bffeb633277e@pm.me> References: <20250307-unique-ref-v5-0-bffeb633277e@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 53ec0d902427928455697c605512ea073defc022 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" AlwaysRefCounted will become a mark trait to indicate that it is allowed to obtain an ARef from a `&`, which cannot be allowed for types which are also Ownable Signed-off-by: Oliver Mangold --- rust/kernel/block/mq/request.rs | 11 +++++++--- rust/kernel/cred.rs | 8 ++++++-- rust/kernel/device.rs | 8 ++++++-- rust/kernel/fs/file.rs | 10 ++++++--- rust/kernel/pid_namespace.rs | 8 ++++++-- rust/kernel/task.rs | 6 +++++- rust/kernel/types.rs | 45 ++++++++++++++++++++++++-------------= ---- 7 files changed, 65 insertions(+), 31 deletions(-) diff --git a/rust/kernel/block/mq/request.rs b/rust/kernel/block/mq/request= .rs index 2f2bb5a04709cc90ae8971da166fc83bb53fb86b..6605a9ce8a13abfc9ed67dd76a9= 480224e805e84 100644 --- a/rust/kernel/block/mq/request.rs +++ b/rust/kernel/block/mq/request.rs @@ -9,7 +9,7 @@ block::mq::Operations, error::Result, sync::Refcount, - types::{ARef, AlwaysRefCounted, Opaque}, + types::{ARef, AlwaysRefCounted, Opaque, RefCounted}, }; use core::{ marker::PhantomData, @@ -209,10 +209,10 @@ unsafe impl Send for Request {} unsafe impl Sync for Request {} =20 // SAFETY: All instances of `Request` are reference counted. This -// implementation of `AlwaysRefCounted` ensure that increments to the ref = count +// implementation of `RefCounted` ensure that increments to the ref count // keeps the object alive in memory at least until a matching reference co= unt // decrement is executed. -unsafe impl AlwaysRefCounted for Request { +unsafe impl RefCounted for Request { fn inc_ref(&self) { self.wrapper_ref().refcount().inc(); } @@ -234,3 +234,8 @@ unsafe fn dec_ref(obj: core::ptr::NonNull) { } } } + +// SAFETY: we current do not implement Ownable, thus it is okay +// to can obtain an `ARef` from an `&Request` +// (but this will change in the future). +unsafe impl AlwaysRefCounted for Request {} diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs index 81d67789b16f243e7832ff3b2e5e479a1ab2bf9e..051f7210390358478f6cc6e8f9e= 3dc1405e5164f 100644 --- a/rust/kernel/cred.rs +++ b/rust/kernel/cred.rs @@ -11,7 +11,7 @@ use crate::{ bindings, task::Kuid, - types::{AlwaysRefCounted, Opaque}, + types::{AlwaysRefCounted, Opaque, RefCounted}, }; =20 /// Wraps the kernel's `struct cred`. @@ -71,7 +71,7 @@ pub fn euid(&self) -> Kuid { } =20 // SAFETY: The type invariants guarantee that `Credential` is always ref-c= ounted. -unsafe impl AlwaysRefCounted for Credential { +unsafe impl RefCounted for Credential { fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. unsafe { bindings::get_cred(self.0.get()) }; @@ -83,3 +83,7 @@ unsafe fn dec_ref(obj: core::ptr::NonNull) { unsafe { bindings::put_cred(obj.cast().as_ptr()) }; } } + +// SAFETY: we do not implement Ownable, thus it is okay +// to can obtain an `ARef` from an `&Credential`. +unsafe impl AlwaysRefCounted for Credential {} diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index db2d9658ba47d9c492bc813ce3eb2ff29703ca31..01c7e5d752b256c37a862f0a12e= 75ddc72051432 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -7,7 +7,7 @@ use crate::{ bindings, str::CStr, - types::{ARef, Opaque}, + types::{ARef, AlwaysRefCounted, Opaque, RefCounted}, }; use core::{fmt, ptr}; =20 @@ -190,7 +190,7 @@ pub fn property_present(&self, name: &CStr) -> bool { } =20 // SAFETY: Instances of `Device` are always reference-counted. -unsafe impl crate::types::AlwaysRefCounted for Device { +unsafe impl RefCounted for Device { fn inc_ref(&self) { // SAFETY: The existence of a shared reference guarantees that the= refcount is non-zero. unsafe { bindings::get_device(self.as_raw()) }; @@ -202,6 +202,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: we do not implement Ownable, thus it is okay +// to can obtain an `Device` from an `&Device`. +unsafe impl AlwaysRefCounted for Device {} + // SAFETY: As by the type invariant `Device` can be sent to any thread. unsafe impl Send for Device {} =20 diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs index e03dbe14d62a566349c4100f2f78b17d4c79aab5..8d31fcc6545b1ea0d41e1d9408d= ad7bdd9d5895b 100644 --- a/rust/kernel/fs/file.rs +++ b/rust/kernel/fs/file.rs @@ -11,7 +11,7 @@ bindings, cred::Credential, error::{code::*, Error, Result}, - types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque}, + types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque, RefCounted}, }; use core::ptr; =20 @@ -190,7 +190,7 @@ unsafe impl Sync for File {} =20 // SAFETY: The type invariants guarantee that `File` is always ref-counted= . This implementation // makes `ARef` own a normal refcount. -unsafe impl AlwaysRefCounted for File { +unsafe impl RefCounted for File { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. @@ -205,6 +205,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: we do not implement Ownable, thus it is okay +// to can obtain an `ARef` from an `&File`. +unsafe impl AlwaysRefCounted for File {} + /// Wraps the kernel's `struct file`. Not thread safe. /// /// This type represents a file that is not known to be safe to transfer a= cross thread boundaries. @@ -225,7 +229,7 @@ pub struct LocalFile { =20 // SAFETY: The type invariants guarantee that `LocalFile` is always ref-co= unted. This implementation // makes `ARef` own a normal refcount. -unsafe impl AlwaysRefCounted for LocalFile { +unsafe impl RefCounted for LocalFile { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. diff --git a/rust/kernel/pid_namespace.rs b/rust/kernel/pid_namespace.rs index 0e93808e4639b37dd77add5d79f64058dac7cb87..91120817ee8cf86ade1c52976fc= f8efa2d790d2a 100644 --- a/rust/kernel/pid_namespace.rs +++ b/rust/kernel/pid_namespace.rs @@ -9,7 +9,7 @@ =20 use crate::{ bindings, - types::{AlwaysRefCounted, Opaque}, + types::{AlwaysRefCounted, RefCounted, Opaque}, }; use core::ptr; =20 @@ -44,7 +44,7 @@ pub unsafe fn from_ptr<'a>(ptr: *const bindings::pid_name= space) -> &'a Self { } =20 // SAFETY: Instances of `PidNamespace` are always reference-counted. -unsafe impl AlwaysRefCounted for PidNamespace { +unsafe impl RefCounted for PidNamespace { #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. @@ -58,6 +58,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: we do not implement Ownable, thus it is okay +// to can obtain an `ARef` from an `&PidNamespace`. +unsafe impl AlwaysRefCounted for PidNamespace {} + // SAFETY: // - `PidNamespace::dec_ref` can be called from any thread. // - It is okay to send ownership of `PidNamespace` across thread boundari= es. diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 07bc22a7645c0c7d792a0a163dd55b8ff0fe5f92..248bf1c56ccb88d38b042e1a062= 116407bfcb145 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -327,7 +327,7 @@ pub fn wake_up(&self) { } =20 // SAFETY: The type invariants guarantee that `Task` is always refcounted. -unsafe impl crate::types::AlwaysRefCounted for Task { +unsafe impl crate::types::RefCounted for Task { fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refc= ount is nonzero. unsafe { bindings::get_task_struct(self.as_ptr()) }; @@ -339,6 +339,10 @@ unsafe fn dec_ref(obj: ptr::NonNull) { } } =20 +// SAFETY: we do not implement Ownable, thus it is okay +// to can obtain an `ARef` from an `&Task`. +unsafe impl crate::types::AlwaysRefCounted for Task {} + impl Kuid { /// Get the current euid. #[inline] diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index e0ce3646a4d3b70c069322a9b0f25c00265a2af8..e6f3308f931d90718d405443c30= 34a216388e0af 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -402,11 +402,9 @@ pub const fn raw_get(this: *const Self) -> *mut T { } } =20 -/// Types that are _always_ reference counted. +/// Types that are internally reference counted. /// /// It allows such types to define their own custom ref increment and decr= ement functions. -/// Additionally, it allows users to convert from a shared reference `&T` = to an owned reference -/// [`ARef`]. /// /// This is usually implemented by wrappers to existing structures on the = C side of the code. For /// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to c= reate reference-counted @@ -418,9 +416,9 @@ pub const fn raw_get(this: *const Self) -> *mut T { /// at least until matching decrements are performed. /// /// Implementers must also ensure that all instances are reference-counted= . (Otherwise they -/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_r= ef`] keep the object +/// won't be able to honour the requirement that [`RefCounted::inc_ref`] k= eep the object /// alive.) -pub unsafe trait AlwaysRefCounted { +pub unsafe trait RefCounted { /// Increments the reference count on the object. fn inc_ref(&self); =20 @@ -433,11 +431,22 @@ pub unsafe trait AlwaysRefCounted { /// Callers must ensure that there was a previous matching increment t= o the reference count, /// and that the object is no longer used after its reference count is= decremented (as it may /// result in the object being freed), unless the caller owns another = increment on the refcount - /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls - /// [`AlwaysRefCounted::dec_ref`] once). + /// (e.g., it calls [`RefCounted::inc_ref`] twice, then calls + /// [`RefCounted::dec_ref`] once). unsafe fn dec_ref(obj: NonNull); } =20 +/// An extension to RefCounted, which declares that it is allowed to conve= rt +/// from a shared reference `&T` to an owned reference [`ARef`]. +/// +/// # Safety +/// +/// Implementers must ensure that no safety invariants are violated by upg= rading an `&T` +/// to an [`ARef`]. In particular that implies [`AlwaysRefCounted`] and= [`Ownable`] +/// cannot be implemented for the same type, as this would allow to violat= e the uniqueness +/// guarantee of [`Owned`] by derefencing it into an `&T` and obtaining= an [`ARef`] from that. +pub unsafe trait AlwaysRefCounted: RefCounted {} + /// An owned reference to an always-reference-counted object. /// /// The object's reference count is automatically decremented when an inst= ance of [`ARef`] is @@ -448,7 +457,7 @@ pub unsafe trait AlwaysRefCounted { /// /// The pointer stored in `ptr` is non-null and valid for the lifetime of = the [`ARef`] instance. In /// particular, the [`ARef`] instance owns an increment on the underlying = object's reference count. -pub struct ARef { +pub struct ARef { ptr: NonNull, _p: PhantomData, } @@ -457,16 +466,16 @@ pub struct ARef { // it effectively means sharing `&T` (which is safe because `T` is `Sync`)= ; additionally, it needs // `T` to be `Send` because any thread that has an `ARef` may ultimatel= y access `T` using a // mutable reference, for example, when the reference count reaches zero a= nd `T` is dropped. -unsafe impl Send for ARef {} +unsafe impl Send for ARef {} =20 // SAFETY: It is safe to send `&ARef` to another thread when the underl= ying `T` is `Sync` // because it effectively means sharing `&T` (which is safe because `T` is= `Sync`); additionally, // it needs `T` to be `Send` because any thread that has a `&ARef` may = clone it and get an // `ARef` on that thread, so the thread may ultimately access `T` using= a mutable reference, for // example, when the reference count reaches zero and `T` is dropped. -unsafe impl Sync for ARef {} +unsafe impl Sync for ARef {} =20 -impl ARef { +impl ARef { /// Creates a new instance of [`ARef`]. /// /// It takes over an increment of the reference count on the underlyin= g object. @@ -495,12 +504,12 @@ pub unsafe fn from_raw(ptr: NonNull) -> Self { /// /// ``` /// use core::ptr::NonNull; - /// use kernel::types::{ARef, AlwaysRefCounted}; + /// use kernel::types::{ARef, RefCounted}; /// /// struct Empty {} /// /// # // SAFETY: TODO. - /// unsafe impl AlwaysRefCounted for Empty { + /// unsafe impl RefCounted for Empty { /// fn inc_ref(&self) {} /// unsafe fn dec_ref(_obj: NonNull) {} /// } @@ -518,7 +527,7 @@ pub fn into_raw(me: Self) -> NonNull { } } =20 -impl Clone for ARef { +impl Clone for ARef { fn clone(&self) -> Self { self.inc_ref(); // SAFETY: We just incremented the refcount above. @@ -526,7 +535,7 @@ fn clone(&self) -> Self { } } =20 -impl Deref for ARef { +impl Deref for ARef { type Target =3D T; =20 fn deref(&self) -> &Self::Target { @@ -543,10 +552,10 @@ fn from(b: &T) -> Self { } } =20 -impl Drop for ARef { +impl Drop for ARef { fn drop(&mut self) { - // SAFETY: The type invariants guarantee that the `ARef` owns the = reference we're about to - // decrement. + // SAFETY: The type invariants guarantee that the `ARef` owns the = reference + // we're about to decrement. unsafe { T::dec_ref(self.ptr) }; } } --=20 2.48.1 From nobody Sun Feb 8 02:56:17 2026 Received: from mail-40133.protonmail.ch (mail-40133.protonmail.ch [185.70.40.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5A2D320E02A; Fri, 7 Mar 2025 10:04:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.70.40.133 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741341885; cv=none; b=eKsvFSORBxxCYDOTI570P1R46hrY8920M9K2p+0kLImkzhotpX6CMHnFf1MI61K3kK5ixFzhJkeulQFzQQHSqt2JREf/L8O+512nm8fZ44uPW0nDR+9BqLgYvbatWwkcr5gJaNe4m/LhaxXD7LO+Qqbf5s6LmX9IiAN048rNAmg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741341885; c=relaxed/simple; bh=kRTzWQygEG5Ns1HqePZuYB9UCZNysEaq22FudaRwL6E=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=uIAr6sPpkYs4tjupfeMA8NbHYwO22HGnz+RJNJYffffStlCvBYt09wXFcAMiKNGhDmEPW8j8eg4Se0bDktZdT6YhDCziuvgs+z5q9Pctlhr3VHK8+lP9Uf/npEErNxJkTDb9BXz/chMWkpGX+IFobTnpN/GPXzeQnSqENqdAmm0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=IQz4K2r2; arc=none smtp.client-ip=185.70.40.133 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="IQz4K2r2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1741341879; x=1741601079; bh=0soWOnUPmUJEv0zAHpPwiKg0s8n+VOyuLKHVFYcokyE=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=IQz4K2r28VKvG9K7I/UzGpHlywImDu7CPJstCYDBNvKvOcYDLcyFDiyTab35Fkw9A wCdiZYgnsvazRfjAS9DtbkMs/X4Z7+O2KHXnZppxSfVg2SebducnZ/S+H/PDBMz7F3 VpaMunKa7lzPSx99VbaFZyOLT/r4BMsXH34A+oJmqaokFIgywhyQ+bz9JEYWDBkymq gFN7b2zsbtNq/7iOON6K2jWebKZcmzvjs/IvD5sOtLqC/LJrfAUDTqoKBOOR7PdddK FMsl4gZzK5M168OKAi/lGrEfBRebhxO4icNYrIiCcWUSUVy7xx/u3D/mvijp11t0tu 9vtdNJrspX3jQ== Date: Fri, 07 Mar 2025 10:04:33 +0000 To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?Q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Asahi Lina From: Oliver Mangold Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Oliver Mangold Subject: [PATCH v5 4/4] rust: adding OwnableRefCounted and SimpleOwnableRefCounted Message-ID: <20250307-unique-ref-v5-4-bffeb633277e@pm.me> In-Reply-To: <20250307-unique-ref-v5-0-bffeb633277e@pm.me> References: <20250307-unique-ref-v5-0-bffeb633277e@pm.me> Feedback-ID: 31808448:user:proton X-Pm-Message-ID: 4909219767ac13eea0b39a877baa4bf244193cca Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Types implementing one of these traits can safely convert between an ARef and an Owned. Signed-off-by: Oliver Mangold --- rust/kernel/types.rs | 268 +++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 268 insertions(+) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index e6f3308f931d90718d405443c3034a216388e0af..0acf95d322b6a213728916f0c7f= 4095aa3f0e0f0 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -552,6 +552,12 @@ fn from(b: &T) -> Self { } } =20 +impl From> for ARef { + fn from(b: Owned) -> Self { + T::into_shared(b) + } +} + impl Drop for ARef { fn drop(&mut self) { // SAFETY: The type invariants guarantee that the `ARef` owns the = reference @@ -669,6 +675,268 @@ fn drop(&mut self) { } } =20 +/// A trait for objects that can be wrapped in either one of the reference= types +/// [`Owned`] and [`ARef`]. +/// +/// # Safety +/// +/// - The same safety requirements as for [`Ownable`] and [`RefCounted`] a= pply. +/// - the uniqueness invariant of [`Owned`] is upheld until dropped. +/// - [`try_from_shared()`](OwnableRefCounted::into_shared) only returns an +/// [`Owned`] if exactly one [`ARef`] exists. +/// - [`into_shared()`](OwnableRefCounted::into_shared) set the reference = count +/// to the value which the returned [`ARef`] expects for an object with = a single reference +/// in existence. This implies that if [`into_shared()`](OwnableRefCount= ed::into_shared) +/// is left on the default implementation, which just rewraps the underl= ying object, +/// the reference count needs not to be modified when converting a [`Own= ed`] to an [`ARef`]. +/// +/// # Examples +/// +/// A minimal example implementation of [`OwnableRefCounted`], +/// [`Ownable`] and its usage with [`ARef`] and [`Owned`] looks like this: +/// +/// ``` +/// # #![expect(clippy::disallowed_names)] +/// use core::cell::Cell; +/// use core::ptr::NonNull; +/// use kernel::alloc::{flags, kbox::KBox, AllocError}; +/// use kernel::types::{ +/// ARef, RefCounted, Owned, Ownable, OwnableRefCounted, +/// }; +/// +/// struct Foo { +/// refcount: Cell, +/// } +/// +/// impl Foo { +/// fn new() -> Result, AllocError> { +/// // Use a KBox to handle the actual allocation +/// let result =3D KBox::new( +/// Foo { +/// refcount: Cell::new(1), +/// }, +/// flags::GFP_KERNEL, +/// )?; +/// // SAFETY: we just allocated the `Foo`, thus it is valid +/// Ok(unsafe { Owned::from_raw(NonNull::new(KBox::into_raw(result= )).unwrap()) }) +/// } +/// } +/// +/// // SAFETY: we increment and decrement correctly and only free the `Foo` +/// // when the refcount reaches zero +/// unsafe impl RefCounted for Foo { +/// fn inc_ref(&self) { +/// self.refcount.replace(self.refcount.get() + 1); +/// } +/// unsafe fn dec_ref(this: NonNull) { +/// // SAFETY: the underlying object is always valid when the func= tion is called +/// let refcount =3D unsafe { &this.as_ref().refcount }; +/// let new_refcount =3D refcount.get() - 1; +/// if new_refcount =3D=3D 0 { +/// // Foo will be dropped when KBox goes out of scope +/// // SAFETY: the `Box` is still alive as the old refcou= nt is 1 +/// unsafe { KBox::from_raw(this.as_ptr()) }; +/// } else { +/// refcount.replace(new_refcount); +/// } +/// } +/// } +/// +/// // SAFETY: we only convert into an `Owned` when the refcount is 1 +/// unsafe impl OwnableRefCounted for Foo { +/// fn try_from_shared(this: ARef) -> Result, ARef> { +/// if this.refcount.get() =3D=3D 1 { +/// // SAFETY: the `Foo` is still alive as the refcount is 1 +/// Ok(unsafe { Owned::from_raw(ARef::into_raw(this)) }) +/// } else { +/// Err(this) +/// } +/// } +/// } +/// +/// // SAFETY: we are not `AlwaysRefCounted` +/// unsafe impl Ownable for Foo { +/// unsafe fn release(this: NonNull) { +/// // SAFETY: using `dec_ref()` from `RefCounted` to release is o= kay, +/// // as the refcount is always 1 for an `Owned` +/// unsafe{ Foo::dec_ref(this) }; +/// } +/// } +/// +/// let foo =3D Foo::new().unwrap(); +/// let mut foo =3D ARef::from(foo); +/// { +/// let bar =3D foo.clone(); +/// assert!(Owned::try_from(bar).is_err()); +/// } +/// assert!(Owned::try_from(foo).is_ok()); +/// ``` +pub unsafe trait OwnableRefCounted: RefCounted + Ownable + Sized { + /// Checks if the [`ARef`] is unique and convert it + /// to an [`Owned`] it that is that case. + /// Otherwise it returns again an [`ARef`] to the same + /// underlying object. + fn try_from_shared(this: ARef) -> Result, ARef= >; + /// Converts the [`Owned`] into an [`ARef`]. + fn into_shared(this: Owned) -> ARef { + // SAFETY: safe by the conditions on implementing the trait + unsafe { ARef::from_raw(Owned::into_raw(this)) } + } +} + +/// This trait allows to implement all of [`Ownable`], [`RefCounted`] and +/// [`OwnableRefCounted`] together in a simplified way, +/// only requiring to provide the methods [`inc_ref()`](SimpleOwnableRefCo= unted::inc_ref), +/// [`dec_ref()`](SimpleOwnableRefCounted::dec_ref), +/// and [`is_unique()`](SimpleOwnableRefCounted::is_unique). +/// +/// For non-standard cases where conversion between [`Ownable`] and [`RefC= ounted`] needs +/// or [`Ownable::release()`] and [`RefCounted::dec_ref()`] cannot be the = same method, +/// [`Ownable`], [`RefCounted`] and [`OwnableRefCounted`] should be implem= ented manually. +/// +/// # Safety +/// +/// - The same safety requirements as for [`Ownable`] and [`RefCounted`] a= pply. +/// - [`is_unique`](SimpleOwnableRefCounted::is_unique) must only return `= true` +/// in case only one [`ARef`] exists and it is impossible for one to be = obtained +/// other than by cloning an existing [`ARef`] or converting an [`Owned`= ] to an [`ARef`]. +/// - It is safe to convert an unique [`ARef`] into an [`Owned`] +/// simply by re-wrapping the underlying object without modifying the re= fcount. +/// +/// # Examples +/// +/// A minimal example implementation of [`SimpleOwnableRefCounted`] +/// and its usage with [`ARef`] and [`Owned`] looks like this: +/// +/// ``` +/// # #![expect(clippy::disallowed_names)] +/// use core::cell::Cell; +/// use core::ptr::NonNull; +/// use kernel::alloc::{flags, kbox::KBox, AllocError}; +/// use kernel::types::{ +/// ARef, SimpleOwnableRefCounted, Owned, +/// }; +/// +/// struct Foo { +/// refcount: Cell, +/// } +/// +/// impl Foo { +/// fn new() -> Result, AllocError> { +/// // Use a KBox to handle the actual allocation +/// let result =3D KBox::new( +/// Foo { +/// refcount: Cell::new(1), +/// }, +/// flags::GFP_KERNEL, +/// )?; +/// // SAFETY: we just allocated the `Foo`, thus it is valid +/// Ok(unsafe { Owned::from_raw(NonNull::new(KBox::into_raw(result= )).unwrap()) }) +/// } +/// } +/// +/// // SAFETY: we implement the trait correctly by ensuring +/// // - the `Foo` is only dropped then the refcount is zero +/// // - `is_unique()` only returns `true` when the refcount is 1 +/// unsafe impl SimpleOwnableRefCounted for Foo { +/// fn inc_ref(&self) { +/// self.refcount.replace(self.refcount.get() + 1); +/// } +/// unsafe fn dec_ref(this: NonNull) { +/// // SAFETY: the underlying object is always valid when the func= tion is called +/// let refcount =3D unsafe { &this.as_ref().refcount }; +/// let new_refcount =3D refcount.get() - 1; +/// if new_refcount =3D=3D 0 { +/// // Foo will be dropped when KBox goes out of scope +/// // SAFETY: the `Box` is still alive as the old refcou= nt is 1 +/// unsafe { KBox::from_raw(this.as_ptr()) }; +/// } else { +/// refcount.replace(new_refcount); +/// } +/// } +/// fn is_unique(&self) -> bool { +/// self.refcount.get() =3D=3D 1 +/// } +/// } +/// +/// let foo =3D Foo::new().unwrap(); +/// let mut foo =3D ARef::from(foo); +/// { +/// let bar =3D foo.clone(); +/// assert!(Owned::try_from(bar).is_err()); +/// } +/// assert!(Owned::try_from(foo).is_ok()); +/// ``` +pub unsafe trait SimpleOwnableRefCounted { + /// Checks if exactly one [`ARef`] to the object exists. + /// In case the object is [`Sync`] the check needs to be race-free. + fn is_unique(&self) -> bool; + /// Increments the reference count on the object. + fn inc_ref(&self); + + /// Decrements the reference count on the object + /// when the [`SimpleOwnableRefCounted`] is dropped. + /// + /// Frees the object when the count reaches zero. + /// + /// # Safety + /// + /// The safety constraints for [`RefCounted::dec_ref`] and + /// [`Ownable::release`] both apply to this method, as it will be used + /// to implement both of these traits. + unsafe fn dec_ref(obj: NonNull); +} + +// TODO: enable this when compiler supports it (>=3D1.85) +// #[diagnostic::do_not_recommend] +// SAFETY: safe by the requirements on implementation of [`SimpleOwnableRe= fCounted`] +unsafe impl OwnableRefCounted for T { + fn try_from_shared(this: ARef) -> Result, ARef= > { + if T::is_unique(&*this) { + // SAFETY: safe by the requirements on implementation of [`Sim= pleOwnable`] + Ok(unsafe { Owned::from_raw(ARef::into_raw(this)) }) + } else { + Err(this) + } + } +} + +// TODO: enable this when compiler supports it (>=3D1.85) +// #[diagnostic::do_not_recommend] +// SAFETY: safe by the requirements on implementation of [`SimpleOwnableRe= fCounted`] +unsafe impl Ownable for T { + unsafe fn release(this: NonNull) { + // SAFETY: safe by the requirements on implementation + // of [`SimpleOwnableRefCounted::dec_ref()`] + unsafe { SimpleOwnableRefCounted::dec_ref(this) }; + } +} + +// TODO: enable this when compiler supports it (>=3D1.85) +// #[diagnostic::do_not_recommend] +// SAFETY: safe by the requirements on implementation of [`SimpleOwnableRe= fCounted`] +unsafe impl RefCounted for T { + fn inc_ref(&self) { + SimpleOwnableRefCounted::inc_ref(self); + } + unsafe fn dec_ref(this: NonNull) { + // SAFETY: safe by the requirements on implementation + // of [`SimpleOwnableRefCounted::dec_ref()`] + unsafe { SimpleOwnableRefCounted::dec_ref(this) }; + } +} + +impl TryFrom> for Owned { + type Error =3D ARef; + /// Tries to convert the [`ARef`] to an [`Owned`] + /// by calling [`try_from_shared()`](OwnableRefCounted::try_from_share= d). + /// In case the [`ARef`] is not unique it returns again an [`ARef`] to= the same + /// underlying object. + fn try_from(b: ARef) -> Result, Self::Error> { + T::try_from_shared(b) + } +} + /// A sum type that always holds either a value of type `L` or `R`. /// /// # Examples --=20 2.48.1