Skip to content

Commit 5e9b372

Browse files
authored
Rollup merge of rust-lang#70733 - yoshuawuyts:arc-increment-refcount, r=Mark-Simulacrum
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 rust-lang#68700 (comment), and from asking a few people this seemed like generally useful to have. References: - [Motivation from rust-lang#68700](rust-lang#68700 (comment)) - [Real world example in an executor](https://docs.rs/extreme/666.666.666666/src/extreme/lib.rs.html#13)
2 parents a08c473 + b04599f commit 5e9b372

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
@@ -776,6 +776,79 @@ impl<T: ?Sized> Arc<T> {
776776
this.inner().strong.load(SeqCst)
777777
}
778778

779+
/// Increments the strong reference count on the `Arc<T>` associated with the
780+
/// provided pointer by one.
781+
///
782+
/// # Safety
783+
///
784+
/// The pointer must have been obtained through `Arc::into_raw`, and the
785+
/// associated `Arc` instance must be valid (i.e. the strong count must be at
786+
/// least 1) for the duration of this method.
787+
///
788+
/// # Examples
789+
///
790+
/// ```
791+
/// #![feature(arc_mutate_strong_count)]
792+
///
793+
/// use std::sync::Arc;
794+
///
795+
/// let five = Arc::new(5);
796+
///
797+
/// unsafe {
798+
/// let ptr = Arc::into_raw(five);
799+
/// Arc::incr_strong_count(ptr);
800+
///
801+
/// // This assertion is deterministic because we haven't shared
802+
/// // the `Arc` between threads.
803+
/// let five = Arc::from_raw(ptr);
804+
/// assert_eq!(2, Arc::strong_count(&five));
805+
/// }
806+
/// ```
807+
#[inline]
808+
#[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
809+
pub unsafe fn incr_strong_count(ptr: *const T) {
810+
// Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
811+
let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr));
812+
// Now increase refcount, but don't drop new refcount either
813+
let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
814+
}
815+
816+
/// Decrements the strong reference count on the `Arc<T>` associated with the
817+
/// provided pointer by one.
818+
///
819+
/// # Safety
820+
///
821+
/// The pointer must have been obtained through `Arc::into_raw`, and the
822+
/// associated `Arc` instance must be valid (i.e. the strong count must be at
823+
/// least 1) when invoking this method. This method can be used to release the final
824+
/// `Arc` and backing storage, but **should not** be called after the final `Arc` has been
825+
/// released.
826+
///
827+
/// # Examples
828+
///
829+
/// ```
830+
/// #![feature(arc_mutate_strong_count)]
831+
///
832+
/// use std::sync::Arc;
833+
///
834+
/// let five = Arc::new(5);
835+
///
836+
/// unsafe {
837+
/// let ptr = Arc::into_raw(five);
838+
/// Arc::decr_strong_count(ptr);
839+
///
840+
/// // This assertion is deterministic because we haven't shared
841+
/// // the `Arc` between threads.
842+
/// let five = Arc::from_raw(ptr);
843+
/// assert_eq!(0, Arc::strong_count(&five));
844+
/// }
845+
/// ```
846+
#[inline]
847+
#[unstable(feature = "arc_mutate_strong_count", issue = "71983")]
848+
pub unsafe fn decr_strong_count(ptr: *const T) {
849+
mem::drop(Arc::from_raw(ptr));
850+
}
851+
779852
#[inline]
780853
fn inner(&self) -> &ArcInner<T> {
781854
// 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)