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 { as_raw_fd(&self) -> RawFd32 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`. new() -> Result<Timer>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`. set_time(&mut self, dur: Option<Duration>, interval: Option<Duration>) -> Result<()>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 { reset_oneshot(&mut self, dur: Duration) -> Result<()>79 fn reset_oneshot(&mut self, dur: Duration) -> Result<()> { 80 self.set_time(Some(dur), None) 81 } 82 reset_repeating(&mut self, dur: Duration) -> Result<()>83 fn reset_repeating(&mut self, dur: Duration) -> Result<()> { 84 self.set_time(Some(dur), Some(dur)) 85 } 86 clear(&mut self) -> Result<()>87 fn clear(&mut self) -> Result<()> { 88 self.set_time(None, None) 89 } 90 wait(&mut self) -> Result<()>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 mark_waited(&mut self) -> Result<bool>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 resolution(&self) -> Result<Duration>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