//! The core reactor driving all I/O. //! //! This module contains the [`Core`] reactor type which is the event loop for //! all I/O happening in `tokio`. This core reactor (or event loop) is used to //! drive I/O resources. //! //! The [`Handle`] and [`Remote`] structs are refences to the event loop, //! created by the [`handle`][handle_method] and [`remote`][remote_method] //! respectively, and are used to construct I/O objects. `Remote` is sendable, //! while `Handle` is not. //! //! Lastly [`PollEvented`] can be used to construct I/O objects that interact //! with the event loop, e.g. [`TcpStream`] in the net module. //! //! [`Core`]: struct.Core.html //! [`Handle`]: struct.Handle.html //! [`Remote`]: struct.Remote.html //! [handle_method]: struct.Core.html#method.handle //! [remote_method]: struct.Core.html#method.remote //! [`PollEvented`]: struct.PollEvented.html //! [`TcpStream`]: ../net/struct.TcpStream.html use std::fmt; use std::io::{self, ErrorKind}; use std::sync::{Arc, Weak, RwLock}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{Duration}; use futures::{Future, Async}; use futures::executor::{self, Notify}; use futures::task::{AtomicTask}; use mio; use mio::event::Evented; use slab::Slab; mod io_token; mod poll_evented; pub use self::poll_evented::PollEvented; /// The core reactor, or event loop. /// /// The event loop is the main source of blocking in an application which drives /// all other I/O events and notifications happening. Each event loop can have /// multiple handles pointing to it, each of which can then be used to create /// various I/O objects to interact with the event loop in interesting ways. pub struct Core { /// Reuse the `mio::Events` value across calls to poll. events: mio::Events, /// State shared between the reactor and the handles. inner: Arc, /// Used for determining when the future passed to `run` is ready. Once the /// registration is passed to `io` above we never touch it again, just keep /// it alive. _future_registration: mio::Registration, future_readiness: Arc, } struct Inner { /// The underlying system event queue. io: mio::Poll, /// Dispatch slabs for I/O and futures events io_dispatch: RwLock>, } /// A handle to an event loop. /// /// A `Handle` is used for associating I/O objects with an event loop /// explicitly. Typically though you won't end up using a `Handle` that often /// and will instead use and implicitly configured handle for your thread. #[derive(Clone)] pub struct Handle { inner: Weak, } struct ScheduledIo { readiness: AtomicUsize, reader: AtomicTask, writer: AtomicTask, } enum Direction { Read, Write, } const TOKEN_FUTURE: mio::Token = mio::Token(1); const TOKEN_START: usize = 2; fn _assert_kinds() { fn _assert() {} _assert::(); } impl Core { /// Creates a new event loop, returning any error that happened during the /// creation. pub fn new() -> io::Result { // Create the I/O poller let io = try!(mio::Poll::new()); // Create a registration for unblocking the reactor when the "run" // future becomes ready. let future_pair = mio::Registration::new2(); try!(io.register(&future_pair.0, TOKEN_FUTURE, mio::Ready::readable(), mio::PollOpt::level())); Ok(Core { events: mio::Events::with_capacity(1024), _future_registration: future_pair.0, future_readiness: Arc::new(MySetReadiness(future_pair.1)), inner: Arc::new(Inner { io: io, io_dispatch: RwLock::new(Slab::with_capacity(1)), }), }) } /// Returns a handle to this event loop which cannot be sent across threads /// but can be used as a proxy to the event loop itself. /// /// Handles are cloneable and clones always refer to the same event loop. /// This handle is typically passed into functions that create I/O objects /// to bind them to this event loop. pub fn handle(&self) -> Handle { Handle { inner: Arc::downgrade(&self.inner), } } /// Runs a future until completion, driving the event loop while we're /// otherwise waiting for the future to complete. /// /// This function will begin executing the event loop and will finish once /// the provided future is resolved. Note that the future argument here /// crucially does not require the `'static` nor `Send` bounds. As a result /// the future will be "pinned" to not only this thread but also this stack /// frame. /// /// This function will return the value that the future resolves to once /// the future has finished. If the future never resolves then this function /// will never return. /// /// # Panics /// /// This method will **not** catch panics from polling the future `f`. If /// the future panics then it's the responsibility of the caller to catch /// that panic and handle it as appropriate. pub fn run(&mut self, f: F) -> Result where F: Future, { let mut task = executor::spawn(f); let mut future_fired = true; loop { if future_fired { let res = task.poll_future_notify(&self.future_readiness, 0)?; if let Async::Ready(e) = res { return Ok(e) } } future_fired = self.poll(None); } } /// Performs one iteration of the event loop, blocking on waiting for events /// for at most `max_wait` (forever if `None`). /// /// It only makes sense to call this method if you've previously spawned /// a future onto this event loop. /// /// `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(max_wait); } fn poll(&mut self, max_wait: Option) -> bool { // Block waiting for an event to happen, peeling out how many events // happened. match self.inner.io.poll(&mut self.events, max_wait) { Ok(_) => {} Err(ref e) if e.kind() == ErrorKind::Interrupted => return false, // TODO: This should return an io::Result instead of panic. Err(e) => panic!("error in poll: {}", e), } // 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(); trace!("event {:?} {:?}", event.readiness(), event.token()); if token == TOKEN_FUTURE { self.future_readiness.0.set_readiness(mio::Ready::empty()).unwrap(); fired = true; } else { self.dispatch(token, event.readiness()); } } return fired } fn dispatch(&mut self, token: mio::Token, ready: mio::Ready) { let token = usize::from(token) - TOKEN_START; let io_dispatch = self.inner.io_dispatch.read().unwrap(); if let Some(io) = io_dispatch.get(token) { io.readiness.fetch_or(ready2usize(ready), Ordering::Relaxed); if ready.is_writable() { io.writer.notify(); } if !(ready & (!mio::Ready::writable())).is_empty() { io.reader.notify(); } } } } impl fmt::Debug for Core { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Core") } } impl Inner { /// Register an I/O resource with the reactor. /// /// The registration token is returned. fn add_source(&self, source: &Evented) -> io::Result { // Acquire a write lock let key = self.io_dispatch.write().unwrap() .insert(ScheduledIo { readiness: AtomicUsize::new(0), reader: AtomicTask::new(), writer: AtomicTask::new(), }); try!(self.io.register(source, mio::Token(TOKEN_START + key), mio::Ready::readable() | mio::Ready::writable() | platform::all(), mio::PollOpt::edge())); Ok(key) } fn deregister_source(&self, source: &Evented) -> io::Result<()> { self.io.deregister(source) } fn drop_source(&self, token: usize) { debug!("dropping I/O source: {}", token); self.io_dispatch.write().unwrap().remove(token); } /// Registers interest in the I/O resource associated with `token`. fn schedule(&self, token: usize, dir: Direction) { debug!("scheduling direction for: {}", token); let io_dispatch = self.io_dispatch.read().unwrap(); let sched = io_dispatch.get(token).unwrap(); let (task, ready) = match dir { Direction::Read => (&sched.reader, !mio::Ready::writable()), Direction::Write => (&sched.writer, mio::Ready::writable()), }; task.register(); if sched.readiness.load(Ordering::SeqCst) & ready2usize(ready) != 0 { task.notify(); } } } impl fmt::Debug for Handle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Handle") } } struct MySetReadiness(mio::SetReadiness); impl Notify for MySetReadiness { fn notify(&self, _id: usize) { self.0.set_readiness(mio::Ready::readable()) .expect("failed to set readiness"); } } fn read_ready() -> mio::Ready { mio::Ready::readable() | platform::hup() } const READ: usize = 1 << 0; const WRITE: usize = 1 << 1; fn ready2usize(ready: mio::Ready) -> usize { let mut bits = 0; if ready.is_readable() { bits |= READ; } if ready.is_writable() { bits |= WRITE; } bits | platform::ready2usize(ready) } fn usize2ready(bits: usize) -> mio::Ready { let mut ready = mio::Ready::empty(); if bits & READ != 0 { ready.insert(mio::Ready::readable()); } if bits & WRITE != 0 { ready.insert(mio::Ready::writable()); } ready | platform::usize2ready(bits) } #[cfg(all(unix, not(target_os = "fuchsia")))] mod platform { use mio::Ready; use mio::unix::UnixReady; pub fn aio() -> Ready { UnixReady::aio().into() } pub fn all() -> Ready { hup() | aio() } pub fn hup() -> Ready { UnixReady::hup().into() } const HUP: usize = 1 << 2; const ERROR: usize = 1 << 3; const AIO: usize = 1 << 4; pub fn ready2usize(ready: Ready) -> usize { let ready = UnixReady::from(ready); let mut bits = 0; if ready.is_aio() { bits |= AIO; } if ready.is_error() { bits |= ERROR; } if ready.is_hup() { bits |= HUP; } bits } pub fn usize2ready(bits: usize) -> Ready { let mut ready = UnixReady::from(Ready::empty()); if bits & AIO != 0 { ready.insert(UnixReady::aio()); } if bits & HUP != 0 { ready.insert(UnixReady::hup()); } if bits & ERROR != 0 { ready.insert(UnixReady::error()); } ready.into() } } #[cfg(any(windows, target_os = "fuchsia"))] mod platform { use mio::Ready; pub fn all() -> Ready { // No platform-specific Readinesses for Windows Ready::empty() } pub fn hup() -> Ready { Ready::empty() } pub fn ready2usize(_r: Ready) -> usize { 0 } pub fn usize2ready(_r: usize) -> Ready { Ready::empty() } }