tailhook / rotor

The mio-based framework for rust for doing I/O in simple and composable way (ABANDONED)
MIT License
361 stars 25 forks source link

UdpSocket is never writable #24

Closed arjantop closed 8 years ago

arjantop commented 8 years ago

I tried to use rotor with this minimal code (maybe I am doing something wrong). But after starting the loop the socket never becomes ready:

use std::str;
use mio::udp::UdpSocket;
use rotor::{EventSet, PollOpt, Loop, Config, Void};
use rotor::{Machine, Response, Scope, EarlyScope};

struct Context;

enum Client {
    Foo
}

impl Client {
    fn new(socket: UdpSocket, scope: &mut EarlyScope) -> Response<Client, Void> {
        scope.register(&socket, EventSet::all(), PollOpt::level()).unwrap();
        Response::ok(Client::Foo)
    }
}

impl Machine for Client {
    type Context = Context;
    type Seed = Void;

    fn create(_: Void, scope: &mut Scope<Context>) -> Response<Self, Void>
    {
        println!("create");
        Response::ok(Client::Foo)
    }

    fn ready(self, events: EventSet, _scope: &mut Scope<Context>) -> Response<Self, Void>
    {
        println!("ready: {:?}", events);
        Response::ok(Client::Foo)
    }

    fn spawned(self, _scope: &mut Scope<Context>) -> Response<Self, Void>
    {
        println!("spawned");
        Response::ok(Client::Foo)
    }

    fn timeout(self, _scope: &mut Scope<Context>) -> Response<Self, Void>
    {
        println!("timeout");
        Response::ok(Client::Foo)
    }

    fn wakeup(self, _scope: &mut Scope<Context>) -> Response<Self, Void>
    {
        println!("wakeup");
        Response::ok(Client::Foo)
    }
}

pub fn get() {
    println!("starting ...");
    let mut loop_creator = Loop::new(&Config::new()).unwrap();
    let any = str::FromStr::from_str("0.0.0.0:0").unwrap();
    let socket = UdpSocket::bound(&any).unwrap();
    loop_creator.add_machine_with(|scope| {
        Client::new(socket, scope)
    }).unwrap();
    loop_creator.run(Context).unwrap();
}

This example with "raw" mio works as expected:

extern crate mio;

use mio::*;
use mio::udp::*;
use std::str;

const LISTENER: Token = Token(0);

pub struct UdpHandler {
    tx: UdpSocket,
}

impl UdpHandler {
    fn new(tx: UdpSocket) -> UdpHandler {
        UdpHandler {
            tx: tx,
        }
    }
}

impl Handler for UdpHandler {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<UdpHandler>, token: Token, events: EventSet) {
        println!("{:?}", events);
    }
}

fn main() {
    let mut event_loop = EventLoop::new().unwrap();
    let any = str::FromStr::from_str("0.0.0.0:0").unwrap();
    let tx = UdpSocket::bound(&any).unwrap();
    event_loop.register(&tx, LISTENER, EventSet::all(), PollOpt::edge()).unwrap();
    event_loop.run(&mut UdpHandler::new(tx)).unwrap();
}
GGist commented 8 years ago

I tested your first example using rotor (on Windows) and I saw that the socket failed to become writable as well. However, you are registering it in level triggered mode in that example whereas the second example using mio you register it in edge triggered mode.

Using edge triggered mode in the rotor example works for me to where I saw the socket become writable.

Also, I am not sure if you are using Windows or not, but last I talked to the mio guys, level trigger support on Windows is somewhat lacking (at least for v0.5). I would use edge triggered registration when possible.

arjantop commented 8 years ago

I tested with both edge and level and none of them work. I tested on OS X 10.11.5, not sure why mio works.

GGist commented 8 years ago

Oh I see. Unfortunately I don't have a copy of OS X to test on.

What you could always do is see if it is a problem with rotor not receiving the writable event from mio, or if it is a problem with rotor not properly percolating the writable event up the stack to the machine.

I believe a print statement before this line might provide some information.

arjantop commented 8 years ago

Ok turns out I did do something wrong: by mistake I passed the ownership of the socket to the function new and this caused the socket to be closed.

@GGist Thanks for the help anyway :)

GGist commented 8 years ago

Ah good catch.

I guess that means the writable event that I saw on my end was just another quirk with Windows.