use std::os::unix::io::{AsRawFd, RawFd};
use super::{Errno, Error, Result, SubscriberId};
use crate::epoll::EpollWrapper;
use vmm_sys_util::epoll::{ControlOperation, EpollEvent, EventSet};
#[derive(Clone, Copy, Debug)]
pub struct Events {
inner: EpollEvent,
}
impl PartialEq for Events {
fn eq(&self, other: &Events) -> bool {
self.fd() == other.fd()
&& self.data() == other.data()
&& self.event_set() == other.event_set()
}
}
impl Events {
pub(crate) fn with_inner(inner: EpollEvent) -> Self {
Self { inner }
}
pub fn empty<T: AsRawFd>(source: &T) -> Self {
Self::empty_raw(source.as_raw_fd())
}
pub fn empty_raw(fd: RawFd) -> Self {
Self::new_raw(fd, EventSet::empty())
}
pub fn new<T: AsRawFd>(source: &T, events: EventSet) -> Self {
Self::new_raw(source.as_raw_fd(), events)
}
pub fn new_raw(source: RawFd, events: EventSet) -> Self {
Self::with_data_raw(source, 0, events)
}
pub fn with_data<T: AsRawFd>(source: &T, data: u32, events: EventSet) -> Self {
Self::with_data_raw(source.as_raw_fd(), data, events)
}
pub fn with_data_raw(source: RawFd, data: u32, events: EventSet) -> Self {
let inner_data = ((data as u64) << 32) + (source as u64);
Events {
inner: EpollEvent::new(events, inner_data),
}
}
pub fn fd(&self) -> RawFd {
self.inner.data() as RawFd
}
pub fn data(&self) -> u32 {
(self.inner.data() >> 32) as u32
}
pub fn event_set(&self) -> EventSet {
self.inner.event_set()
}
pub fn epoll_event(&self) -> EpollEvent {
self.inner
}
}
pub struct EventOps<'a> {
epoll_wrapper: &'a mut EpollWrapper,
subscriber_id: SubscriberId,
}
impl<'a> EventOps<'a> {
pub(crate) fn new(epoll_wrapper: &'a mut EpollWrapper, subscriber_id: SubscriberId) -> Self {
EventOps {
epoll_wrapper,
subscriber_id,
}
}
fn ctl(&self, op: ControlOperation, events: Events) -> Result<()> {
self.epoll_wrapper
.epoll
.ctl(op, events.fd(), events.epoll_event())
.map_err(|e| Error::Epoll(Errno::from(e)))
}
pub fn add(&mut self, events: Events) -> Result<()> {
let fd = events.fd();
if self.epoll_wrapper.fd_dispatch.contains_key(&fd) {
return Err(Error::FdAlreadyRegistered);
}
self.ctl(ControlOperation::Add, events)?;
self.epoll_wrapper
.fd_dispatch
.insert(fd, self.subscriber_id);
self.epoll_wrapper
.subscriber_watch_list
.entry(self.subscriber_id)
.or_insert_with(Vec::new)
.push(fd);
Ok(())
}
pub fn modify(&self, events: Events) -> Result<()> {
self.ctl(ControlOperation::Modify, events)
}
pub fn remove(&mut self, events: Events) -> Result<()> {
self.ctl(ControlOperation::Delete, events)?;
self.epoll_wrapper.remove_event(events.fd());
if let Some(watch_list) = self
.epoll_wrapper
.subscriber_watch_list
.get_mut(&self.subscriber_id)
{
if let Some(index) = watch_list.iter().position(|&x| x == events.fd()) {
watch_list.remove(index);
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use vmm_sys_util::eventfd::EventFd;
#[test]
fn test_empty_events() {
let event_fd = EventFd::new(0).unwrap();
let events_raw = Events::empty_raw(event_fd.as_raw_fd());
let events = Events::empty(&event_fd);
assert_eq!(events, events_raw);
assert_eq!(events.event_set(), EventSet::empty());
assert_eq!(events.data(), 0);
assert_eq!(events.fd(), event_fd.as_raw_fd());
}
#[test]
fn test_events_no_data() {
let event_fd = EventFd::new(0).unwrap();
let event_set = EventSet::IN;
let events_raw = Events::new_raw(event_fd.as_raw_fd(), event_set);
let events = Events::new(&event_fd, event_set);
assert_eq!(events_raw, events);
assert_eq!(events.data(), 0);
assert_eq!(events.fd(), event_fd.as_raw_fd());
assert_eq!(events.event_set(), event_set);
}
#[test]
fn test_events_data() {
let event_fd = EventFd::new(0).unwrap();
let event_set = EventSet::IN;
let events_raw = Events::with_data_raw(event_fd.as_raw_fd(), 42, event_set);
let events = Events::with_data(&event_fd, 43, event_set);
assert_ne!(events_raw, events);
assert_eq!(events.data(), 43);
assert_eq!(events_raw.data(), 42);
}
}