Skip to content

Commit

Permalink
Merge pull request torvalds#721 from wedsonaf/ref-counted
Browse files Browse the repository at this point in the history
rust: add `ARef`, an owned reference to an always-refcounted object
  • Loading branch information
wedsonaf authored Mar 23, 2022
2 parents ffa9654 + ffec70e commit 18bb7ec
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 2 deletions.
4 changes: 3 additions & 1 deletion rust/kernel/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ pub mod user_ptr;
pub use build_error::build_error;

pub use crate::error::{to_result, Error, Result};
pub use crate::types::{bit, bits_iter, Bool, False, Mode, Opaque, ScopeGuard, True};
pub use crate::types::{
bit, bits_iter, ARef, AlwaysRefCounted, Bool, False, Mode, Opaque, ScopeGuard, True,
};

use core::marker::PhantomData;

Expand Down
2 changes: 1 addition & 1 deletion rust/kernel/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ pub use super::static_assert;

pub use super::{error::code::*, Error, KernelModule, Result};

pub use super::{str::CStr, ThisModule};
pub use super::{str::CStr, ARef, ThisModule};
107 changes: 107 additions & 0 deletions rust/kernel/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ use crate::{
use alloc::boxed::Box;
use core::{
cell::UnsafeCell,
marker::PhantomData,
mem::MaybeUninit,
ops::{self, Deref, DerefMut},
pin::Pin,
ptr::NonNull,
};

/// Permissions.
Expand Down Expand Up @@ -567,3 +569,108 @@ pub struct False;

// SAFETY: This is one of the only two implementations of `Bool`.
unsafe impl Bool for False {}

/// Types that are _always_ reference counted.
///
/// It allows such types to define their own custom ref increment and decrement functions.
/// Additionally, it allows users to convert from a shared reference `&T` to an owned reference
/// [`ARef<T>`].
///
/// This is usually implemented by wrappers to existing structures on the C side of the code. For
/// Rust code, the recommendation is to use [`Ref`] to create reference-counted instances of a
/// type.
///
/// # Safety
///
/// Implementers must ensure that increments to the reference count keeps the object alive in
/// memory at least until a matching decrement performed.
///
/// Implementers must also ensure that all instances are reference-counted. (Otherwise they
/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object
/// alive.)
pub unsafe trait AlwaysRefCounted {
/// Increments the reference count on the object.
fn inc_ref(&self);

/// Decrements the reference count on the object.
///
/// Frees the object when the count reaches zero.
///
/// # Safety
///
/// Callers must ensure that there was a previous matching increment to 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).
unsafe fn dec_ref(obj: NonNull<Self>);
}

/// An owned reference to an always-reference-counted object.
///
/// The object's reference count is automatically decremented when an instance of [`ARef`] is
/// dropped. It is also automatically incremented when a new instance is created via
/// [`ARef::clone`].
///
/// # Invariants
///
/// 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 underlying object's reference count.
pub struct ARef<T: AlwaysRefCounted> {
ptr: NonNull<T>,
_p: PhantomData<T>,
}

impl<T: AlwaysRefCounted> ARef<T> {
/// Creates a new instance of [`ARef`].
///
/// It takes over an increment of the reference count on the underlying object.
///
/// # Safety
///
/// Callers must ensure that the reference count was incremented at least once, and that they
/// are properly relinquishing one increment. That is, if there is only one increment, callers
/// must not use the underlying object anymore -- it is only safe to do so via the newly
/// created [`ARef`].
pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
// INVARIANT: The safety requirements guarantee that the new instance now owns the
// increment on the refcount.
Self {
ptr,
_p: PhantomData,
}
}
}

impl<T: AlwaysRefCounted> Clone for ARef<T> {
fn clone(&self) -> Self {
self.inc_ref();
// SAFETY: We just incremented the refcount above.
unsafe { Self::from_raw(self.ptr) }
}
}

impl<T: AlwaysRefCounted> Deref for ARef<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
// SAFETY: The type invariants guarantee that the object is valid.
unsafe { self.ptr.as_ref() }
}
}

impl<T: AlwaysRefCounted> From<&T> for ARef<T> {
fn from(b: &T) -> Self {
b.inc_ref();
// SAFETY: We just incremented the refcount above.
unsafe { Self::from_raw(NonNull::from(b)) }
}
}

impl<T: AlwaysRefCounted> Drop for ARef<T> {
fn drop(&mut self) {
// SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
// decrement.
unsafe { T::dec_ref(self.ptr) };
}
}

0 comments on commit 18bb7ec

Please sign in to comment.