Skip to content

Commit 9d74562

Browse files
committed
Auto merge of #75505 - Dylan-DPC:feature/arc_new, r=KodrAus
Add Arc::new_cyclic Rework of #72443 References #75861 cc @Diggsey @RalfJung r? @KodrAus
2 parents d795eb4 + c26a8d5 commit 9d74562

File tree

3 files changed

+147
-4
lines changed

3 files changed

+147
-4
lines changed

library/alloc/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@
135135
#![feature(alloc_layout_extra)]
136136
#![feature(try_trait)]
137137
#![feature(associated_type_bounds)]
138-
139138
// Allow testing this library
140139

141140
#[cfg(test)]

library/alloc/src/sync.rs

+80-3
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,79 @@ impl<T> Arc<T> {
319319
Self::from_inner(Box::leak(x).into())
320320
}
321321

322+
/// Constructs a new `Arc<T>` using a weak reference to itself. Attempting
323+
/// to upgrade the weak reference before this function returns will result
324+
/// in a `None` value. However, the weak reference may be cloned freely and
325+
/// stored for use at a later time.
326+
///
327+
/// # Examples
328+
/// ```
329+
/// #![feature(arc_new_cyclic)]
330+
/// #![allow(dead_code)]
331+
///
332+
/// use std::sync::{Arc, Weak};
333+
///
334+
/// struct Foo {
335+
/// me: Weak<Foo>,
336+
/// }
337+
///
338+
/// let foo = Arc::new_cyclic(|me| Foo {
339+
/// me: me.clone(),
340+
/// });
341+
/// ```
342+
#[inline]
343+
#[unstable(feature = "arc_new_cyclic", issue = "75861")]
344+
pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Arc<T> {
345+
// Construct the inner in the "uninitialized" state with a single
346+
// weak reference.
347+
let uninit_ptr: NonNull<_> = Box::leak(box ArcInner {
348+
strong: atomic::AtomicUsize::new(0),
349+
weak: atomic::AtomicUsize::new(1),
350+
data: mem::MaybeUninit::<T>::uninit(),
351+
})
352+
.into();
353+
let init_ptr: NonNull<ArcInner<T>> = uninit_ptr.cast();
354+
355+
let weak = Weak { ptr: init_ptr };
356+
357+
// It's important we don't give up ownership of the weak pointer, or
358+
// else the memory might be freed by the time `data_fn` returns. If
359+
// we really wanted to pass ownership, we could create an additional
360+
// weak pointer for ourselves, but this would result in additional
361+
// updates to the weak reference count which might not be necessary
362+
// otherwise.
363+
let data = data_fn(&weak);
364+
365+
// Now we can properly initialize the inner value and turn our weak
366+
// reference into a strong reference.
367+
unsafe {
368+
let inner = init_ptr.as_ptr();
369+
ptr::write(&raw mut (*inner).data, data);
370+
371+
// The above write to the data field must be visible to any threads which
372+
// observe a non-zero strong count. Therefore we need at least "Release" ordering
373+
// in order to synchronize with the `compare_exchange_weak` in `Weak::upgrade`.
374+
//
375+
// "Acquire" ordering is not required. When considering the possible behaviours
376+
// of `data_fn` we only need to look at what it could do with a reference to a
377+
// non-upgradeable `Weak`:
378+
// - It can *clone* the `Weak`, increasing the weak reference count.
379+
// - It can drop those clones, decreasing the weak reference count (but never to zero).
380+
//
381+
// These side effects do not impact us in any way, and no other side effects are
382+
// possible with safe code alone.
383+
let prev_value = (*inner).strong.fetch_add(1, Release);
384+
debug_assert_eq!(prev_value, 0, "No prior strong references should exist");
385+
}
386+
387+
let strong = Arc::from_inner(init_ptr);
388+
389+
// Strong references should collectively own a shared weak reference,
390+
// so don't run the destructor for our old weak reference.
391+
mem::forget(weak);
392+
strong
393+
}
394+
322395
/// Constructs a new `Arc` with uninitialized contents.
323396
///
324397
/// # Examples
@@ -1604,7 +1677,8 @@ impl<T: ?Sized> Weak<T> {
16041677
#[stable(feature = "arc_weak", since = "1.4.0")]
16051678
pub fn upgrade(&self) -> Option<Arc<T>> {
16061679
// We use a CAS loop to increment the strong count instead of a
1607-
// fetch_add because once the count hits 0 it must never be above 0.
1680+
// fetch_add as this function should never take the reference count
1681+
// from zero to one.
16081682
let inner = self.inner()?;
16091683

16101684
// Relaxed load because any write of 0 that we can observe
@@ -1623,8 +1697,11 @@ impl<T: ?Sized> Weak<T> {
16231697
abort();
16241698
}
16251699

1626-
// Relaxed is valid for the same reason it is on Arc's Clone impl
1627-
match inner.strong.compare_exchange_weak(n, n + 1, Relaxed, Relaxed) {
1700+
// Relaxed is fine for the failure case because we don't have any expectations about the new state.
1701+
// Acquire is necessary for the success case to synchronise with `Arc::new_cyclic`, when the inner
1702+
// value can be initialized after `Weak` references have already been created. In that case, we
1703+
// expect to observe the fully initialized value.
1704+
match inner.strong.compare_exchange_weak(n, n + 1, Acquire, Relaxed) {
16281705
Ok(_) => return Some(Arc::from_inner(self.ptr)), // null checked above
16291706
Err(old) => n = old,
16301707
}

library/alloc/src/sync/tests.rs

+67
Original file line numberDiff line numberDiff line change
@@ -492,3 +492,70 @@ fn test_array_from_slice() {
492492
let a: Result<Arc<[u32; 2]>, _> = r.clone().try_into();
493493
assert!(a.is_err());
494494
}
495+
496+
#[test]
497+
fn test_arc_cyclic_with_zero_refs() {
498+
struct ZeroRefs {
499+
inner: Weak<ZeroRefs>,
500+
}
501+
let zero_refs = Arc::new_cyclic(|inner| {
502+
assert_eq!(inner.strong_count(), 0);
503+
assert!(inner.upgrade().is_none());
504+
ZeroRefs { inner: Weak::new() }
505+
});
506+
507+
assert_eq!(Arc::strong_count(&zero_refs), 1);
508+
assert_eq!(Arc::weak_count(&zero_refs), 0);
509+
assert_eq!(zero_refs.inner.strong_count(), 0);
510+
assert_eq!(zero_refs.inner.weak_count(), 0);
511+
}
512+
513+
#[test]
514+
fn test_arc_new_cyclic_one_ref() {
515+
struct OneRef {
516+
inner: Weak<OneRef>,
517+
}
518+
let one_ref = Arc::new_cyclic(|inner| {
519+
assert_eq!(inner.strong_count(), 0);
520+
assert!(inner.upgrade().is_none());
521+
OneRef { inner: inner.clone() }
522+
});
523+
524+
assert_eq!(Arc::strong_count(&one_ref), 1);
525+
assert_eq!(Arc::weak_count(&one_ref), 1);
526+
527+
let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap();
528+
assert!(Arc::ptr_eq(&one_ref, &one_ref2));
529+
530+
assert_eq!(Arc::strong_count(&one_ref), 2);
531+
assert_eq!(Arc::weak_count(&one_ref), 1);
532+
}
533+
534+
#[test]
535+
fn test_arc_cyclic_two_refs() {
536+
struct TwoRefs {
537+
inner1: Weak<TwoRefs>,
538+
inner2: Weak<TwoRefs>,
539+
}
540+
let two_refs = Arc::new_cyclic(|inner| {
541+
assert_eq!(inner.strong_count(), 0);
542+
assert!(inner.upgrade().is_none());
543+
544+
let inner1 = inner.clone();
545+
let inner2 = inner1.clone();
546+
547+
TwoRefs { inner1, inner2 }
548+
});
549+
550+
assert_eq!(Arc::strong_count(&two_refs), 1);
551+
assert_eq!(Arc::weak_count(&two_refs), 2);
552+
553+
let two_refs1 = Weak::upgrade(&two_refs.inner1).unwrap();
554+
assert!(Arc::ptr_eq(&two_refs, &two_refs1));
555+
556+
let two_refs2 = Weak::upgrade(&two_refs.inner2).unwrap();
557+
assert!(Arc::ptr_eq(&two_refs, &two_refs2));
558+
559+
assert_eq!(Arc::strong_count(&two_refs), 3);
560+
assert_eq!(Arc::weak_count(&two_refs), 2);
561+
}

0 commit comments

Comments
 (0)