Skip to content

Commit 0d0b283

Browse files
author
Bryan Donlan
committed
Make Weak::weak_count() return zero when no strong refs remain
1 parent 91ee3d1 commit 0d0b283

File tree

4 files changed

+31
-45
lines changed

4 files changed

+31
-45
lines changed

src/liballoc/rc.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,20 +1814,16 @@ impl<T: ?Sized> Weak<T> {
18141814

18151815
/// Gets the number of `Weak` pointers pointing to this allocation.
18161816
///
1817-
/// If `self` was created using [`Weak::new`], this will return `None`. If
1818-
/// not, the returned value is at least 1, since `self` still points to the
1819-
/// allocation.
1820-
///
1821-
/// [`Weak::new`]: #method.new
1817+
/// If no strong pointers remain, this will return zero.
18221818
#[stable(feature = "weak_counts", since = "1.40.0")]
1823-
pub fn weak_count(&self) -> Option<usize> {
1819+
pub fn weak_count(&self) -> usize {
18241820
self.inner().map(|inner| {
18251821
if inner.strong() > 0 {
18261822
inner.weak() - 1 // subtract the implicit weak ptr
18271823
} else {
1828-
inner.weak()
1824+
0
18291825
}
1830-
})
1826+
}).unwrap_or(0)
18311827
}
18321828

18331829
/// Returns `None` when the pointer is dangling and there is no allocated `RcBox`

src/liballoc/rc/tests.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,28 +114,28 @@ fn test_weak_count() {
114114

115115
#[test]
116116
fn weak_counts() {
117-
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
117+
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), 0);
118118
assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
119119

120120
let a = Rc::new(0);
121121
let w = Rc::downgrade(&a);
122122
assert_eq!(Weak::strong_count(&w), 1);
123-
assert_eq!(Weak::weak_count(&w), Some(1));
123+
assert_eq!(Weak::weak_count(&w), 1);
124124
let w2 = w.clone();
125125
assert_eq!(Weak::strong_count(&w), 1);
126-
assert_eq!(Weak::weak_count(&w), Some(2));
126+
assert_eq!(Weak::weak_count(&w), 2);
127127
assert_eq!(Weak::strong_count(&w2), 1);
128-
assert_eq!(Weak::weak_count(&w2), Some(2));
128+
assert_eq!(Weak::weak_count(&w2), 2);
129129
drop(w);
130130
assert_eq!(Weak::strong_count(&w2), 1);
131-
assert_eq!(Weak::weak_count(&w2), Some(1));
131+
assert_eq!(Weak::weak_count(&w2), 1);
132132
let a2 = a.clone();
133133
assert_eq!(Weak::strong_count(&w2), 2);
134-
assert_eq!(Weak::weak_count(&w2), Some(1));
134+
assert_eq!(Weak::weak_count(&w2), 1);
135135
drop(a2);
136136
drop(a);
137137
assert_eq!(Weak::strong_count(&w2), 0);
138-
assert_eq!(Weak::weak_count(&w2), Some(1));
138+
assert_eq!(Weak::weak_count(&w2), 0);
139139
drop(w2);
140140
}
141141

