Skip to content

Commit 2098b9a

Browse files
nbdd0121jannau
authored andcommitted
rust: convert Arc to use Refcount
With `Refcount` type created, `Arc` can use `Refcount` instead of calling into FFI directly. Signed-off-by: Gary Guo <gary@garyguo.net> Signed-off-by: Boqun Feng <boqun.feng@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Reviewed-by: Benno Lossin <lossin@kernel.org> Reviewed-by: Elle Rhumsaa <elle@weathered-steel.dev> Link: https://lore.kernel.org/r/20250723233312.3304339-4-gary@kernel.org
1 parent c0092da commit 2098b9a

1 file changed

Lines changed: 14 additions & 31 deletions

File tree

rust/kernel/sync/arc.rs

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//! threads.
99
//!
1010
//! It is different from the standard library's [`Arc`] in a few ways:
11-
//! 1. It is backed by the kernel's `refcount_t` type.
11+
//! 1. It is backed by the kernel's [`Refcount`] type.
1212
//! 2. It does not support weak references, which allows it to be half the size.
1313
//! 3. It saturates the reference count instead of aborting when it goes over a threshold.
1414
//! 4. It does not provide a `get_mut` method, so the ref counted object is pinned.
@@ -18,11 +18,11 @@
1818
1919
use crate::{
2020
alloc::{AllocError, Flags, KBox},
21-
bindings,
2221
ffi::c_void,
2322
init::InPlaceInit,
23+
sync::Refcount,
2424
try_init,
25-
types::{ForeignOwnable, Opaque},
25+
types::ForeignOwnable,
2626
};
2727
use core::{
2828
alloc::Layout,
@@ -145,7 +145,7 @@ pub struct Arc<T: ?Sized> {
145145
#[pin_data]
146146
#[repr(C)]
147147
struct ArcInner<T: ?Sized> {
148-
refcount: Opaque<bindings::refcount_t>,
148+
refcount: Refcount,
149149
data: T,
150150
}
151151

@@ -157,7 +157,7 @@ impl<T: ?Sized> ArcInner<T> {
157157
/// `ptr` must have been returned by a previous call to [`Arc::into_raw`], and the `Arc` must
158158
/// not yet have been destroyed.
159159
unsafe fn container_of(ptr: *const T) -> NonNull<ArcInner<T>> {
160-
let refcount_layout = Layout::new::<bindings::refcount_t>();
160+
let refcount_layout = Layout::new::<Refcount>();
161161
// SAFETY: The caller guarantees that the pointer is valid.
162162
let val_layout = Layout::for_value(unsafe { &*ptr });
163163
// SAFETY: We're computing the layout of a real struct that existed when compiling this
@@ -229,8 +229,7 @@ impl<T> Arc<T> {
229229
pub fn new(contents: T, flags: Flags) -> Result<Self, AllocError> {
230230
// INVARIANT: The refcount is initialised to a non-zero value.
231231
let value = ArcInner {
232-
// SAFETY: There are no safety requirements for this FFI call.
233-
refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
232+
refcount: Refcount::new(1),
234233
data: contents,
235234
};
236235

@@ -348,18 +347,13 @@ impl<T: ?Sized> Arc<T> {
348347
// We will manually manage the refcount in this method, so we disable the destructor.
349348
let this = ManuallyDrop::new(this);
350349
// SAFETY: We own a refcount, so the pointer is still valid.
351-
let refcount = unsafe { this.ptr.as_ref() }.refcount.get();
350+
let refcount = unsafe { &this.ptr.as_ref().refcount };
352351

353352
// If the refcount reaches a non-zero value, then we have destroyed this `Arc` and will
354353
// return without further touching the `Arc`. If the refcount reaches zero, then there are
355354
// no other arcs, and we can create a `UniqueArc`.
356-
//
357-
// SAFETY: We own a refcount, so the pointer is not dangling.
358-
let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) };
359-
if is_zero {
360-
// SAFETY: We have exclusive access to the arc, so we can perform unsynchronized
361-
// accesses to the refcount.
362-
unsafe { core::ptr::write(refcount, bindings::REFCOUNT_INIT(1)) };
355+
if refcount.dec_and_test() {
356+
refcount.set(1);
363357

364358
// INVARIANT: We own the only refcount to this arc, so we may create a `UniqueArc`. We
365359
// must pin the `UniqueArc` because the values was previously in an `Arc`, and they pin
@@ -456,14 +450,10 @@ impl<T: ?Sized> Borrow<T> for Arc<T> {
456450

457451
impl<T: ?Sized> Clone for Arc<T> {
458452
fn clone(&self) -> Self {
459-
// SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
460-
// safe to dereference it.
461-
let refcount = unsafe { self.ptr.as_ref() }.refcount.get();
462-
463-
// INVARIANT: C `refcount_inc` saturates the refcount, so it cannot overflow to zero.
453+
// INVARIANT: `Refcount` saturates the refcount, so it cannot overflow to zero.
464454
// SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
465455
// safe to increment the refcount.
466-
unsafe { bindings::refcount_inc(refcount) };
456+
unsafe { self.ptr.as_ref() }.refcount.inc();
467457

468458
// SAFETY: We just incremented the refcount. This increment is now owned by the new `Arc`.
469459
unsafe { Self::from_inner(self.ptr) }
@@ -472,16 +462,10 @@ impl<T: ?Sized> Clone for Arc<T> {
472462

473463
impl<T: ?Sized> Drop for Arc<T> {
474464
fn drop(&mut self) {
475-
// SAFETY: By the type invariant, there is necessarily a reference to the object. We cannot
476-
// touch `refcount` after it's decremented to a non-zero value because another thread/CPU
477-
// may concurrently decrement it to zero and free it. It is ok to have a raw pointer to
478-
// freed/invalid memory as long as it is never dereferenced.
479-
let refcount = unsafe { self.ptr.as_ref() }.refcount.get();
480-
481465
// INVARIANT: If the refcount reaches zero, there are no other instances of `Arc`, and
482466
// this instance is being dropped, so the broken invariant is not observable.
483-
// SAFETY: Also by the type invariant, we are allowed to decrement the refcount.
484-
let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) };
467+
// SAFETY: By the type invariant, there is necessarily a reference to the object.
468+
let is_zero = unsafe { self.ptr.as_ref() }.refcount.dec_and_test();
485469
if is_zero {
486470
// The count reached zero, we must free the memory.
487471
//
@@ -775,8 +759,7 @@ impl<T> UniqueArc<T> {
775759
// INVARIANT: The refcount is initialised to a non-zero value.
776760
let inner = KBox::try_init::<AllocError>(
777761
try_init!(ArcInner {
778-
// SAFETY: There are no safety requirements for this FFI call.
779-
refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
762+
refcount: Refcount::new(1),
780763
data <- pin_init::uninit::<T, AllocError>(),
781764
}? AllocError),
782765
flags,

0 commit comments

Comments
 (0)