base/sys/linux/
timer.rs

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