src/liballoc/sync.rs

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use core::sync::atomic;
1212
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
1313
use core::borrow;
1414
use core::fmt;
15-
use core::cmp::{self, Ordering};
15+
use core::cmp::Ordering;
1616
use core::iter;
1717
use core::intrinsics::abort;
1818
use core::mem::{self, align_of, align_of_val, size_of_val};
@@ -1508,9 +1508,8 @@ impl<T: ?Sized> Weak<T> {
15081508
/// Gets an approximation of the number of `Weak` pointers pointing to this
15091509
/// allocation.
15101510
///
1511-
/// If `self` was created using [`Weak::new`], this will return 0. If not,
1512-
/// the returned value is at least 1, since `self` still points to the
1513-
/// allocation.
1511+
/// If `self` was created using [`Weak::new`], or if there are no remaining
1512+
/// strong pointers, this will return 0.
15141513
///
15151514
/// # Accuracy
15161515
///
@@ -1520,30 +1519,21 @@ impl<T: ?Sized> Weak<T> {
15201519
///
15211520
/// [`Weak::new`]: #method.new
15221521
#[stable(feature = "weak_counts", since = "1.40.0")]
1523-
pub fn weak_count(&self) -> Option<usize> {
1524-
// Due to the implicit weak pointer added when any strong pointers are
1525-
// around, we cannot implement `weak_count` correctly since it
1526-
// necessarily requires accessing the strong count and weak count in an
1527-
// unsynchronized fashion. So this version is a bit racy.
1522+
pub fn weak_count(&self) -> usize {
15281523
self.inner().map(|inner| {
1529-
let strong = inner.strong.load(SeqCst);
15301524
let weak = inner.weak.load(SeqCst);
1525+
let strong = inner.strong.load(SeqCst);
15311526
if strong == 0 {
1532-
// If the last `Arc` has *just* been dropped, it might not yet
1533-
// have removed the implicit weak count, so the value we get
1534-
// here might be 1 too high.
1535-
weak
1527+
0
15361528
} else {
1537-
// As long as there's still at least 1 `Arc` around, subtract
1538-
// the implicit weak pointer.
1539-
// Note that the last `Arc` might get dropped between the 2
1540-
// loads we do above, removing the implicit weak pointer. This
1541-
// means that the value might be 1 too low here. In order to not
1542-
// return 0 here (which would happen if we're the only weak
1543-
// pointer), we guard against that specifically.
1544-
cmp::max(1, weak - 1)
1529+
// Since we observed that there was at least one strong pointer
1530+
// after reading the weak count, we know that the implicit weak
1531+
// reference (present whenever any strong references are alive)
1532+
// was still around when we observed the weak count, and can
1533+
// therefore safely subtract it.
1534+
weak - 1
15451535
}
1546-
})
1536+
}).unwrap_or(0)
15471537
}
15481538

15491539
/// Returns `None` when the pointer is dangling and there is no allocated `ArcInner`,

src/liballoc/sync/tests.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,28 +62,28 @@ fn test_arc_get_mut() {
6262

6363
#[test]
6464
fn weak_counts() {
65-
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), None);
65+
assert_eq!(Weak::weak_count(&Weak::<u64>::new()), 0);
6666
assert_eq!(Weak::strong_count(&Weak::<u64>::new()), 0);
6767

6868
let a = Arc::new(0);
6969
let w = Arc::downgrade(&a);
7070
assert_eq!(Weak::strong_count(&w), 1);
71-
assert_eq!(Weak::weak_count(&w), Some(1));
71+
assert_eq!(Weak::weak_count(&w), 1);
7272
let w2 = w.clone();
7373
assert_eq!(Weak::strong_count(&w), 1);
74-
assert_eq!(Weak::weak_count(&w), Some(2));
74+
assert_eq!(Weak::weak_count(&w), 2);
7575
assert_eq!(Weak::strong_count(&w2), 1);
76-
assert_eq!(Weak::weak_count(&w2), Some(2));
76+
assert_eq!(Weak::weak_count(&w2), 2);
7777
drop(w);
7878
assert_eq!(Weak::strong_count(&w2), 1);
79-
assert_eq!(Weak::weak_count(&w2), Some(1));
79+
assert_eq!(Weak::weak_count(&w2), 1);
8080
let a2 = a.clone();
8181
assert_eq!(Weak::strong_count(&w2), 2);
82-
assert_eq!(Weak::weak_count(&w2), Some(1));
82+
assert_eq!(Weak::weak_count(&w2), 1);
8383
drop(a2);
8484
drop(a);
8585
assert_eq!(Weak::strong_count(&w2), 0);
86-
assert_eq!(Weak::weak_count(&w2), Some(1));
86+
assert_eq!(Weak::weak_count(&w2), 0);
8787
drop(w2);
8888
}
8989

0 commit comments

Comments
 (0)