Skip to content

Commit dd1823c

Browse files
bors[bot]Stjepan Glavina
and
Stjepan Glavina
committed
Merge #382
382: Fix a race in channel disconnection r=stjepang a=stjepang Co-authored-by: Stjepan Glavina <[email protected]>
2 parents 240cf90 + 9178ce1 commit dd1823c

File tree

1 file changed

+12
-3
lines changed

1 file changed

+12
-3
lines changed

crossbeam-channel/src/counter.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
///! Reference counter for channels.
2+
23
use std::isize;
34
use std::ops;
45
use std::process;
5-
use std::sync::atomic::{AtomicUsize, Ordering};
6+
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
67

78
/// Reference counter internals.
89
struct Counter<C> {
@@ -12,6 +13,9 @@ struct Counter<C> {
1213
/// The number of receivers associated with the channel.
1314
receivers: AtomicUsize,
1415

16+
/// Set to `true` if the last sender or the last receiver reference deallocates the channel.
17+
destroy: AtomicBool,
18+
1519
/// The internal channel.
1620
chan: C,
1721
}
@@ -21,6 +25,7 @@ pub fn new<C>(chan: C) -> (Sender<C>, Receiver<C>) {
2125
let counter = Box::into_raw(Box::new(Counter {
2226
senders: AtomicUsize::new(1),
2327
receivers: AtomicUsize::new(1),
28+
destroy: AtomicBool::new(false),
2429
chan,
2530
}));
2631
let s = Sender { counter };
@@ -60,7 +65,9 @@ impl<C> Sender<C> {
6065
/// Function `disconnect` will be called if this is the last sender reference.
6166
pub unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
6267
if self.counter().senders.fetch_sub(1, Ordering::AcqRel) == 1 {
63-
if !disconnect(&self.counter().chan) {
68+
disconnect(&self.counter().chan);
69+
70+
if self.counter().destroy.swap(true, Ordering::AcqRel) {
6471
drop(Box::from_raw(self.counter));
6572
}
6673
}
@@ -113,7 +120,9 @@ impl<C> Receiver<C> {
113120
/// Function `disconnect` will be called if this is the last receiver reference.
114121
pub unsafe fn release<F: FnOnce(&C) -> bool>(&self, disconnect: F) {
115122
if self.counter().receivers.fetch_sub(1, Ordering::AcqRel) == 1 {
116-
if !disconnect(&self.counter().chan) {
123+
disconnect(&self.counter().chan);
124+
125+
if self.counter().destroy.swap(true, Ordering::AcqRel) {
117126
drop(Box::from_raw(self.counter));
118127
}
119128
}

0 commit comments

Comments
 (0)