diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 111a7651b5e..a7f14c0bfd4 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -751,6 +751,79 @@ impl Arc { this.inner().strong.load(SeqCst) } + /// Increments the strong reference count on the `Arc` 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::::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` 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 { // This unsafety is ok because while this arc is alive we're guaranteed diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs index a64d5d7a63b..745444a152e 100644 --- a/src/liballoc/task.rs +++ b/src/liballoc/task.rs @@ -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; @@ -60,9 +60,11 @@ impl From> for RawWaker { fn raw_waker(waker: Arc) -> RawWaker { // Increment the reference count of the arc to clone it. unsafe fn clone_waker(waker: *const ()) -> RawWaker { - let waker: Arc = 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::, wake::, wake_by_ref::, drop_waker::), + ) } // Wake by value, moving the Arc into the Wake::wake function @@ -79,7 +81,7 @@ fn raw_waker(waker: Arc) -> RawWaker { // Decrement the reference count of the Arc on drop unsafe fn drop_waker(waker: *const ()) { - mem::drop(Arc::from_raw(waker as *const W)); + Arc::decr_strong_count(waker as *const W); } RawWaker::new(