1

The following code generates a "user event" to be returned by poll:

extern crate mio;

use mio::event::Evented;
use mio::{Events, Poll, PollOpt, Ready, Registration, Token};
use std::thread::{sleep, spawn, JoinHandle};
use std::time::{Duration, Instant};

#[derive(Debug)]
struct Output(u32, Duration);

pub struct MioThread {
    registration: Registration,
    handle: JoinHandle<Output>,
}

impl MioThread {
    pub fn new(i: u32) -> MioThread {
        let now = Instant::now();

        let (registration, set_readiness) = Registration::new2();

        let handle = spawn(move || {
            sleep(Duration::from_millis((1000 - (100 * i)) as u64));

            set_readiness.set_readiness(Ready::readable()).unwrap();

            Output(i, now.elapsed())
        });

        MioThread {
            registration: registration,
            handle: handle,
        }
    }

    // manage the thread result
    fn eval_result(self) {
        let out = self.handle.join();
        println!("do whathever you want with: {:?}", out.unwrap());
    }
}

fn main() {
    let poll = Poll::new().unwrap();

    let mut events = Events::with_capacity(16);

    let mut tasks = Vec::new();
    for i in 0..5 {
        let mio_thread = MioThread::new(i);

        mio_thread
            .registration
            .register(&poll, Token(i as usize), Ready::readable(), PollOpt::edge())
            .unwrap();

        tasks.push(Some(mio_thread));
    }

    loop {
        let num_events = poll.poll(&mut events, None).unwrap();
        println!("poll fired: {} events", num_events);
        for event in &events {
            if event.readiness().is_readable() {
                let Token(thread_id) = event.token();

                if let Some(t) = tasks.remove(thread_id) {
                    t.eval_result();
                }

            }
        }
    }
}

The output is:

poll fired: 1 events
do whathever you want with: Output(4, Duration { secs: 0, nanos: 600967623 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(3, Duration { secs: 0, nanos: 701035026 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(2, Duration { secs: 0, nanos: 801089370 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(1, Duration { secs: 0, nanos: 900890190 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(0, Duration { secs: 1, nanos: 600076 })
poll fired: 0 events

I've opened an issue on the Mio repository.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
attdona
  • 17,196
  • 7
  • 49
  • 60
  • I don't see any extra events. The first call to `poll` blocks as expected, as do all the subsequent alternate calls. But the calls in between are returning immediately (with no events). I don't know why it would behave like this, but I also don't see why it would be a problem... – Peter Hall May 03 '18 at 11:33
  • It actually doesn't happen if you don't remove the done tasks from the `tasks` Vec. At a guess, I'd say that [`Registration::drop`](https://docs.rs/mio/0.6.10/src/mio/poll.rs.html#1508-1518) is updating the state of the `Poll`, causing `poll` to return because of the state change, even though there are no new events. – Peter Hall May 03 '18 at 11:50
  • You are right, in general it is not a problem. But there are specific cases where you want optimize as much as possible the event loop thread or, as in my case, to understand how Mio works, probably I'm missing something. – attdona May 03 '18 at 12:13

1 Answers1

0

As stated in the comments and confirmed here:

dropping a Registration might wake up the loop (which it indeed does, the same as a registration) without actually triggering an event

This is obviously not an issue in most cases, just a behavior that I did not expect after reading the docs:

fn poll(&self, events: &mut Events, timeout: Option) -> Result[−] Wait for readiness events

Blocks the current thread and waits for readiness events for any of the Evented handles that have been registered with this Poll instance. The function will block until either at least one readiness event has been received or timeout has elapsed. A timeout of None means that poll will block until a readiness event has been received.

The current thread is indeed awaken also when dropping a Registration.

attdona
  • 17,196
  • 7
  • 49
  • 60