use std::mem;
use std::ptr;
use std::time::Duration;
use libc::c_void;
use libc::eventfd;
use libc::read;
use libc::write;
use libc::POLLIN;
use serde::Deserialize;
use serde::Serialize;
use super::errno_result;
use super::Error;
use super::RawDescriptor;
use super::Result;
use crate::descriptor::AsRawDescriptor;
use crate::descriptor::FromRawDescriptor;
use crate::descriptor::IntoRawDescriptor;
use crate::descriptor::SafeDescriptor;
use crate::handle_eintr_errno;
use crate::unix::duration_to_timespec;
use crate::EventWaitResult;
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub(crate) struct PlatformEvent {
event_handle: SafeDescriptor,
}
pub trait EventExt {
fn write_count(&self, v: u64) -> Result<()>;
fn read_count(&self) -> Result<u64>;
}
impl EventExt for crate::Event {
fn write_count(&self, v: u64) -> Result<()> {
self.0.write_count(v)
}
fn read_count(&self) -> Result<u64> {
self.0.read_count()
}
}
impl PlatformEvent {
pub fn new() -> Result<PlatformEvent> {
let ret = unsafe { eventfd(0, 0) };
if ret < 0 {
return errno_result();
}
Ok(PlatformEvent {
event_handle: unsafe { SafeDescriptor::from_raw_descriptor(ret) },
})
}
pub fn write_count(&self, v: u64) -> Result<()> {
let ret = handle_eintr_errno!(unsafe {
write(
self.as_raw_descriptor(),
&v as *const u64 as *const c_void,
mem::size_of::<u64>(),
)
});
if ret < 0 {
return errno_result();
}
if ret as usize != mem::size_of::<u64>() {
return Err(Error::new(libc::EIO));
}
Ok(())
}
pub fn read_count(&self) -> Result<u64> {
let mut buf: u64 = 0;
let ret = handle_eintr_errno!(unsafe {
read(
self.as_raw_descriptor(),
&mut buf as *mut u64 as *mut c_void,
mem::size_of::<u64>(),
)
});
if ret < 0 {
return errno_result();
}
if ret as usize != mem::size_of::<u64>() {
return Err(Error::new(libc::EIO));
}
Ok(buf)
}
pub fn signal(&self) -> Result<()> {
self.write_count(1)
}
pub fn wait(&self) -> Result<()> {
self.read_count().map(|_| ())
}
pub fn wait_timeout(&self, timeout: Duration) -> Result<EventWaitResult> {
let mut pfd = libc::pollfd {
fd: self.as_raw_descriptor(),
events: POLLIN,
revents: 0,
};
let timeoutspec: libc::timespec = duration_to_timespec(timeout);
let ret = unsafe {
libc::ppoll(
&mut pfd as *mut libc::pollfd,
1,
&timeoutspec,
ptr::null_mut(),
)
};
if ret < 0 {
return errno_result();
}
if pfd.revents == 0 {
return Ok(EventWaitResult::TimedOut);
}
self.wait()?;
Ok(EventWaitResult::Signaled)
}
pub fn reset(&self) -> Result<()> {
let _: EventWaitResult = self.wait_timeout(Duration::ZERO)?;
Ok(())
}
pub fn try_clone(&self) -> Result<PlatformEvent> {
self.event_handle
.try_clone()
.map(|event_handle| PlatformEvent { event_handle })
}
}
impl AsRawDescriptor for PlatformEvent {
fn as_raw_descriptor(&self) -> RawDescriptor {
self.event_handle.as_raw_descriptor()
}
}
impl FromRawDescriptor for PlatformEvent {
unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Self {
PlatformEvent {
event_handle: SafeDescriptor::from_raw_descriptor(descriptor),
}
}
}
impl IntoRawDescriptor for PlatformEvent {
fn into_raw_descriptor(self) -> RawDescriptor {
self.event_handle.into_raw_descriptor()
}
}
impl From<PlatformEvent> for SafeDescriptor {
fn from(evt: PlatformEvent) -> Self {
evt.event_handle
}
}
impl From<SafeDescriptor> for PlatformEvent {
fn from(sd: SafeDescriptor) -> Self {
PlatformEvent { event_handle: sd }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Event;
use crate::EventExt;
#[test]
fn new() {
Event::new().unwrap();
}
#[test]
fn read_write() {
let evt = Event::new().unwrap();
evt.write_count(55).unwrap();
assert_eq!(evt.read_count(), Ok(55));
}
#[test]
fn clone() {
let evt = Event::new().unwrap();
let evt_clone = evt.try_clone().unwrap();
evt.write_count(923).unwrap();
assert_eq!(evt_clone.read_count(), Ok(923));
}
#[test]
fn timeout() {
let evt = Event::new().expect("failed to create eventfd");
assert_eq!(
evt.wait_timeout(Duration::from_millis(1))
.expect("failed to read from eventfd with timeout"),
EventWaitResult::TimedOut
);
}
}