blob: 1765a7f443f6d2cf79fb7a3157eaa8ed8423b026 [file] [edit]
// Copyright 2018 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::mem;
use std::os::unix::io::AsRawFd;
use std::os::unix::io::RawFd;
use std::ptr;
use std::time::Duration;
use libc::clock_getres;
use libc::timerfd_create;
use libc::timerfd_settime;
use libc::CLOCK_MONOTONIC;
use libc::EAGAIN;
use libc::POLLIN;
use libc::TFD_CLOEXEC;
use super::super::errno_result;
use super::super::Error;
use super::super::Result;
use crate::descriptor::AsRawDescriptor;
use crate::descriptor::FromRawDescriptor;
use crate::descriptor::SafeDescriptor;
use crate::handle_eintr_errno;
use crate::timer::Timer;
use crate::timer::TimerTrait;
use crate::unix::duration_to_timespec;
impl AsRawFd for Timer {
fn as_raw_fd(&self) -> RawFd {
self.handle.as_raw_descriptor()
}
}
impl Timer {
/// Creates a new timerfd. The timer is initally disarmed and must be armed by calling
/// `reset`.
pub fn new() -> Result<Timer> {
// SAFETY:
// Safe because this doesn't modify any memory and we check the return value.
let ret = unsafe { timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC) };
if ret < 0 {
return errno_result();
}
Ok(Timer {
// SAFETY:
// Safe because we uniquely own the file descriptor.
handle: unsafe { SafeDescriptor::from_raw_descriptor(ret) },
interval: None,
})
}
// Calls `timerfd_settime()` and stores the new value of `interval`.
fn set_time(&mut self, dur: Option<Duration>, interval: Option<Duration>) -> Result<()> {
// The posix implementation of timer does not need self.interval, but we
// save it anyways to keep a consistent interface.
self.interval = interval;
let spec = libc::itimerspec {
it_interval: duration_to_timespec(interval.unwrap_or_default()),
it_value: duration_to_timespec(dur.unwrap_or_default()),
};
// SAFETY:
// Safe because this doesn't modify any memory and we check the return value.
let ret = unsafe { timerfd_settime(self.as_raw_descriptor(), 0, &spec, ptr::null_mut()) };
if ret < 0 {
return errno_result();
}
Ok(())
}
}
impl TimerTrait for Timer {
fn reset_oneshot(&mut self, dur: Duration) -> Result<()> {
self.set_time(Some(dur), None)
}
fn reset_repeating(&mut self, dur: Duration) -> Result<()> {
self.set_time(Some(dur), Some(dur))
}
fn clear(&mut self) -> Result<()> {
self.set_time(None, None)
}
fn wait(&mut self) -> Result<()> {
let mut pfd = libc::pollfd {
fd: self.as_raw_descriptor(),
events: POLLIN,
revents: 0,
};
// SAFETY:
// Safe because this only modifies |pfd| and we check the return value
let ret = handle_eintr_errno!(unsafe {
libc::ppoll(
&mut pfd as *mut libc::pollfd,
1,
ptr::null_mut(),
ptr::null_mut(),
)
});
if ret < 0 {
return errno_result();
}
// EAGAIN is a valid error in the case where another thread has called timerfd_settime
// in between this thread calling ppoll and read. Since the ppoll returned originally
// without any revents it means the timer did expire, so we treat this as a
// WaitResult::Expired.
let _ = self.mark_waited()?;
Ok(())
}
fn mark_waited(&mut self) -> Result<bool> {
let mut count = 0u64;
// SAFETY:
// The timerfd is in non-blocking mode, so this should return immediately.
let ret = unsafe {
libc::read(
self.as_raw_descriptor(),
&mut count as *mut _ as *mut libc::c_void,
mem::size_of_val(&count),
)
};
if ret < 0 {
if Error::last().errno() == EAGAIN {
Ok(true)
} else {
errno_result()
}
} else {
Ok(false)
}
}
fn resolution(&self) -> Result<Duration> {
// SAFETY:
// Safe because we are zero-initializing a struct with only primitive member fields.
let mut res: libc::timespec = unsafe { mem::zeroed() };
// SAFETY:
// Safe because it only modifies a local struct and we check the return value.
let ret = unsafe { clock_getres(CLOCK_MONOTONIC, &mut res) };
if ret != 0 {
return errno_result();
}
Ok(Duration::new(res.tv_sec as u64, res.tv_nsec as u32))
}
}