1use std::os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
2use std::time::Duration;
3use std::mem;
4use std::io::{self, Read};
5use std::convert::TryInto;
6use std::fmt;
7
8use crate::epoll::{Epoll, Token, Ready, EpollOpt, Source};
9
10use super::fd::FileDesc;
11
12#[derive(Clone, Copy)]
13#[repr(i32)]
14pub enum Clock {
15 Realtime = libc::CLOCK_REALTIME,
16 Monotonic = libc::CLOCK_MONOTONIC,
17 Boottime = libc::CLOCK_BOOTTIME,
18 RealtimeAlarm = libc::CLOCK_REALTIME_ALARM,
19 BoottimeAlarm = libc::CLOCK_BOOTTIME_ALARM
20}
21
22impl Clock {
23 pub fn clock_name(&self) -> &'static str {
24 match self {
25 Clock::Realtime => "CLOCK_REALTIME",
26 Clock::RealtimeAlarm => "CLOCK_REALTIME_ALARM",
27 Clock::Monotonic => "CLOCK_MONOTONIC",
28 Clock::Boottime => "CLOCK_BOOTTIME",
29 Clock::BoottimeAlarm => "CLOCK_BOOTTIME_ALARM",
30 }
31 }
32}
33
34impl fmt::Display for Clock {
35 fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
36 write!(f, "{}", self.clock_name())
37 }
38}
39
40impl fmt::Debug for Clock {
41 fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
42 write!(f, "{} ({})", self.clone() as i32, self.clock_name())
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub enum SetTimeFlags {
48 Default,
52
53 Abstime,
57
58 TimerCancelOnSet,
67}
68
69pub const TFD_CLOEXEC: i32 = libc::TFD_CLOEXEC;
70pub const TFD_NONBLOCK: i32 = libc::TFD_NONBLOCK;
71
72const TFD_TIMER_ABSTIME: i32 = libc::TFD_TIMER_ABSTIME;
73const TFD_TIMER_CANCEL_ON_SET: i32 = 0o0000002;
74
75#[derive(Debug)]
76pub struct TimerFd {
77 inner: FileDesc
78}
79
80#[derive(Debug, Clone)]
81pub struct TimerSpec {
82 pub interval: Duration,
83 pub value: Duration
84}
85
86impl TimerFd {
87 pub fn new() -> io::Result<TimerFd> {
98 let clock = Clock::Realtime;
99 let flags = TFD_CLOEXEC | TFD_NONBLOCK;
100 TimerFd::create(clock, flags)
101 }
102
103 pub fn create(clock: Clock, flags: i32) -> io::Result<TimerFd> {
115 let timerfd = syscall!(timerfd_create(clock as i32, flags))?;
116 Ok(TimerFd {
117 inner: unsafe { FileDesc::new(timerfd) }
118 })
119 }
120
121 pub fn settime(&self, value: TimerSpec, flags: SetTimeFlags) -> io::Result<TimerSpec> {
139 let new_value = libc::itimerspec {
140 it_interval: duration_to_timespec(value.interval),
141 it_value: duration_to_timespec(value.value)
142 };
143
144 let mut old_value: libc::itimerspec = unsafe { mem::zeroed() };
145
146 let flags = match flags {
147 SetTimeFlags::Default => 0,
148 SetTimeFlags::Abstime => TFD_TIMER_ABSTIME,
149 SetTimeFlags::TimerCancelOnSet => TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET,
150 };
151
152 syscall!(timerfd_settime(
153 self.inner.as_raw_fd(),
154 flags,
155 &new_value as *const libc::itimerspec,
156 &mut old_value as *mut libc::itimerspec
157 ))?;
158
159 Ok(TimerSpec {
160 interval: timespec_to_duration(old_value.it_interval),
161 value: timespec_to_duration(old_value.it_value)
162 })
163 }
164
165 pub fn gettime(&self) -> io::Result<TimerSpec> {
185 let mut itimerspec: libc::itimerspec = unsafe { mem::zeroed() };
186
187 syscall!(timerfd_gettime(
188 self.inner.as_raw_fd(),
189 &mut itimerspec as *mut libc::itimerspec
190 ))?;
191
192 Ok(TimerSpec {
193 interval: timespec_to_duration(itimerspec.it_interval),
194 value: timespec_to_duration(itimerspec.it_value)
195 })
196 }
197
198 pub fn read(&self) -> io::Result<u64> {
205 let mut buf = [0u8; 8];
206 (&self.inner).read_exact(&mut buf)?;
207 let temp: u64 = unsafe { mem::transmute(buf) };
208 Ok(temp)
209 }
210}
211
212fn duration_to_timespec(duration: Duration) -> libc::timespec {
213 libc::timespec {
214 tv_sec: duration.as_secs().try_into().unwrap(),
215 tv_nsec: duration.subsec_nanos().try_into().unwrap()
216 }
217}
218
219fn timespec_to_duration(timespec: libc::timespec) -> Duration {
220 Duration::new(timespec.tv_sec as u64, timespec.tv_nsec as u32)
221}
222
223impl FromRawFd for TimerFd {
224 unsafe fn from_raw_fd(fd: RawFd) -> Self {
225 TimerFd {
226 inner: FileDesc::new(fd)
227 }
228 }
229}
230
231impl IntoRawFd for TimerFd {
232 fn into_raw_fd(self) -> RawFd {
233 self.inner.into_raw_fd()
234 }
235}
236
237impl AsRawFd for TimerFd {
238 fn as_raw_fd(&self) -> RawFd {
239 self.inner.as_raw_fd()
240 }
241}
242
243impl Source for TimerFd {
244 fn add(&self, epoll: &Epoll, token: Token, interest: Ready, opts: EpollOpt) -> io::Result<()> {
245 epoll.add(&self.as_raw_fd(), token, interest, opts)
246 }
247
248 fn modify(&self, epoll: &Epoll, token: Token, interest: Ready, opts: EpollOpt) -> io::Result<()> {
249 epoll.modify(&self.as_raw_fd(), token, interest, opts)
250 }
251
252 fn delete(&self, epoll: &Epoll) -> io::Result<()> {
253 epoll.delete(&self.as_raw_fd())
254 }
255}