use std::mem;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::RawFd;
use std::ptr;
use std::time::Duration;
use libc::clock_getres;
use libc::timerfd_create;
use libc::timerfd_settime;
use libc::CLOCK_MONOTONIC;
use libc::EAGAIN;
use libc::POLLIN;
use libc::TFD_CLOEXEC;
use libc::TFD_NONBLOCK;
use super::super::errno_result;
use super::super::Error;
use super::super::Result;
use crate::descriptor::AsRawDescriptor;
use crate::descriptor::FromRawDescriptor;
use crate::descriptor::SafeDescriptor;
use crate::handle_eintr_errno;
use crate::timer::Timer;
use crate::timer::TimerTrait;
use crate::unix::duration_to_timespec;
impl AsRawFd for Timer {
fn as_raw_fd(&self) -> RawFd {
self.handle.as_raw_descriptor()
}
}
impl Timer {
pub fn new() -> Result<Timer> {
let ret = unsafe { timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK) };
if ret < 0 {
return errno_result();
}
Ok(Timer {
handle: unsafe { SafeDescriptor::from_raw_descriptor(ret) },
interval: None,
})
}
fn set_time(&mut self, dur: Option<Duration>, interval: Option<Duration>) -> Result<()> {
self.interval = interval;
let spec = libc::itimerspec {
it_interval: duration_to_timespec(interval.unwrap_or_default()),
it_value: duration_to_timespec(dur.unwrap_or_default()),
};
let ret = unsafe { timerfd_settime(self.as_raw_descriptor(), 0, &spec, ptr::null_mut()) };
if ret < 0 {
return errno_result();
}
Ok(())
}
}
impl TimerTrait for Timer {
fn reset_oneshot(&mut self, dur: Duration) -> Result<()> {
self.set_time(Some(dur), None)
}
fn reset_repeating(&mut self, dur: Duration) -> Result<()> {
self.set_time(Some(dur), Some(dur))
}
fn clear(&mut self) -> Result<()> {
self.set_time(None, None)
}
fn wait(&mut self) -> Result<()> {
let mut pfd = libc::pollfd {
fd: self.as_raw_descriptor(),
events: POLLIN,
revents: 0,
};
let ret = handle_eintr_errno!(unsafe {
libc::ppoll(
&mut pfd as *mut libc::pollfd,
1,
ptr::null_mut(),
ptr::null_mut(),
)
});
if ret < 0 {
return errno_result();
}
let _ = self.mark_waited()?;
Ok(())
}
fn mark_waited(&mut self) -> Result<bool> {
let mut count = 0u64;
let ret = unsafe {
libc::read(
self.as_raw_descriptor(),
&mut count as *mut _ as *mut libc::c_void,
mem::size_of_val(&count),
)
};
if ret < 0 {
if Error::last().errno() == EAGAIN {
Ok(true)
} else {
errno_result()
}
} else {
Ok(false)
}
}
fn resolution(&self) -> Result<Duration> {
let mut res: libc::timespec = unsafe { mem::zeroed() };
let ret = unsafe { clock_getres(CLOCK_MONOTONIC, &mut res) };
if ret != 0 {
return errno_result();
}
Ok(Duration::new(res.tv_sec as u64, res.tv_nsec as u32))
}
}