#![cfg_attr(not(feature = "rt"), allow(dead_code))]
mod interest;
#[allow(unreachable_pub)]
pub use interest::Interest;
mod ready;
#[allow(unreachable_pub)]
pub use ready::Ready;
mod registration;
pub(crate) use registration::Registration;
mod scheduled_io;
use scheduled_io::ScheduledIo;
use crate::park::{Park, Unpark};
use crate::util::slab::{self, Slab};
use crate::{loom::sync::Mutex, util::bit};
use std::fmt;
use std::io;
use std::sync::{Arc, Weak};
use std::time::Duration;
pub(crate) struct Driver {
tick: u8,
events: Option<mio::Events>,
resources: Option<Slab<ScheduledIo>>,
poll: mio::Poll,
inner: Arc<Inner>,
}
#[derive(Clone)]
pub(crate) struct Handle {
inner: Weak<Inner>,
}
pub(crate) struct ReadyEvent {
tick: u8,
pub(crate) ready: Ready,
}
pub(super) struct Inner {
resources: Mutex<Option<Slab<ScheduledIo>>>,
registry: mio::Registry,
pub(super) io_dispatch: slab::Allocator<ScheduledIo>,
waker: mio::Waker,
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
enum Direction {
Read,
Write,
}
enum Tick {
Set(u8),
Clear(u8),
}
const TOKEN_WAKEUP: mio::Token = mio::Token(1 << 31);
const ADDRESS: bit::Pack = bit::Pack::least_significant(24);
const GENERATION: bit::Pack = ADDRESS.then(7);
fn _assert_kinds() {
fn _assert<T: Send + Sync>() {}
_assert::<Handle>();
}
impl Driver {
pub(crate) fn new() -> io::Result<Driver> {
let poll = mio::Poll::new()?;
let waker = mio::Waker::new(poll.registry(), TOKEN_WAKEUP)?;
let registry = poll.registry().try_clone()?;
let slab = Slab::new();
let allocator = slab.allocator();
Ok(Driver {
tick: 0,
events: Some(mio::Events::with_capacity(1024)),
poll,
resources: Some(slab),
inner: Arc::new(Inner {
resources: Mutex::new(None),
registry,
io_dispatch: allocator,
waker,
}),
})
}
pub(crate) fn handle(&self) -> Handle {
Handle {
inner: Arc::downgrade(&self.inner),
}
}
fn turn(&mut self, max_wait: Option<Duration>) -> io::Result<()> {
const COMPACT_INTERVAL: u8 = 255;
self.tick = self.tick.wrapping_add(1);
if self.tick == COMPACT_INTERVAL {
self.resources.as_mut().unwrap().compact()
}
let mut events = self.events.take().expect("i/o driver event store missing");
match self.poll.poll(&mut events, max_wait) {
Ok(_) => {}
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
for event in events.iter() {
let token = event.token();
if token != TOKEN_WAKEUP {
self.dispatch(token, Ready::from_mio(event));
}
}
self.events = Some(events);
Ok(())
}
fn dispatch(&mut self, token: mio::Token, ready: Ready) {
let addr = slab::Address::from_usize(ADDRESS.unpack(token.0));
let resources = self.resources.as_mut().unwrap();
let io = match resources.get(addr) {
Some(io) => io,
None => return,
};
let res = io.set_readiness(Some(token.0), Tick::Set(self.tick), |curr| curr | ready);
if res.is_err() {
return;
}
io.wake(ready);
}
}
impl Drop for Driver {
fn drop(&mut self) {
(*self.inner.resources.lock()) = self.resources.take();
}
}
impl Drop for Inner {
fn drop(&mut self) {
let resources = self.resources.lock().take();
if let Some(mut slab) = resources {
slab.for_each(|io| {
io.shutdown();
});
}
}
}
impl Park for Driver {
type Unpark = Handle;
type Error = io::Error;
fn unpark(&self) -> Self::Unpark {
self.handle()
}
fn park(&mut self) -> io::Result<()> {
self.turn(None)?;
Ok(())
}
fn park_timeout(&mut self, duration: Duration) -> io::Result<()> {
self.turn(Some(duration))?;
Ok(())
}
fn shutdown(&mut self) {}
}
impl fmt::Debug for Driver {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Driver")
}
}
cfg_rt! {
impl Handle {
pub(super) fn current() -> Self {
crate::runtime::context::io_handle()
.expect("there is no reactor running, must be called from the context of Tokio runtime")
}
}
}
cfg_not_rt! {
impl Handle {
pub(super) fn current() -> Self {
panic!("there is no reactor running, must be called from the context of Tokio runtime with `rt` enabled.")
}
}
}
impl Handle {
fn wakeup(&self) {
if let Some(inner) = self.inner() {
inner.waker.wake().expect("failed to wake I/O driver");
}
}
pub(super) fn inner(&self) -> Option<Arc<Inner>> {
self.inner.upgrade()
}
}
impl Unpark for Handle {
fn unpark(&self) {
self.wakeup();
}
}
impl fmt::Debug for Handle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Handle")
}
}
impl Inner {
pub(super) fn add_source(
&self,
source: &mut impl mio::event::Source,
interest: Interest,
) -> io::Result<slab::Ref<ScheduledIo>> {
let (address, shared) = self.io_dispatch.allocate().ok_or_else(|| {
io::Error::new(
io::ErrorKind::Other,
"reactor at max registered I/O resources",
)
})?;
let token = GENERATION.pack(shared.generation(), ADDRESS.pack(address.as_usize(), 0));
self.registry
.register(source, mio::Token(token), interest.to_mio())?;
Ok(shared)
}
pub(super) fn deregister_source(&self, source: &mut impl mio::event::Source) -> io::Result<()> {
self.registry.deregister(source)
}
}
impl Direction {
pub(super) fn mask(self) -> Ready {
match self {
Direction::Read => Ready::READABLE | Ready::READ_CLOSED,
Direction::Write => Ready::WRITABLE | Ready::WRITE_CLOSED,
}
}
}