Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/linux/timer.rs
5394 views
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
use libc::TFD_NONBLOCK;
19
20
use super::super::errno_result;
21
use super::super::Error;
22
use super::super::Result;
23
use crate::descriptor::AsRawDescriptor;
24
use crate::descriptor::FromRawDescriptor;
25
use crate::descriptor::SafeDescriptor;
26
use crate::handle_eintr_errno;
27
use crate::timer::Timer;
28
use crate::timer::TimerTrait;
29
use crate::unix::duration_to_timespec;
30
31
impl AsRawFd for Timer {
32
fn as_raw_fd(&self) -> RawFd {
33
self.handle.as_raw_descriptor()
34
}
35
}
36
37
impl 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
78
impl 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
}
162
163