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

epoll: after try_clone(), a stream can receive notifications even after it is dropped. #361

Closed
dwrensha opened this issue Feb 24, 2016 · 1 comment
Milestone

Comments

@dwrensha
Copy link
Contributor

I'm filing this issue to make more concrete the concern that I raised here, and because #360 proposes to commit to the "drop implies deregister" semantics:

When a value is dropped, it will no longer trigger any further notifications.

Consider this program:

extern crate mio;

use mio::tcp::{TcpListener, TcpStream};

struct Handler {
    listener: TcpListener,
    stream: Option<TcpStream>,
}

impl mio::Handler for Handler {
    type Timeout = ();
    type Message = ();
    fn ready(&mut self, event_loop: &mut mio::EventLoop<Self>, token: mio::Token, _: mio::EventSet) {
        if token == mio::Token(1) {
            println!("got a connection");
            let stream1 = self.listener.accept().unwrap().unwrap().0;
            let stream2 = stream1.try_clone().unwrap();
            event_loop.register(&stream1, mio::Token(2),
                                ::mio::EventSet::readable(),
                                ::mio::PollOpt::edge()
                                ).unwrap();

            drop(stream1); // Should this imply deregister()?                                                               

            self.stream = Some(stream2);
        } else if token == mio::Token(2) {
            println!("token 2: readable");
        }
    }
}

pub fn main() {
    let listener = TcpListener::bind(&"127.0.0.1:2653".parse().unwrap()).unwrap();
    let mut event_loop: mio::EventLoop<Handler> = mio::EventLoop::new().unwrap();

    event_loop.register(&listener, mio::Token(1), ::mio::EventSet::readable(),
                        mio::PollOpt::edge()).unwrap();

    let mut handler = Handler {
        listener: listener,
        stream: None,
    };

    event_loop.run(&mut handler).unwrap();
}

On Linux, if I run the above program in one terminal and do nc 127.0.0.1 2653 in a second terminal, when I enter data into the second terminal, the program outputs "token 2: readable", even though the specific stream that was registered with the EventLoop has been closed. See Q6 in http://man7.org/linux/man-pages/man7/epoll.7.html for an explanation of why this happens.

When I do the same thing on OSX, token 2 does not receive any notifications.

In my opinion, the kqueue semantics make more sense, but I'm not sure how they could be emulated with epoll. Maybe we just say that registering dup()ed streams leads to undefined behavior? That seems sad, because it's sometimes useful to dup() a stream and register one clone of it as readable and the other clone as writable.

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

No branches or pull requests

2 participants