From f6241b63304319559cb992055b0a9b6791794c80 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 Nov 2016 14:27:49 -0800 Subject: [PATCH] Touch up Reactor::poll --- src/reactor/mod.rs | 113 ++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 68 deletions(-) diff --git a/src/reactor/mod.rs b/src/reactor/mod.rs index a797b7b71..470bd5854 100644 --- a/src/reactor/mod.rs +++ b/src/reactor/mod.rs @@ -212,22 +212,19 @@ impl Core { { let mut task = task::spawn(f); let ready = self.future_readiness.clone(); + let mut future_fired = true; - // Next, move all that data into a dynamically dispatched closure to cut - // down on monomorphization costs. Inside this closure we unset the - // readiness of the future (as we're about to poll it) and then we check - // to see if it's done. If it's not then the event loop will turn again. - let mut res = None; - self._run(&mut || { - assert!(res.is_none()); - match task.poll_future(ready.clone()) { - Ok(Async::NotReady) => {} - Ok(Async::Ready(e)) => res = Some(Ok(e)), - Err(e) => res = Some(Err(e)), + loop { + if future_fired { + let res = try!(CURRENT_LOOP.set(self, || { + task.poll_future(ready.clone()) + })); + if let Async::Ready(e) = res { + return Ok(e) + } } - res.is_some() - }); - res.expect("run should not return until future is done") + future_fired = self.poll(None); + } } /// Performs one iteration of the event loop, blocking on waiting for events @@ -239,62 +236,44 @@ impl Core { /// `loop { lp.turn(None) }` is equivalent to calling `run` with an /// empty future (one that never finishes). pub fn turn(&mut self, max_wait: Option) { - self.poll_internal(max_wait, &mut || true).expect("Error in event loop turn"); + self.poll(max_wait); } - fn _run(&mut self, done: &mut FnMut() -> bool) { - // Check to see if we're done immediately, if so we shouldn't do any - // work. - if CURRENT_LOOP.set(self, || done()) { - return - } - - let mut finished = false; - while !finished { - finished = self.poll_internal(None, done).expect("Error in event loop") - } - } - - fn poll_internal(&mut self, max_wait: Option, done: &mut FnMut() -> bool) -> io::Result { - let amt; + fn poll(&mut self, max_wait: Option) -> bool { + // Given the `max_wait` variable specified, figure out the actual + // timeout that we're going to pass to `poll`. This involves taking a + // look at active timers on our heap as well. let start = Instant::now(); - { - let inner = self.inner.borrow_mut(); - let timeout = inner.timer_heap.peek().map(|t| { - if t.0 < start { - Duration::new(0, 0) - } else { - t.0 - start - } - }); - let timeout = if let (Some(d1), Some(d2)) = (max_wait, timeout) { - Some(cmp::min(d1, d2)) + let timeout = self.inner.borrow_mut().timer_heap.peek().map(|t| { + if t.0 < start { + Duration::new(0, 0) } else { - max_wait.or(timeout) - }; - match inner.io.poll(&mut self.events, timeout) { - Ok(a) => { - amt = a; - } - // On Linux, Poll::poll is epoll_wait, which may return EINTR if a - // ptracer attaches. - Err(ref e) if e.kind() == ErrorKind::Interrupted => { - return Ok(false) - }, - Err(e) => { - return Err(e) - }, + t.0 - start } - } - debug!("loop poll - {:?}", start.elapsed()); - debug!("loop time - {:?}", Instant::now()); + }); + let timeout = match (max_wait, timeout) { + (Some(d1), Some(d2)) => Some(cmp::min(d1, d2)), + (max_wait, timeout) => max_wait.or(timeout), + }; - // First up, process all timeouts that may have just occurred. - let start = Instant::now(); - self.consume_timeouts(start); + // Block waiting for an event to happen, peeling out how many events + // happened. + let amt = match self.inner.borrow_mut().io.poll(&mut self.events, timeout) { + Ok(a) => a, + Err(ref e) if e.kind() == ErrorKind::Interrupted => return false, + Err(e) => panic!("error in poll: {}", e), + }; - // Next, process all the events that came in. - let mut finished = false; + let after_poll = Instant::now(); + debug!("loop poll - {:?}", after_poll - start); + debug!("loop time - {:?}", after_poll); + + // Process all timeouts that may have just occurred, updating the + // current time since + self.consume_timeouts(after_poll); + + // Process all the events that came in, dispatching appropriately + let mut fired = false; for i in 0..self.events.len() { let event = self.events.get(i).unwrap(); let token = event.token(); @@ -304,15 +283,13 @@ impl Core { CURRENT_LOOP.set(&self, || self.consume_queue()); } else if token == TOKEN_FUTURE { self.future_readiness.0.set_readiness(mio::Ready::none()).unwrap(); - if !finished && CURRENT_LOOP.set(self, || done()) { - finished = true; - } + fired = true; } else { self.dispatch(token, event.kind()); } } - debug!("loop process - {} events, {:?}", amt, start.elapsed()); - Ok(finished) + debug!("loop process - {} events, {:?}", amt, after_poll.elapsed()); + return fired } fn dispatch(&mut self, token: mio::Token, ready: mio::Ready) {