• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::mem;
6 use std::os::unix::io::AsRawFd;
7 use std::os::unix::io::RawFd;
8 use std::ptr;
9 use std::time::Duration;
10 
11 use libc::clock_getres;
12 use libc::timerfd_create;
13 use libc::timerfd_settime;
14 use libc::CLOCK_MONOTONIC;
15 use libc::EAGAIN;
16 use libc::POLLIN;
17 use libc::TFD_CLOEXEC;
18 
19 use super::super::errno_result;
20 use super::super::Error;
21 use super::super::Result;
22 use crate::descriptor::AsRawDescriptor;
23 use crate::descriptor::FromRawDescriptor;
24 use crate::descriptor::SafeDescriptor;
25 use crate::handle_eintr_errno;
26 use crate::timer::Timer;
27 use crate::timer::TimerTrait;
28 use crate::unix::duration_to_timespec;
29 
30 impl AsRawFd for Timer {
as_raw_fd(&self) -> RawFd31     fn as_raw_fd(&self) -> RawFd {
32         self.handle.as_raw_descriptor()
33     }
34 }
35 
36 impl Timer {
37     /// Creates a new timerfd.  The timer is initally disarmed and must be armed by calling
38     /// `reset`.
new() -> Result<Timer>39     pub fn new() -> Result<Timer> {
40         // SAFETY:
41         // Safe because this doesn't modify any memory and we check the return value.
42         let ret = unsafe { timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC) };
43         if ret < 0 {
44             return errno_result();
45         }
46 
47         Ok(Timer {
48             // SAFETY:
49             // Safe because we uniquely own the file descriptor.
50             handle: unsafe { SafeDescriptor::from_raw_descriptor(ret) },
51             interval: None,
52         })
53     }
54 
55     // Calls `timerfd_settime()` and stores the new value of `interval`.
set_time(&mut self, dur: Option<Duration>, interval: Option<Duration>) -> Result<()>56     fn set_time(&mut self, dur: Option<Duration>, interval: Option<Duration>) -> Result<()> {
57         // The posix implementation of timer does not need self.interval, but we
58         // save it anyways to keep a consistent interface.
59         self.interval = interval;
60 
61         let spec = libc::itimerspec {
62             it_interval: duration_to_timespec(interval.unwrap_or_default()),
63             it_value: duration_to_timespec(dur.unwrap_or_default()),
64         };
65 
66         // SAFETY:
67         // Safe because this doesn't modify any memory and we check the return value.
68         let ret = unsafe { timerfd_settime(self.as_raw_descriptor(), 0, &spec, ptr::null_mut()) };
69         if ret < 0 {
70             return errno_result();
71         }
72 
73         Ok(())
74     }
75 }
76 
77 impl TimerTrait for Timer {
reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()>78     fn reset(&mut self, dur: Duration, interval: Option<Duration>) -> Result<()> {
79         self.set_time(Some(dur), interval)
80     }
81 
clear(&mut self) -> Result<()>82     fn clear(&mut self) -> Result<()> {
83         self.set_time(None, None)
84     }
85 
wait(&mut self) -> Result<()>86     fn wait(&mut self) -> Result<()> {
87         let mut pfd = libc::pollfd {
88             fd: self.as_raw_descriptor(),
89             events: POLLIN,
90             revents: 0,
91         };
92 
93         // SAFETY:
94         // Safe because this only modifies |pfd| and we check the return value
95         let ret = handle_eintr_errno!(unsafe {
96             libc::ppoll(
97                 &mut pfd as *mut libc::pollfd,
98                 1,
99                 ptr::null_mut(),
100                 ptr::null_mut(),
101             )
102         });
103 
104         if ret < 0 {
105             return errno_result();
106         }
107 
108         // EAGAIN is a valid error in the case where another thread has called timerfd_settime
109         // in between this thread calling ppoll and read. Since the ppoll returned originally
110         // without any revents it means the timer did expire, so we treat this as a
111         // WaitResult::Expired.
112         let _ = self.mark_waited()?;
113 
114         Ok(())
115     }
116 
mark_waited(&mut self) -> Result<bool>117     fn mark_waited(&mut self) -> Result<bool> {
118         let mut count = 0u64;
119 
120         // SAFETY:
121         // The timerfd is in non-blocking mode, so this should return immediately.
122         let ret = unsafe {
123             libc::read(
124                 self.as_raw_descriptor(),
125                 &mut count as *mut _ as *mut libc::c_void,
126                 mem::size_of_val(&count),
127             )
128         };
129 
130         if ret < 0 {
131             if Error::last().errno() == EAGAIN {
132                 Ok(true)
133             } else {
134                 errno_result()
135             }
136         } else {
137             Ok(false)
138         }
139     }
140 
resolution(&self) -> Result<Duration>141     fn resolution(&self) -> Result<Duration> {
142         // SAFETY:
143         // Safe because we are zero-initializing a struct with only primitive member fields.
144         let mut res: libc::timespec = unsafe { mem::zeroed() };
145 
146         // SAFETY:
147         // Safe because it only modifies a local struct and we check the return value.
148         let ret = unsafe { clock_getres(CLOCK_MONOTONIC, &mut res) };
149 
150         if ret != 0 {
151             return errno_result();
152         }
153 
154         Ok(Duration::new(res.tv_sec as u64, res.tv_nsec as u32))
155     }
156 }
157