use std::collections::HashMap;
use std::os::unix::io::RawFd;
use vmm_sys_util::epoll::{ControlOperation, Epoll, EpollEvent};
use super::{Errno, Error, EventOps, Result, SubscriberId};
pub(crate) struct EpollWrapper {
pub(crate) epoll: Epoll,
pub(crate) fd_dispatch: HashMap<RawFd, SubscriberId>,
pub(crate) subscriber_watch_list: HashMap<SubscriberId, Vec<RawFd>>,
pub(crate) ready_events: Vec<EpollEvent>,
}
impl EpollWrapper {
pub(crate) fn new(ready_events_capacity: usize) -> Result<Self> {
Ok(EpollWrapper {
epoll: Epoll::new().map_err(|e| Error::Epoll(Errno::from(e)))?,
fd_dispatch: HashMap::new(),
subscriber_watch_list: HashMap::new(),
ready_events: vec![EpollEvent::default(); ready_events_capacity],
})
}
pub(crate) fn poll(&mut self, milliseconds: i32) -> Result<usize> {
let event_count = match self.epoll.wait(
self.ready_events.capacity(),
milliseconds,
&mut self.ready_events[..],
) {
Ok(ev) => ev,
Err(e) if e.raw_os_error() == Some(libc::EINTR) => return Ok(0),
Err(e) => return Err(Error::Epoll(Errno::from(e))),
};
Ok(event_count)
}
pub(crate) fn remove(&mut self, subscriber_id: SubscriberId) {
let fds = self
.subscriber_watch_list
.remove(&subscriber_id)
.unwrap_or_else(Vec::new);
for fd in fds {
let _ = self
.epoll
.ctl(ControlOperation::Delete, fd, EpollEvent::default());
self.remove_event(fd);
}
}
pub(crate) fn remove_event(&mut self, fd: RawFd) {
self.fd_dispatch.remove(&fd);
for event in self.ready_events.iter_mut() {
if event.fd() == fd {
*event = EpollEvent::default();
}
}
}
pub(crate) fn subscriber_id(&self, fd: RawFd) -> Option<SubscriberId> {
self.fd_dispatch.get(&fd).copied()
}
pub(crate) fn ops_unchecked(&mut self, subscriber_id: SubscriberId) -> EventOps {
EventOps::new(self, subscriber_id)
}
}