Skip to content

Commit

Permalink
Rollup merge of #70733 - yoshuawuyts:arc-increment-refcount, r=Mark-S…
Browse files Browse the repository at this point in the history
…imulacrum

Add Arc::{incr,decr}_strong_count

This adds two `unsafe` methods to `Arc`: `incr_strong_count` and `decr_strong_count`. A suggestion to add methods to change the strong count in `Arc` came up in during review in #68700 (comment), and from asking a few people this seemed like generally useful to have.

References:
- [Motivation from #68700](#68700 (comment))
- [Real world example in an executor](https://docs.rs/extreme/666.666.666666/src/extreme/lib.rs.html#13)
  • Loading branch information
Dylan-DPC committed May 7, 2020
2 parents a08c473 + b04599f commit 5e9b372
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 5 deletions.
73 changes: 73 additions & 0 deletions src/liballoc/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,79 @@ impl<T: ?Sized> Arc<T> {
this.inner().strong.load(SeqCst)
}

/// Increments the strong reference count on the `Arc<T>` associated with the
/// provided pointer by one.
///
/// # Safety
///
/// The pointer must have been obtained through `Arc::into_raw`, and the
/// associated `Arc` instance must be valid (i.e. the strong count must be at
/// least 1) for the duration of this method.
///
/// # Examples
///
/// ```
/// #![feature(arc_mutate_strong_count)]
///
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
///
/// unsafe {
/// let ptr = Arc::into_raw(five);
/// Arc::incr_strong_count(ptr);
///
/// // This assertion is deterministic because we haven't shared
/// // the `Arc` between threads.
/// let five = Arc::from_raw(ptr);
/// assert_eq!(2, Arc::strong_count(&five));
/// }
/// ```
#[inline]
#[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
pub unsafe fn incr_strong_count(ptr: *const T) {
// Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr));
// Now increase refcount, but don't drop new refcount either
let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
}

/// Decrements the strong reference count on the `Arc<T>` associated with the
/// provided pointer by one.
///
/// # Safety
///
/// The pointer must have been obtained through `Arc::into_raw`, and the
/// associated `Arc` instance must be valid (i.e. the strong count must be at
/// least 1) when invoking this method. This method can be used to release the final
/// `Arc` and backing storage, but **should not** be called after the final `Arc` has been
/// released.
///
/// # Examples
///
/// ```
/// #![feature(arc_mutate_strong_count)]
///
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
///
/// unsafe {
/// let ptr = Arc::into_raw(five);
/// Arc::decr_strong_count(ptr);
///
/// // This assertion is deterministic because we haven't shared
/// // the `Arc` between threads.
/// let five = Arc::from_raw(ptr);
/// assert_eq!(0, Arc::strong_count(&five));
/// }
/// ```
#[inline]
#[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
pub unsafe fn decr_strong_count(ptr: *const T) {
mem::drop(Arc::from_raw(ptr));
}

#[inline]
fn inner(&self) -> &ArcInner<T> {
// This unsafety is ok because while this arc is alive we're guaranteed
Expand Down
12 changes: 7 additions & 5 deletions src/liballoc/task.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![unstable(feature = "wake_trait", issue = "69912")]
//! Types and Traits for working with asynchronous tasks.
use core::mem::{self, ManuallyDrop};
use core::mem::ManuallyDrop;
use core::task::{RawWaker, RawWakerVTable, Waker};

use crate::sync::Arc;
Expand Down Expand Up @@ -60,9 +60,11 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
// Increment the reference count of the arc to clone it.
unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
let waker: Arc<W> = Arc::from_raw(waker as *const W);
mem::forget(Arc::clone(&waker));
raw_waker(waker)
Arc::incr_strong_count(waker as *const W);
RawWaker::new(
waker as *const (),
&RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
)
}

// Wake by value, moving the Arc into the Wake::wake function
Expand All @@ -79,7 +81,7 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {

// Decrement the reference count of the Arc on drop
unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
mem::drop(Arc::from_raw(waker as *const W));
Arc::decr_strong_count(waker as *const W);
}

RawWaker::new(
Expand Down

0 comments on commit 5e9b372

Please sign in to comment.