Tokio: The broadcast channel receiver sometimes panics while dropping with the message "unexpected empty broadcast channel"

Created on 13 May 2020  路  7Comments  路  Source: tokio-rs/tokio

Version

tokio v0.2.20, tokio-macros v0.2.5

Platform

Linux pa-player 4.19.115-v7 #1 SMP Thu Apr 16 13:53:57 UTC 2020 armv7l GNU/Linux (using the Yocto Project)

Description

This happened in a relatively large codebase, so it's rather hard to try to isolate what exactly contributes to this behaviour, and as such, I sadly do not have a minimal example for when this happens.

Specifically, the panic!("unexpected empty broadcast channel") at src/sync/broadcast.rs:957 (the Drop implementation for Receiver<T>) gets triggered sometimes, which as far as I can tell is not documented anywhere and as such seams to be a bug, and not a misuse of the broadcast channel.

The channel in question was created via tokio::sync::broadcast::channel(1), in case this might be the edge case responsible.

A-tokio C-bug M-sync

All 7 comments

The broadcast channel was changed in the v0.2.21 release. Can you check if you still get the issue.

As far as I can tell the issue doesn't occur anymore. I'll close the ticket and reopen it should it occur again.

Thanks :]

The issue appears to still occur sporadically.

As an extra note: This might have something to do with the excessive spamming into the broadcast channel, which I'll attempt to minimize, so my very uneducated guess would be that it's some kind of race condition.

As far as I can tell stopping the sheer amount of spamming (which was essentially a busy loop of spamming until the response is received) stops the issue from occurring.

It would be very helpful if you could try to make it happen in a small test case.

I finally managed to replicate it (thanks for reminding me to try again with the added knowledge of the spamming maybe being a part of it):

use std::mem::drop;

use tokio::sync::broadcast;

#[tokio::main]
async fn main() {
    loop {
        let (sender, _unused_receiver) = broadcast::channel(3);
        let other_receiver = sender.subscribe();

        tokio::spawn(async move {
            for _ in 0..30 {
                let _ = sender.send(());
            }
        });

        drop(other_receiver);  // also happens when dropping the first receiver
    }
}

The bug appears to occur when:

  • There are more than one receivers
  • At the point of one of the receivers dropping there are still values being sent into the channel
  • The channel has a low capacity

Thank you! Confirmed locally on my machine in both debug and release mode.

Was this page helpful?
0 / 5 - 0 ratings