diff --git a/CHANGELOG.md b/CHANGELOG.md index 075f8b4..82f404b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Version 0.17.5 - Improved support of keymodifier for linux, arrow keys, function keys, home keys etc. - Add `SetTitle` command to change the terminal title. +- Mio 0.7 update # Version 0.17.4 - Add macros for `Colorize` and `Styler` impls, add an impl for `String` diff --git a/Cargo.toml b/Cargo.toml index 50f0a4c..256195f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,8 +54,8 @@ crossterm_winapi = "0.6.1" # [target.'cfg(unix)'.dependencies] libc = "0.2" -mio = "0.6" -signal-hook = { version = "0.1.15", features = ["mio-support"] } +mio = {version="0.7", features=["os-poll"]} +signal-hook = { version = "0.1.15", features = ["mio-0_7-support"] } # # Dev dependencies (examples, ...) diff --git a/src/event/source/unix.rs b/src/event/source/unix.rs index ce83856..aa0286f 100644 --- a/src/event/source/unix.rs +++ b/src/event/source/unix.rs @@ -1,8 +1,8 @@ -use mio::{unix::EventedFd, Events, Poll, PollOpt, Ready, Token}; +use mio::{unix::SourceFd, Events, Interest, Poll, Token}; use signal_hook::iterator::Signals; -use std::{collections::VecDeque, time::Duration}; +use std::{collections::VecDeque, io, time::Duration}; -use crate::Result; +use crate::{ErrorKind, Result}; #[cfg(feature = "event-stream")] use super::super::sys::Waker; @@ -45,34 +45,17 @@ impl UnixInternalEventSource { pub(crate) fn from_file_descriptor(input_fd: FileDesc) -> Result { let poll = Poll::new()?; + let mut registry = poll.registry(); - // PollOpt::level vs PollOpt::edge mio documentation: - // - // > With edge-triggered events, operations must be performed on the Evented type until - // > WouldBlock is returned. - // - // TL;DR - DO NOT use PollOpt::edge. - // - // Because of the `try_read` nature (loop with returns) we can't use `PollOpt::edge`. All - // `Evented` handles MUST be registered with the `PollOpt::level`. - // - // If you have to use `PollOpt::edge` and there's no way how to do it with the `PollOpt::level`, - // be aware that the whole `TtyInternalEventSource` have to be rewritten - // (read everything from each `Evented`, process without returns, store all InternalEvent events - // into a buffer and then return first InternalEvent, etc.). Even these changes wont be - // enough, because `Poll::poll` wont fire again until additional `Evented` event happens and - // we can still have a buffer filled with InternalEvent events. let tty_raw_fd = input_fd.raw_fd(); - let tty_ev = EventedFd(&tty_raw_fd); - poll.register(&tty_ev, TTY_TOKEN, Ready::readable(), PollOpt::level())?; + let mut tty_ev = SourceFd(&tty_raw_fd); + registry.register(&mut tty_ev, TTY_TOKEN, Interest::READABLE)?; - let signals = Signals::new(&[signal_hook::SIGWINCH])?; - poll.register(&signals, SIGNAL_TOKEN, Ready::readable(), PollOpt::level())?; + let mut signals = Signals::new(&[signal_hook::SIGWINCH])?; + registry.register(&mut signals, SIGNAL_TOKEN, Interest::READABLE)?; #[cfg(feature = "event-stream")] - let waker = Waker::new()?; - #[cfg(feature = "event-stream")] - poll.register(&waker, WAKE_TOKEN, Ready::readable(), PollOpt::level())?; + let mut waker = Waker::new(registry, WAKE_TOKEN)?; Ok(UnixInternalEventSource { poll, @@ -107,20 +90,28 @@ impl EventSource for UnixInternalEventSource { for token in self.events.iter().map(|x| x.token()) { match token { TTY_TOKEN => { - let read_count = self.tty_fd.read(&mut self.tty_buffer, TTY_BUFFER_SIZE)?; - - if read_count > 0 { - self.poll - .poll(&mut additional_input_events, Some(Duration::from_secs(0)))?; - - let additional_input_available = additional_input_events - .iter() - .any(|event| event.token() == TTY_TOKEN); - - self.parser.advance( - &self.tty_buffer[..read_count], - additional_input_available, - ); + loop { + match self.tty_fd.read(&mut self.tty_buffer, TTY_BUFFER_SIZE) { + Ok(read_count) => { + if read_count > 0 { + self.parser.advance( + &self.tty_buffer[..read_count], + read_count == TTY_BUFFER_SIZE, + ); + } + } + Err(ErrorKind::IoError(e)) => { + // No more data to read at the moment. We will receive another event + if e.kind() == io::ErrorKind::WouldBlock { + break; + } + // once more data is available to read. + else if e.kind() == io::ErrorKind::Interrupted { + continue; + } + } + Err(e) => return Err(e), + }; if let Some(event) = self.parser.next() { return Ok(Some(event)); @@ -149,7 +140,6 @@ impl EventSource for UnixInternalEventSource { } #[cfg(feature = "event-stream")] WAKE_TOKEN => { - let _ = self.waker.reset(); return Err(std::io::Error::new( std::io::ErrorKind::Interrupted, "Poll operation was woken up by `Waker::wake`", diff --git a/src/event/sys/unix/waker.rs b/src/event/sys/unix/waker.rs index 9345210..f040827 100644 --- a/src/event/sys/unix/waker.rs +++ b/src/event/sys/unix/waker.rs @@ -1,101 +1,39 @@ -// TODO Replace with `mio::Waker` when the 0.7 is released (not available in 0.6). - use std::sync::{Arc, Mutex}; -use mio::{Evented, Poll, PollOpt, Ready, Registration, SetReadiness, Token}; +use mio::{Registry, Token}; -use crate::Result; - -#[derive(Debug)] -struct WakerInner { - registration: Registration, - set_readiness: SetReadiness, -} - -impl WakerInner { - fn new() -> Self { - let (registration, set_readiness) = Registration::new2(); - - Self { - registration, - set_readiness, - } - } - - fn wake(&self) -> Result<()> { - self.set_readiness.set_readiness(Ready::readable())?; - Ok(()) - } - - fn reset(&self) -> Result<()> { - self.set_readiness.set_readiness(Ready::empty())?; - Ok(()) - } -} +use crate::{ErrorKind, Result}; /// Allows to wake up the `mio::Poll::poll()` method. +/// This type wraps `mio::Waker`, for more information see its documentation. #[derive(Clone, Debug)] pub(crate) struct Waker { - inner: Arc>, + inner: Arc>, } impl Waker { - /// Creates a new waker. - /// - /// `Waker` implements the `mio::Evented` trait and you have to register - /// it in order to use it. - pub(crate) fn new() -> Result { + /// Create a new `Waker`. + pub(crate) fn new(registry: &Registry, waker_token: Token) -> Result { Ok(Self { - inner: Arc::new(Mutex::new(WakerInner::new())), + inner: Arc::new(Mutex::new(mio::Waker::new(registry, waker_token)?)), }) } - /// Wakes the `mio::Poll.poll()` method. + /// Wake up the [`Poll`] associated with this `Waker`. /// /// Readiness is set to `Ready::readable()`. pub(crate) fn wake(&self) -> Result<()> { - self.inner.lock().unwrap().wake() + self.inner + .lock() + .unwrap() + .wake() + .map_err(|e| ErrorKind::IoError(e)) } /// Resets the state so the same waker can be reused. /// - /// Readiness is set back to `Ready::empty()`. + /// This function is not impl pub(crate) fn reset(&self) -> Result<()> { - self.inner.lock().unwrap().reset() - } -} - -impl Evented for Waker { - fn register( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> ::std::io::Result<()> { - self.inner - .lock() - .unwrap() - .registration - .register(poll, token, interest, opts) - } - - fn reregister( - &self, - poll: &Poll, - token: Token, - interest: Ready, - opts: PollOpt, - ) -> ::std::io::Result<()> { - self.inner - .lock() - .unwrap() - .registration - .reregister(poll, token, interest, opts) - } - - #[allow(deprecated)] - fn deregister(&self, poll: &Poll) -> ::std::io::Result<()> { - self.inner.lock().unwrap().registration.deregister(poll) + Ok(()) } }