Skip to content

Commit b04599f

Browse files
committed
Add Arc::{incr,decr}_strong_count
1 parent 607b858 commit b04599f

File tree

2 files changed

+80
-5
lines changed

2 files changed

+80
-5
lines changed

src/liballoc/sync.rs

+73
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,79 @@ impl<T: ?Sized> Arc<T> {
751751
this.inner().strong.load(SeqCst)
752752
}
753753

754+
/// Increments the strong reference count on the `Arc<T>` associated with the
755+
/// provided pointer by one.
756+
///
757+
/// # Safety
758+
///
759+
/// The pointer must have been obtained through `Arc::into_raw`, and the
760+
/// associated `Arc` instance must be valid (i.e. the strong count must be at
761+
/// least 1) for the duration of this method.
762+
///
763+
/// # Examples
764+
///
765+
/// ```
766+
/// #![feature(arc_mutate_strong_count)]
767+
///
768+
/// use std::sync::Arc;
769+
///
770+
/// let five = Arc::new(5);
771+
///
772+
/// unsafe {
773+
/// let ptr = Arc::into_raw(five);
774+
/// Arc::incr_strong_count(ptr);
775+
///
776+
/// // This assertion is deterministic because we haven't shared
777+
/// // the `Arc` between threads.
778+
/// let five = Arc::from_raw(ptr);
779+
/// assert_eq!(2, Arc::strong_count(&five));
780+
/// }
781+
/// ```
782+
#[inline]
783+
#[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
784+
pub unsafe fn incr_strong_count(ptr: *const T) {
785+
// Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
786+
let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr));
787+
// Now increase refcount, but don't drop new refcount either
788+
let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
789+
}
790+
791+
/// Decrements the strong reference count on the `Arc<T>` associated with the
792+
/// provided pointer by one.
793+
///
794+
/// # Safety
795+
///
796+
/// The pointer must have been obtained through `Arc::into_raw`, and the
797+
/// associated `Arc` instance must be valid (i.e. the strong count must be at
798+
/// least 1) when invoking this method. This method can be used to release the final
799+
/// `Arc` and backing storage, but **should not** be called after the final `Arc` has been
800+
/// released.
801+
///
802+
/// # Examples
803+
///
804+
/// ```
805+
/// #![feature(arc_mutate_strong_count)]
806+
///
807+
/// use std::sync::Arc;
808+
///
809+
/// let five = Arc::new(5);
810+
///
811+
/// unsafe {
812+
/// let ptr = Arc::into_raw(five);
813+
/// Arc::decr_strong_count(ptr);
814+
///
815+
/// // This assertion is deterministic because we haven't shared
816+
/// // the `Arc` between threads.
817+
/// let five = Arc::from_raw(ptr);
818+
/// assert_eq!(0, Arc::strong_count(&five));
819+
/// }
820+
/// ```
821+
#[inline]
822+
#[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
823+
pub unsafe fn decr_strong_count(ptr: *const T) {
824+
mem::drop(Arc::from_raw(ptr));
825+
}
826+
754827
#[inline]
755828
fn inner(&self) -> &ArcInner<T> {
756829
// This unsafety is ok because while this arc is alive we're guaranteed

src/liballoc/task.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![unstable(feature = "wake_trait", issue = "69912")]
22
//! Types and Traits for working with asynchronous tasks.
3-
use core::mem::{self, ManuallyDrop};
3+
use core::mem::ManuallyDrop;
44
use core::task::{RawWaker, RawWakerVTable, Waker};
55

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

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

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

8587
RawWaker::new(

0 commit comments

Comments
 (0)