#![allow(dead_code)] extern crate libc; use libc::{c_int, c_void, time_t, timespec}; use std::io; use std::os::unix::io::{AsRawFd, RawFd}; use std::time::Duration; /* * libc timer implementation */ #[allow(non_camel_case_types)] #[repr(C)] struct itimerspec { it_interval: timespec, it_value: timespec, } #[allow(non_camel_case_types)] pub struct Itimerspec { pub it_interval: Duration, pub it_value: Duration, } extern "C" { fn timerfd_create(clockid: c_int, flags: c_int) -> RawFd; fn timerfd_settime( fd: RawFd, flags: c_int, new_value: *const itimerspec, old_value: *mut itimerspec, ) -> libc::c_int; fn timerfd_gettime(fd: RawFd, curr_value: *mut itimerspec) -> libc::c_int; } pub struct Timerfd(RawFd); impl Timerfd { pub fn create(clockid: c_int, flags: c_int) -> io::Result { let timerfd = unsafe { timerfd_create(clockid, flags) }; if timerfd == -1 { return Err(io::Error::last_os_error()); } Ok(Timerfd(timerfd)) } pub fn settime(&self, flags: c_int, new_value: &Itimerspec) -> io::Result { let new_raw = itimerspec { it_interval: timespec { tv_sec: new_value.it_interval.as_secs() as time_t, tv_nsec: new_value.it_interval.subsec_nanos() as i64, }, it_value: timespec { tv_sec: new_value.it_value.as_secs() as time_t, tv_nsec: new_value.it_value.subsec_nanos() as i64, }, }; let mut old_raw = itimerspec { it_interval: timespec { tv_sec: 0, tv_nsec: 0, }, it_value: timespec { tv_sec: 0, tv_nsec: 0, }, }; if unsafe { timerfd_settime(self.0, flags, &new_raw, &mut old_raw) } == -1 { return Err(io::Error::last_os_error()); } Ok(Itimerspec { it_interval: Duration::new( old_raw.it_interval.tv_sec as u64, old_raw.it_interval.tv_nsec as u32, ), it_value: Duration::new( old_raw.it_value.tv_sec as u64, old_raw.it_value.tv_nsec as u32, ), }) } pub fn gettime(&self) -> io::Result { let mut raw = itimerspec { it_interval: timespec { tv_sec: 0, tv_nsec: 0, }, it_value: timespec { tv_sec: 0, tv_nsec: 0, }, }; if unsafe { timerfd_gettime(self.0, &mut raw) } == -1 { return Err(io::Error::last_os_error()); } Ok(Itimerspec { it_interval: Duration::new( raw.it_interval.tv_sec as u64, raw.it_interval.tv_nsec as u32, ), it_value: Duration::new(raw.it_value.tv_sec as u64, raw.it_value.tv_nsec as u32), }) } pub fn read(&self) -> io::Result { let mut buf = 0u64; let nr = unsafe { libc::read( self.0, &mut buf as *mut _ as *mut c_void, ::std::mem::size_of::(), ) }; if nr == ::std::mem::size_of::() as isize { return Ok(buf); } Err(io::Error::last_os_error()) } } impl Drop for Timerfd { fn drop(&mut self) { unsafe { libc::close(self.0) }; } } impl AsRawFd for Timerfd { fn as_raw_fd(&self) -> RawFd { self.0 } } /* * mio Evented implementation */ extern crate mio; use mio::unix::SourceFd; use mio::{event, Interest, Registry, Token}; impl event::Source for Timerfd { fn register( &mut self, registry: &Registry, token: Token, interests: Interest, ) -> io::Result<()> { SourceFd(&self.0).register(registry, token, interests) } fn reregister( &mut self, registry: &Registry, token: Token, interests: Interest, ) -> io::Result<()> { SourceFd(&self.0).reregister(registry, token, interests) } fn deregister(&mut self, registry: &Registry) -> io::Result<()> { SourceFd(&self.0).deregister(registry) } } fn main() {}