Skip to content
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

comm::peek hangs #2841

Closed
jesse99 opened this issue Jul 8, 2012 · 9 comments
Closed

comm::peek hangs #2841

jesse99 opened this issue Jul 8, 2012 · 9 comments
Labels
A-concurrency Area: Concurrency
Milestone

Comments

@jesse99
Copy link
Contributor

jesse99 commented Jul 8, 2012

Was able to get comm::peek to hang with 8+ tasks. This was on Mac 10.7.4 using a rust pulled on July 8, 2012.

Here is a test case:

// rustc --test multiple_tasks.rs && ./multiple_tasks
use std;

enum control_event
{
    dup_event(str, comm::chan<str>),
    close_event,
}

fn silly(n: uint) -> comm::chan<control_event>
{
    do task::spawn_listener
    |control_port: comm::port<control_event>|
    {
        io::println(#fmt["started task %?", n]);
        loop
        {
            libc::funcs::posix88::unistd::sleep(1);

            if comm::peek(control_port)
            {
                alt comm::recv(control_port)
                {
                    dup_event(data, data_ch)
                    {
                        io::println(#fmt["task %? received %?", n, data]);
                        comm::send(data_ch, data + data);
                    }
                    close_event
                    {
                        io::println(#fmt["exiting task %?", n]);
                        break;
                    }
                }
            }
        }
    }
}

#[test]
fn blah()
{
    let po = comm::port();
    let ch = comm::chan(po);

    // With under 8 this test passes.
    // With 8 and above the test hangs (last thing printed is "started task 7").
    // If prints are added to the loop in silly you can see that the tasks are running.
    let silly_channels = do vec::from_fn(8) |n| {silly(n)};

    for vec::each(silly_channels)
    |sc|
    {
        comm::send(sc, dup_event("hey", ch));
        assert comm::recv(po) == "heyhey";
    }

    for vec::each(silly_channels)
    |sc|
    {
        comm::send(sc, close_event);
    }
}
@jesse99
Copy link
Contributor Author

jesse99 commented Jul 8, 2012

This seems to be even more serious than I thought: I rewrote my code to use select2 instead of peek and now the select2 is hanging...

@jesse99
Copy link
Contributor Author

jesse99 commented Jul 9, 2012

Was able to work around this using task::spawn_sched:

// rustc --test multiple_tasks.rs && ./multiple_tasks
use std;

enum control_event
{
    dup_event(str, comm::chan<str>),
    close_event,
}

// This works with single_threaded and with manual_threads(4|16).
// Also tried thread_per_core and thread_per_task but they are not
// implemented.
fn silly2(n: uint) -> comm::chan<control_event>
{
    let channel_port = comm::port();
    let channel_channel = comm::chan(channel_port);

    do task::spawn_sched(task::manual_threads(4))
    {
        let control_port: comm::port<control_event> = comm::port();    // this is bookkeeping that spawn_listener handles for us
        let control_channel = comm::chan(control_port);
        comm::send(channel_channel, control_channel);

        io::println(#fmt["started task %?", n]);
        loop
        {
            libc::funcs::posix88::unistd::sleep(1);

            if comm::peek(control_port)
            {
                alt comm::recv(control_port)
                {
                    dup_event(data, data_ch)
                    {
                        io::println(#fmt["task %? received %?", n, data]);
                        comm::send(data_ch, data + data);
                    }
                    close_event
                    {
                        io::println(#fmt["exiting task %?", n]);
                        break;
                    }
                }
            }
        }
    };

    comm::recv(channel_port)
}

#[test]
fn blah()
{
    let po = comm::port();
    let ch = comm::chan(po);

    let silly_channels = do vec::from_fn(10) |n| {silly2(n)};

    for vec::each(silly_channels)
    |sc|
    {
        comm::send(sc, dup_event("hey", ch));
        assert comm::recv(po) == "heyhey";
    }

    for vec::each(silly_channels)
    |sc|
    {
        comm::send(sc, close_event);
    }
}

@eholk
Copy link
Contributor

eholk commented Jul 9, 2012

I suspect the call to libc::funcs::posix88::unistd::sleep(1) might be part of the problem. sleep is outside of the realm of things the Rust scheduler is aware of, and so sleeping blocks a whole thread instead of allowing other tasks to run on that thread while the sleeping task is sleeping. I'd recommend using std::timer::sleep, which the Rust scheduler is aware of. That said, unistd::sleep should wake up eventually, so I'm surprised this is hanging rather than just taking a potentially very long time to finish.

Also, recv blocks until data is available on a port, so sleeping in the loop isn't really necessary. It may be that you want to periodically perform some other processing though. If this is the case, I'd suggest using std::timer::recv_timeout.

@ghost ghost assigned eholk Jul 12, 2012
@jesse99
Copy link
Contributor Author

jesse99 commented Jul 13, 2012

I don't think this behavior can be pinned on unistd::sleep (exclusively). Yesterday I saw the same symptom (task not starting up) and worked around it the same way (task::spawn_sched instead of task::spawn). There was a lot of code involved and a lot of tasks running around, but my code at least didn't call sleep.

(The code above was from some sample code of mine which used sleep in a rather unrealistic manner to keep the sample simple. My real code is where I saw this new task hang).

@jesse99
Copy link
Contributor Author

jesse99 commented Jul 14, 2012

Found another place where tasks launched with spawn just hang: the test_server_client unit test in https://github.com/jdm/rust-socket on "Linux shell 3.2.0-24-generic #39-Ubuntu SMP Mon May 21 16:52:17 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux". Worked around again with spawn_sched.

Note that those unit tests did work on my Mac which is where I do 99% of my rust work.

@tedhorst
Copy link
Contributor

Adding task::yield to comm::peek fixes the original case. I'm not sure about the select2 case. See pull request #2947.

@tedhorst
Copy link
Contributor

The select2 case works for me. As a side note, I think there should be library sleep function that calls task::yield.

@eholk
Copy link
Contributor

eholk commented Jul 18, 2012

Nice work, @tedhorst. We don't currently insert yield checks on loop backedges like we should (#524), which means to loop around sleep and peek never yields. Adding a call to task::yield in comm::peek seems like kind of a hack, but I think it's reasonable for now given that we don't do yield checks like we should.

@eholk
Copy link
Contributor

eholk commented Jul 25, 2012

This was fixed by #2947.

@eholk eholk closed this as completed Jul 25, 2012
@jesse99 jesse99 mentioned this issue Sep 9, 2012
RalfJung pushed a commit to RalfJung/rust that referenced this issue Apr 28, 2023
compiletest: complain about unknown flags

This would have avoided rust-lang#110102
celinval added a commit to celinval/rust-dev that referenced this issue Jun 4, 2024
We have two different ways today of building release bundles, one in
`kani.yml` and another one in `release.yml`, and only the `kani.yml`
actually run tests. This is error prone, since the release workflow only
runs during a release without validation tests, and the build can
diverge from what's being tested in CI.

Instead, we will always run the same workflow, except for the steps that
create the release.

Resolves rust-lang#2703

Co-authored-by: Zyad Hassan <88045115+zhassan-aws@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-concurrency Area: Concurrency
Projects
None yet
Development

No branches or pull requests

3 participants