use std::{
collections::BTreeMap,
convert::TryFrom,
io,
os::fd::{AsFd, BorrowedFd},
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
task::Wake,
};
use log::{error, warn};
use nix::{
errno::Errno,
poll::PollTimeout,
sys::{
epoll::{Epoll, EpollCreateFlags, EpollEvent, EpollFlags},
eventfd::{EfdFlags, EventFd},
},
};
use thiserror::Error;
use crate::device::Device;
#[derive(Debug, PartialEq)]
pub enum DeviceEvent {
CaptureReady,
OutputReady,
V4L2Event,
}
#[derive(Debug, PartialEq)]
pub enum PollEvent {
Device(DeviceEvent),
Waker(u32),
}
pub struct PollEvents {
events: [EpollEvent; 4],
nb_events: usize,
cur_event: usize,
}
impl PollEvents {
fn new() -> Self {
PollEvents {
events: [
EpollEvent::empty(),
EpollEvent::empty(),
EpollEvent::empty(),
EpollEvent::empty(),
],
nb_events: 0,
cur_event: 0,
}
}
}
impl Iterator for PollEvents {
type Item = PollEvent;
fn next(&mut self) -> Option<Self::Item> {
if self.cur_event >= self.nb_events {
return None;
}
let slot = &mut self.events[self.cur_event];
match slot.data() {
DEVICE_ID => {
if slot.events().contains(EpollFlags::EPOLLOUT) {
*slot = EpollEvent::new(
slot.events().difference(EpollFlags::EPOLLOUT),
slot.data(),
);
Some(PollEvent::Device(DeviceEvent::OutputReady))
} else if slot.events().contains(EpollFlags::EPOLLIN) {
*slot =
EpollEvent::new(slot.events().difference(EpollFlags::EPOLLIN), slot.data());
Some(PollEvent::Device(DeviceEvent::CaptureReady))
} else if slot.events().contains(EpollFlags::EPOLLPRI) {
*slot = EpollEvent::new(
slot.events().difference(EpollFlags::EPOLLPRI),
slot.data(),
);
Some(PollEvent::Device(DeviceEvent::V4L2Event))
} else {
self.cur_event += 1;
self.next()
}
}
waker_id @ FIRST_WAKER_ID..=LAST_WAKER_ID => {
self.cur_event += 1;
Some(PollEvent::Waker(waker_id as u32))
}
_ => panic!("Unregistered token returned by epoll_wait!"),
}
}
}
pub struct Waker {
fd: EventFd,
}
impl Waker {
fn new() -> io::Result<Self> {
Ok(Waker {
fd: EventFd::from_value_and_flags(0, EfdFlags::EFD_CLOEXEC | EfdFlags::EFD_NONBLOCK)?,
})
}
fn wake_direct(&self) -> nix::Result<()> {
self.fd.write(1).map(|_| ())
}
fn reset(&self) -> nix::Result<()> {
match self.fd.read() {
Ok(_) | Err(Errno::EAGAIN) => Ok(()),
Err(e) => Err(e),
}
}
}
impl Wake for Waker {
fn wake(self: Arc<Self>) {
self.wake_direct().unwrap_or_else(|e| {
error!("Failed to signal Waker: {}", e);
});
}
}
pub struct Poller {
device: Arc<Device>,
wakers: BTreeMap<u32, Arc<Waker>>,
epoll: Epoll,
capture_enabled: bool,
output_enabled: bool,
events_enabled: bool,
poll_wakeups_counter: Option<Arc<AtomicUsize>>,
}
const FIRST_WAKER_ID: u64 = 0;
const LAST_WAKER_ID: u64 = DEVICE_ID - 1;
const DEVICE_ID: u64 = 1 << 32;
#[derive(Debug, Error)]
pub enum PollError {
#[error("timeout value too large for epoll")]
TimeoutTryFromError,
#[error("error during call to epoll_wait: {0}")]
EPollWait(nix::Error),
#[error("error while resetting the waker: {0}")]
WakerReset(nix::Error),
#[error("V4L2 device returned EPOLLERR")]
V4L2Device,
}
impl Poller {
pub fn new(device: Arc<Device>) -> nix::Result<Self> {
let epoll = Epoll::new(EpollCreateFlags::EPOLL_CLOEXEC)?;
epoll.add(&device, EpollEvent::new(EpollFlags::EPOLLIN, DEVICE_ID))?;
epoll.wait(&mut [EpollEvent::empty()], 10u8)?;
epoll.modify(
&device,
&mut EpollEvent::new(EpollFlags::empty(), DEVICE_ID),
)?;
Ok(Poller {
device,
wakers: BTreeMap::new(),
epoll,
capture_enabled: false,
output_enabled: false,
events_enabled: false,
poll_wakeups_counter: None,
})
}
pub fn add_waker(&mut self, id: u32) -> io::Result<Arc<Waker>> {
match self.wakers.entry(id) {
std::collections::btree_map::Entry::Vacant(entry) => {
let waker = Waker::new()?;
self.epoll.add(
&waker.fd,
EpollEvent::new(EpollFlags::EPOLLIN, FIRST_WAKER_ID + id as u64),
)?;
let waker = Arc::new(waker);
entry.insert(Arc::clone(&waker));
Ok(waker)
}
std::collections::btree_map::Entry::Occupied(_) => Err(io::Error::new(
io::ErrorKind::AlreadyExists,
format!("A waker with id {} is already registered", id),
)),
}
}
pub fn remove_waker(&mut self, id: u32) -> io::Result<Arc<Waker>> {
match self.wakers.entry(id) {
std::collections::btree_map::Entry::Vacant(_) => Err(io::Error::new(
io::ErrorKind::AlreadyExists,
format!("No waker with id {} in this poller", id),
)),
std::collections::btree_map::Entry::Occupied(entry) => {
self.epoll.delete(&entry.get().fd)?;
Ok(entry.remove())
}
}
}
pub fn set_poll_counter(&mut self, poll_wakeup_counter: Arc<AtomicUsize>) {
self.poll_wakeups_counter = Some(poll_wakeup_counter);
}
fn update_device_registration(&mut self) -> nix::Result<()> {
let mut epoll_flags = EpollFlags::empty();
if self.capture_enabled {
epoll_flags.insert(EpollFlags::EPOLLIN);
}
if self.output_enabled {
epoll_flags.insert(EpollFlags::EPOLLOUT);
}
if self.events_enabled {
epoll_flags.insert(EpollFlags::EPOLLPRI);
}
let mut epoll_event = EpollEvent::new(epoll_flags, DEVICE_ID);
self.epoll
.modify(&self.device, &mut epoll_event)
.map(|_| ())
}
fn set_event(&mut self, event: DeviceEvent, enable: bool) -> nix::Result<()> {
let event = match event {
DeviceEvent::CaptureReady => &mut self.capture_enabled,
DeviceEvent::OutputReady => &mut self.output_enabled,
DeviceEvent::V4L2Event => &mut self.events_enabled,
};
if *event == enable {
return Ok(());
}
*event = enable;
self.update_device_registration()
}
pub fn enable_event(&mut self, event: DeviceEvent) -> nix::Result<()> {
self.set_event(event, true)
}
pub fn disable_event(&mut self, event: DeviceEvent) -> nix::Result<()> {
self.set_event(event, false)
}
pub fn is_event_enabled(&self, event: DeviceEvent) -> bool {
match event {
DeviceEvent::CaptureReady => self.capture_enabled,
DeviceEvent::OutputReady => self.output_enabled,
DeviceEvent::V4L2Event => self.events_enabled,
}
}
pub fn poll(&mut self, duration: Option<std::time::Duration>) -> Result<PollEvents, PollError> {
let mut events = PollEvents::new();
let duration: PollTimeout = match duration {
None => PollTimeout::NONE,
Some(d) => PollTimeout::try_from(d).map_err(|_| PollError::TimeoutTryFromError)?,
};
events.nb_events = self
.epoll
.wait(&mut events.events, duration)
.map_err(PollError::EPollWait)?;
if let Some(wakeup_counter) = &self.poll_wakeups_counter {
wakeup_counter.fetch_add(1, Ordering::SeqCst);
}
for event in &events.events[0..events.nb_events] {
if event.data() <= LAST_WAKER_ID {
match self.wakers.get(&(event.data() as u32)) {
Some(waker) => waker.reset().map_err(PollError::WakerReset)?,
None => warn!("Unregistered waker has been signaled."),
}
}
}
for event in &events.events[0..events.nb_events] {
if event.data() == DEVICE_ID && event.events().contains(EpollFlags::EPOLLERR) {
error!("V4L2 device returned EPOLLERR!");
return Err(PollError::V4L2Device);
}
}
Ok(events)
}
}
impl AsFd for Poller {
fn as_fd(&self) -> BorrowedFd {
self.epoll.0.as_fd()
}
}
#[cfg(test)]
mod tests {
use std::os::fd::AsFd;
use super::{DeviceEvent::*, PollEvent, PollEvents, Waker};
use super::{DEVICE_ID, FIRST_WAKER_ID};
use nix::poll::PollTimeout;
use nix::sys::epoll::{Epoll, EpollCreateFlags, EpollEvent, EpollFlags};
#[test]
fn test_waker() {
let waker = Waker::new().unwrap();
let epoll = Epoll::new(EpollCreateFlags::empty()).unwrap();
let mut event = [EpollEvent::empty()];
epoll
.add(
waker.fd.as_fd(),
EpollEvent::new(EpollFlags::EPOLLIN, FIRST_WAKER_ID),
)
.unwrap();
let nb_events = epoll.wait(&mut event, PollTimeout::ZERO).unwrap();
assert_eq!(nb_events, 0);
waker.wake_direct().unwrap();
let nb_events = epoll.wait(&mut event, PollTimeout::ZERO).unwrap();
assert_eq!(nb_events, 1);
assert_eq!(
event[0],
EpollEvent::new(EpollFlags::EPOLLIN, FIRST_WAKER_ID)
);
waker.wake_direct().unwrap();
let nb_events = epoll.wait(&mut event, PollTimeout::ZERO).unwrap();
assert_eq!(nb_events, 1);
assert_eq!(
event[0],
EpollEvent::new(EpollFlags::EPOLLIN, FIRST_WAKER_ID)
);
waker.reset().unwrap();
let nb_events = epoll.wait(&mut event, PollTimeout::ZERO).unwrap();
assert_eq!(nb_events, 0);
waker.reset().unwrap();
let nb_events = epoll.wait(&mut event, PollTimeout::ZERO).unwrap();
assert_eq!(nb_events, 0);
}
#[test]
fn test_pollevents_iterator() {
let mut poll_events = PollEvents::new();
assert_eq!(poll_events.next(), None);
let mut poll_events = PollEvents::new();
poll_events.events[0] = EpollEvent::new(EpollFlags::EPOLLIN, DEVICE_ID);
poll_events.nb_events = 1;
assert_eq!(poll_events.next(), Some(PollEvent::Device(CaptureReady)));
assert_eq!(poll_events.next(), None);
let mut poll_events = PollEvents::new();
poll_events.events[0] = EpollEvent::new(EpollFlags::EPOLLOUT, DEVICE_ID);
poll_events.nb_events = 1;
assert_eq!(poll_events.next(), Some(PollEvent::Device(OutputReady)));
assert_eq!(poll_events.next(), None);
let mut poll_events = PollEvents::new();
poll_events.events[0] = EpollEvent::new(EpollFlags::EPOLLPRI, DEVICE_ID);
poll_events.nb_events = 1;
assert_eq!(poll_events.next(), Some(PollEvent::Device(V4L2Event)));
assert_eq!(poll_events.next(), None);
let mut poll_events = PollEvents::new();
poll_events.events[0] =
EpollEvent::new(EpollFlags::EPOLLPRI | EpollFlags::EPOLLOUT, DEVICE_ID);
poll_events.nb_events = 1;
assert_eq!(poll_events.next(), Some(PollEvent::Device(OutputReady)));
assert_eq!(poll_events.next(), Some(PollEvent::Device(V4L2Event)));
assert_eq!(poll_events.next(), None);
let mut poll_events = PollEvents::new();
poll_events.events[0] = EpollEvent::new(EpollFlags::EPOLLIN, DEVICE_ID);
poll_events.events[1] =
EpollEvent::new(EpollFlags::EPOLLPRI | EpollFlags::EPOLLOUT, DEVICE_ID);
poll_events.nb_events = 2;
assert_eq!(poll_events.next(), Some(PollEvent::Device(CaptureReady)));
assert_eq!(poll_events.next(), Some(PollEvent::Device(OutputReady)));
assert_eq!(poll_events.next(), Some(PollEvent::Device(V4L2Event)));
assert_eq!(poll_events.next(), None);
let mut poll_events = PollEvents::new();
poll_events.events[0] = EpollEvent::new(EpollFlags::empty(), FIRST_WAKER_ID);
poll_events.nb_events = 1;
assert_eq!(poll_events.next(), Some(PollEvent::Waker(0)));
assert_eq!(poll_events.next(), None);
let mut poll_events = PollEvents::new();
poll_events.events[0] = EpollEvent::new(EpollFlags::empty(), FIRST_WAKER_ID + 20);
poll_events.events[1] = EpollEvent::new(EpollFlags::empty(), FIRST_WAKER_ID + 42);
poll_events.events[2] = EpollEvent::new(EpollFlags::empty(), FIRST_WAKER_ID);
poll_events.nb_events = 3;
assert_eq!(poll_events.next(), Some(PollEvent::Waker(20)));
assert_eq!(poll_events.next(), Some(PollEvent::Waker(42)));
assert_eq!(poll_events.next(), Some(PollEvent::Waker(0)));
assert_eq!(poll_events.next(), None);
let mut poll_events = PollEvents::new();
poll_events.events[0] = EpollEvent::new(EpollFlags::empty(), FIRST_WAKER_ID + 20);
poll_events.events[1] = EpollEvent::new(EpollFlags::empty(), FIRST_WAKER_ID + 42);
poll_events.events[2] =
EpollEvent::new(EpollFlags::EPOLLPRI | EpollFlags::EPOLLIN, DEVICE_ID);
poll_events.events[3] = EpollEvent::new(EpollFlags::empty(), FIRST_WAKER_ID);
poll_events.nb_events = 4;
assert_eq!(poll_events.next(), Some(PollEvent::Waker(20)));
assert_eq!(poll_events.next(), Some(PollEvent::Waker(42)));
assert_eq!(poll_events.next(), Some(PollEvent::Device(CaptureReady)));
assert_eq!(poll_events.next(), Some(PollEvent::Device(V4L2Event)));
assert_eq!(poll_events.next(), Some(PollEvent::Waker(0)));
assert_eq!(poll_events.next(), None);
}
}