use std::sync::OnceLock;
use crate::{Driver, Handle};
pub trait RawIoContext {
fn driver(&self) -> &Driver;
fn poller(&self) -> Handle;
}
#[cfg(feature = "mio-driver")]
mod default_context {
use std::{
io,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::JoinHandle,
};
use super::RawIoContext;
use crate::{mio::mio_driver, Cmd, Description, Driver, Handle};
pub struct MioContext {
driver: Driver,
poller: Handle,
flag: Arc<AtomicBool>,
join_handle: Option<JoinHandle<()>>,
}
impl MioContext {
pub fn new() -> io::Result<Self> {
let driver = mio_driver();
let poller = driver.fd_open(Description::Poller, crate::OpenFlags::None)?;
let flag: Arc<AtomicBool> = Default::default();
let flag_cloned = flag.clone();
let driver_cloned = driver.clone();
let join_handle = std::thread::spawn(move || {
while !flag_cloned.load(Ordering::Acquire) {
driver_cloned.fd_cntl(poller, Cmd::PollOnce(None)).unwrap();
}
});
Ok(Self {
driver,
poller,
flag,
join_handle: Some(join_handle),
})
}
}
impl Drop for MioContext {
fn drop(&mut self) {
self.flag.store(true, Ordering::Release);
self.join_handle.take().unwrap().join().unwrap();
}
}
impl RawIoContext for MioContext {
fn driver(&self) -> &Driver {
&self.driver
}
fn poller(&self) -> Handle {
self.poller
}
}
}
pub struct IoContext(Box<dyn RawIoContext + Send + Sync + 'static>);
impl RawIoContext for IoContext {
fn driver(&self) -> &Driver {
self.0.driver()
}
fn poller(&self) -> Handle {
self.0.poller()
}
}
static REGISTER: OnceLock<IoContext> = OnceLock::new();
pub fn register_io_context<C: RawIoContext + Send + Sync + 'static>(context: C) {
if REGISTER.set(IoContext(Box::new(context))).is_err() {
panic!("Register io context twice");
}
}
pub fn io_context() -> &'static IoContext {
#[cfg(feature = "mio-driver")]
return REGISTER
.get_or_init(|| IoContext(Box::new(default_context::MioContext::new().unwrap())));
#[cfg(not(feature = "mio-driver"))]
REGISTER
.get()
.as_ref()
.expect("Call register_io_context first")
}