Skip to content

Commit bc24503

Browse files
author
Stjepan Glavina
authored
Fix deadlock when all receivers are dropped (#474)
* Fix deadlock when all receivers are dropped * Add a comment to explain the behavior of try_send * Disable clippy
1 parent 266e632 commit bc24503

File tree

3 files changed

+29
-15
lines changed

3 files changed

+29
-15
lines changed

.github/workflows/ci.yml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ jobs:
7474
- name: Docs
7575
run: cargo doc --features docs
7676

77-
clippy_check:
78-
name: Clippy check
79-
runs-on: ubuntu-latest
80-
steps:
81-
- uses: actions/checkout@v1
82-
- name: Install rust
83-
run: rustup update beta && rustup default beta
84-
- name: Install clippy
85-
run: rustup component add clippy
86-
- name: clippy
87-
run: cargo clippy --all --features unstable
77+
# clippy_check:
78+
# name: Clippy check
79+
# runs-on: ubuntu-latest
80+
# steps:
81+
# - uses: actions/checkout@v1
82+
# - name: Install rust
83+
# run: rustup update beta && rustup default beta
84+
# - name: Install clippy
85+
# run: rustup component add clippy
86+
# - name: clippy
87+
# run: cargo clippy --all --features unstable

src/sync/channel.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,14 @@ impl<T> Channel<T> {
677677
let mut tail = self.tail.load(Ordering::Relaxed);
678678

679679
loop {
680+
// Extract mark bit from the tail and unset it.
681+
//
682+
// If the mark bit was set (which means all receivers have been dropped), we will still
683+
// send the message into the channel if there is enough capacity. The message will get
684+
// dropped when the channel is dropped (which means when all senders are also dropped).
685+
let mark_bit = tail & self.mark_bit;
686+
tail ^= mark_bit;
687+
680688
// Deconstruct the tail.
681689
let index = tail & (self.mark_bit - 1);
682690
let lap = tail & !(self.one_lap - 1);
@@ -699,8 +707,8 @@ impl<T> Channel<T> {
699707

700708
// Try moving the tail.
701709
match self.tail.compare_exchange_weak(
702-
tail,
703-
new_tail,
710+
tail | mark_bit,
711+
new_tail | mark_bit,
704712
Ordering::SeqCst,
705713
Ordering::Relaxed,
706714
) {
@@ -732,7 +740,7 @@ impl<T> Channel<T> {
732740
// ...then the channel is full.
733741

734742
// Check if the channel is disconnected.
735-
if tail & self.mark_bit != 0 {
743+
if mark_bit != 0 {
736744
return Err(TrySendError::Disconnected(msg));
737745
} else {
738746
return Err(TrySendError::Full(msg));

tests/channel.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,13 @@ fn smoke() {
2525

2626
drop(s);
2727
assert_eq!(r.recv().await, None);
28-
})
28+
});
29+
30+
task::block_on(async {
31+
let (s, r) = channel(10);
32+
drop(r);
33+
s.send(1).await;
34+
});
2935
}
3036

3137
#[test]

0 commit comments

Comments
 (0)