Skip to content

Race condition in task communication causes deadlocks #15761

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
carllerche opened this issue Jul 17, 2014 · 3 comments · Fixed by #15764
Closed

Race condition in task communication causes deadlocks #15761

carllerche opened this issue Jul 17, 2014 · 3 comments · Fixed by #15764

Comments

@carllerche
Copy link
Member

Repro:

extern crate time;

use std::io::IoResult;
use std::io::timer::Timer;
use std::sync::Future;

fn repro() -> IoResult<()> {
    let (tx, rx): (SyncSender<&'static str>, Receiver<&'static str>) = sync_channel(3);

    let mut f = Future::spawn(proc() {
        let mut timer = try!(Timer::new());
        let tick = timer.periodic(10000);

        loop {
            println!("select; {}", time::precise_time_ns());
            select! {
                _ = tick.recv() => {
                    fail!("nope, received tick first; {}", time::precise_time_ns());
                },
                msg = rx.recv() => {
                    println!("Received msg; {}", msg);

                    if msg == "hi2u" {
                        break;
                    }
                }
            }
        }

        Ok(())
    });

    tx.try_send("zomg").unwrap();
    tx.try_send("hi2u").unwrap();

    f.get()
}

pub fn main() {
    let mut i = 0u;
    loop {
        i += 1;
        println!("starting iter {}; {}", i, time::precise_time_ns());
        repro().unwrap();
    }
}
@carllerche
Copy link
Member Author

It seems that the select! is not necessarily related:

extern crate time;

use std::io::IoResult;
use std::io::timer::Timer;
use std::sync::Future;

fn repro() -> IoResult<()> {
    let (tx, rx): (SyncSender<&'static str>, Receiver<&'static str>) = sync_channel(3);

    let mut f = Future::spawn(proc() {
        rx.recv();
        rx.recv();

        Ok(())
    });

    tx.try_send("zomg").unwrap();
    tx.try_send("hi2u").unwrap();

    f.get()
}

pub fn main() {
    let mut i = 0u;
    loop {
        i += 1;
        println!("starting iter {}; {}", i, time::precise_time_ns());
        repro().unwrap();
    }
}

@carllerche
Copy link
Member Author

Removing Future deadlocks as well:

extern crate time;

use std::io::IoResult;
use std::io::timer::Timer;
use std::sync::Future;

fn repro() -> IoResult<()> {
    let (tx1, rx1): (SyncSender<&'static str>, Receiver<&'static str>) = sync_channel(3);
    let (tx2, rx2): (SyncSender<&'static str>, Receiver<&'static str>) = sync_channel(3);

    spawn(proc() {
        rx1.recv();
        tx2.try_send("pong").unwrap();
    });

    tx1.try_send("ping").unwrap();
    rx2.recv();

    Ok(())
}

pub fn main() {
    let mut i = 0u;
    loop {
        i += 1;
        println!("starting iter {}; {}", i, time::precise_time_ns());
        repro().unwrap();
    }
}

@carllerche
Copy link
Member Author

It seems that SyncSender#try_send is the culprit.

alexcrichton added a commit to alexcrichton/rust that referenced this issue Jul 18, 2014
This branch of try_send() just forgot to wake up any receiver waiting for data.

Closes rust-lang#15761
bors added a commit that referenced this issue Jul 20, 2014
This branch of try_send() just forgot to wake up any receiver waiting for data.

Closes #15761
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant