use std::collections::HashMap;
use std::io;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use super::super::driver_failure::DriverFailureState;
use super::super::metrics::ReactorMetrics;
#[cfg(any(unix, windows))]
use super::super::waiter_cancellation::WaiterCancellationState;
#[cfg(all(test, windows))]
use super::types::FdKey;
use super::types::IoReactor;
#[cfg(all(test, windows))]
use crate::RawFd;
use crate::{Reactor, create_reactor};
impl IoReactor {
pub fn new() -> io::Result<Self> {
let platform_reactor = create_reactor()?;
let platform_reactor = Arc::new(platform_reactor);
let running = Arc::new(AtomicBool::new(false));
let registered_fds = Arc::new(Mutex::new(HashMap::new()));
let driver_failure = DriverFailureState::default();
#[cfg(windows)]
let platform_generations = Arc::new(Mutex::new(HashMap::new()));
#[cfg(any(unix, windows))]
let waiter_cancellations = WaiterCancellationState::new(
Arc::clone(&platform_reactor),
Arc::clone(&running),
Arc::clone(®istered_fds),
#[cfg(windows)]
Arc::clone(&platform_generations),
driver_failure.clone(),
);
Ok(Self {
platform_reactor,
running,
registered_fds,
driver_failure,
#[cfg(windows)]
platform_generations,
#[cfg(any(unix, windows))]
waiter_cancellations,
metrics: Arc::new(ReactorMetrics::default()),
})
}
#[cfg(all(test, windows))]
pub(in crate::reactor) fn has_platform_generation(&self, fd: RawFd) -> bool {
self.platform_generations
.lock()
.unwrap_or_else(|poison| poison.into_inner())
.contains_key(&FdKey::from(fd))
}
pub fn run(&self) -> io::Result<()> {
self.metrics
.start_time
.set(Instant::now())
.map_err(|_| io::Error::other("Reactor already started"))?;
self.running.store(true, Ordering::Relaxed);
while self.running.load(Ordering::Relaxed) {
if let Err(error) = self.run_iteration(Some(Duration::from_millis(10))) {
return Err(self.publish_driver_failure(error));
}
}
Ok(())
}
pub fn run_iteration(&self, timeout: Option<Duration>) -> io::Result<()> {
#[cfg(test)]
if let Some(error) = self.driver_failure.take_iteration_failure() {
return Err(error);
}
let iteration_start = Instant::now();
#[cfg(any(unix, windows))]
{
let events = self.platform_reactor.poll_registered_events(timeout)?;
for event in events {
self.handle_polled_event(event)?;
}
}
#[cfg(not(any(unix, windows)))]
{
let events = self.platform_reactor.poll_events(timeout)?;
for event in events {
self.handle_event(event)?;
}
}
let iteration_time = iteration_start.elapsed().as_nanos() as u64;
self.metrics
.avg_event_time_ns
.store(iteration_time, Ordering::Relaxed);
Ok(())
}
pub fn stop(&self) -> io::Result<()> {
self.running.store(false, Ordering::Relaxed);
self.platform_reactor.wake()
}
pub fn wake(&self) -> io::Result<()> {
self.platform_reactor.wake()
}
pub fn metrics(&self) -> ReactorMetrics {
ReactorMetrics {
events_processed: AtomicU64::new(self.metrics.events_processed.load(Ordering::Relaxed)),
avg_event_time_ns: AtomicU64::new(
self.metrics.avg_event_time_ns.load(Ordering::Relaxed),
),
peak_fd_count: AtomicU64::new(self.metrics.peak_fd_count.load(Ordering::Relaxed)),
start_time: std::sync::OnceLock::new(),
}
}
}