1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
use std::os::unix::io::{RawFd, AsRawFd}; use std::io::{Error, Result}; use std::mem; use libc; /// An opaque handle to a kernel timer instance. /// /// On Linux this contains a file descriptor created with /// [timerfd_create()](http://man7.org/linux/man-pages/man2/timerfd_create.2.html) /// On systems using kqueue, a file descriptor is not needed, so it is set to 0. #[derive(Debug)] pub struct Timer { #[doc(hidden)] pub fd: RawFd, #[doc(hidden)] pub interval: bool } impl Timer { /// Re-arm a recurring timer. /// /// This method must be called when an interval timer notification is received. If not called, /// the next timer notification will not be received. /// /// The pattern is to store the timers in a hashmap keyed by their IDs. When a timer id is received, /// and the timer looked up the user should call arm(). /// /// This method doesn't actually change the timing of the recurring timer. An interval timer /// will fire exactly at the interval specified originally. This just allows the kernel poller /// to received the timer event and send a notification. On epoll based systems if a timer has /// already fired because the timer period has elapsed, the kernel poller will be woken up /// immediately after this call and a notification will be sent. This should not be a problem in /// practice as timers should be re-armed before the next timer fires. Otherwise the timer /// interval is too short to be useful. /// /// On Linux timers are file descriptors registered with epoll. Since we use edge triggering we /// need to read the file descriptors to change their state. Note that even if we used level /// triggering we'd still need to do this, but for a different reason. The timer would fire /// indefinitely as ready in the level triggered case, rather than never firing again as in the /// edge triggered case. /// pub fn arm(&self) -> Result<()> { let buf: u64 = 0; unsafe { let ptr: *mut libc::c_void = mem::transmute(&buf); if libc::read(self.fd, ptr, 8) < 0 { return Err(Error::last_os_error()); } Ok(()) } } } impl Drop for Timer { fn drop(&mut self) { unsafe { libc::close(self.fd); } } } impl AsRawFd for Timer { fn as_raw_fd(&self) -> RawFd { self.fd } }