Skip to content

Commit 3206421

Browse files
nbdd0121Andreas Hindborg
authored andcommitted
LIST: [PATCH v3 2/4] 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 <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent bb2cf53 commit 3206421

File tree

1 file changed

+26
-39
lines changed

1 file changed

+26
-39
lines changed

rust/kernel/sync/arc.rs

Lines changed: 26 additions & 39 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,10 +18,10 @@
1818
1919
use crate::{
2020
alloc::{AllocError, Flags, KBox},
21-
bindings,
2221
init::{self, InPlaceInit, Init, PinInit},
22+
sync::Refcount,
2323
try_init,
24-
types::{ForeignOwnable, Opaque},
24+
types::ForeignOwnable,
2525
};
2626
use core::{
2727
alloc::Layout,
@@ -144,7 +144,7 @@ pub struct Arc<T: ?Sized> {
144144
#[pin_data]
145145
#[repr(C)]
146146
struct ArcInner<T: ?Sized> {
147-
refcount: Opaque<bindings::refcount_t>,
147+
refcount: Refcount,
148148
data: T,
149149
}
150150

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

@@ -300,7 +299,7 @@ impl<T: ?Sized> Arc<T> {
300299
/// use kernel::sync::{Arc, UniqueArc};
301300
///
302301
/// let arc = Arc::new(42, GFP_KERNEL)?;
303-
/// let unique_arc = arc.into_unique_or_drop();
302+
/// let unique_arc = Arc::into_unique_or_drop(arc);
304303
///
305304
/// // The above conversion should succeed since refcount of `arc` is 1.
306305
/// assert!(unique_arc.is_some());
@@ -316,35 +315,30 @@ impl<T: ?Sized> Arc<T> {
316315
/// let arc = Arc::new(42, GFP_KERNEL)?;
317316
/// let another = arc.clone();
318317
///
319-
/// let unique_arc = arc.into_unique_or_drop();
318+
/// let unique_arc = Arc::into_unique_or_drop(arc);
320319
///
321320
/// // The above conversion should fail since refcount of `arc` is >1.
322321
/// assert!(unique_arc.is_none());
323322
///
324323
/// # Ok::<(), Error>(())
325324
/// ```
326-
pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> {
325+
pub fn into_unique_or_drop(this: Self) -> Option<Pin<UniqueArc<T>>> {
327326
// We will manually manage the refcount in this method, so we disable the destructor.
328-
let me = ManuallyDrop::new(self);
327+
let this = ManuallyDrop::new(this);
329328
// SAFETY: We own a refcount, so the pointer is still valid.
330-
let refcount = unsafe { me.ptr.as_ref() }.refcount.get();
329+
let refcount = unsafe { &this.ptr.as_ref().refcount };
331330

332331
// If the refcount reaches a non-zero value, then we have destroyed this `Arc` and will
333332
// return without further touching the `Arc`. If the refcount reaches zero, then there are
334333
// no other arcs, and we can create a `UniqueArc`.
335-
//
336-
// SAFETY: We own a refcount, so the pointer is not dangling.
337-
let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) };
338-
if is_zero {
339-
// SAFETY: We have exclusive access to the arc, so we can perform unsynchronized
340-
// accesses to the refcount.
341-
unsafe { core::ptr::write(refcount, bindings::REFCOUNT_INIT(1)) };
334+
if refcount.dec_and_test() {
335+
refcount.set(1);
342336

343-
// INVARIANT: We own the only refcount to this arc, so we may create a `UniqueArc`. We
344-
// must pin the `UniqueArc` because the values was previously in an `Arc`, and they pin
345-
// their values.
337+
// INVARIANT: If the refcount failed to decrement because it is 1, then we have the
338+
// exclusive ownership, so we may create a `UniqueArc`. We must pin the `UniqueArc`
339+
// because the values was previously in an `Arc`, and they pin their values.
346340
Some(Pin::from(UniqueArc {
347-
inner: ManuallyDrop::into_inner(me),
341+
inner: ManuallyDrop::into_inner(this),
348342
}))
349343
} else {
350344
None
@@ -419,14 +413,10 @@ impl<T: ?Sized> AsRef<T> for Arc<T> {
419413

420414
impl<T: ?Sized> Clone for Arc<T> {
421415
fn clone(&self) -> Self {
422-
// SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
423-
// safe to dereference it.
424-
let refcount = unsafe { self.ptr.as_ref() }.refcount.get();
425-
426-
// INVARIANT: C `refcount_inc` saturates the refcount, so it cannot overflow to zero.
416+
// INVARIANT: `Refcount` saturates the refcount, so it cannot overflow to zero.
427417
// SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
428418
// safe to increment the refcount.
429-
unsafe { bindings::refcount_inc(refcount) };
419+
unsafe { self.ptr.as_ref().refcount.inc() };
430420

431421
// SAFETY: We just incremented the refcount. This increment is now owned by the new `Arc`.
432422
unsafe { Self::from_inner(self.ptr) }
@@ -435,16 +425,14 @@ impl<T: ?Sized> Clone for Arc<T> {
435425

436426
impl<T: ?Sized> Drop for Arc<T> {
437427
fn drop(&mut self) {
438-
// SAFETY: By the type invariant, there is necessarily a reference to the object. We cannot
439-
// touch `refcount` after it's decremented to a non-zero value because another thread/CPU
440-
// may concurrently decrement it to zero and free it. It is ok to have a raw pointer to
441-
// freed/invalid memory as long as it is never dereferenced.
442-
let refcount = unsafe { self.ptr.as_ref() }.refcount.get();
443-
444428
// INVARIANT: If the refcount reaches zero, there are no other instances of `Arc`, and
445429
// this instance is being dropped, so the broken invariant is not observable.
446-
// SAFETY: Also by the type invariant, we are allowed to decrement the refcount.
447-
let is_zero = unsafe { bindings::refcount_dec_and_test(refcount) };
430+
// SAFETY: By the type invariant, there is necessarily a reference to the object.
431+
// NOTE: we cannot touch `refcount` after it's decremented to a non-zero value because
432+
// another thread/CPU may concurrently decrement it to zero and free it. However it is okay
433+
// to have a transient reference to decrement the refcount, see
434+
// https://github.com/rust-lang/rust/issues/55005.
435+
let is_zero = unsafe { self.ptr.as_ref().refcount.dec_and_test() };
448436
if is_zero {
449437
// The count reached zero, we must free the memory.
450438
//
@@ -696,8 +684,7 @@ impl<T> UniqueArc<T> {
696684
// INVARIANT: The refcount is initialised to a non-zero value.
697685
let inner = KBox::try_init::<AllocError>(
698686
try_init!(ArcInner {
699-
// SAFETY: There are no safety requirements for this FFI call.
700-
refcount: Opaque::new(unsafe { bindings::REFCOUNT_INIT(1) }),
687+
refcount: Refcount::new(1),
701688
data <- init::uninit::<T, AllocError>(),
702689
}? AllocError),
703690
flags,

0 commit comments

Comments
 (0)