summaryrefslogtreecommitdiff
path: root/src/sys
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys')
-rw-r--r--src/sys/mod.rs15
-rw-r--r--src/sys/signal.rs5
-rw-r--r--src/sys/socket/addr.rs121
-rw-r--r--src/sys/socket/mod.rs6
-rw-r--r--src/sys/time.rs123
-rw-r--r--src/sys/timer.rs175
-rw-r--r--src/sys/timerfd.rs111
7 files changed, 423 insertions, 133 deletions
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index 16ba9e0a..654a4d87 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -201,3 +201,18 @@ feature! {
#[allow(missing_docs)]
pub mod timerfd;
}
+
+#[cfg(all(
+ any(
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "netbsd"
+ ),
+ feature = "time",
+ feature = "signal"
+))]
+feature! {
+ #![feature = "time"]
+ pub mod timer;
+}
diff --git a/src/sys/signal.rs b/src/sys/signal.rs
index b655604d..9750d890 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -1085,6 +1085,11 @@ mod sigevent {
pub fn sigevent(&self) -> libc::sigevent {
self.sigevent
}
+
+ /// Returns a mutable pointer to the `sigevent` wrapped by `self`
+ pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
+ &mut self.sigevent
+ }
}
impl<'a> From<&'a libc::sigevent> for SigEvent {
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index f06a80d3..67e5d6c6 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -1,8 +1,10 @@
use super::sa_family_t;
+use cfg_if::cfg_if;
use crate::{Result, NixPath};
use crate::errno::Errno;
use memoffset::offset_of;
use std::{fmt, mem, net, ptr, slice};
+use std::convert::TryInto;
use std::ffi::OsStr;
use std::hash::{Hash, Hasher};
use std::path::Path;
@@ -575,9 +577,17 @@ impl fmt::Display for Ipv6Addr {
/// A wrapper around `sockaddr_un`.
#[derive(Clone, Copy, Debug)]
pub struct UnixAddr {
- // INVARIANT: sun & path_len are valid as defined by docs for from_raw_parts
+ // INVARIANT: sun & sun_len are valid as defined by docs for from_raw_parts
sun: libc::sockaddr_un,
- path_len: usize,
+ /// The length of the valid part of `sun`, including the sun_family field
+ /// but excluding any trailing nul.
+ // On the BSDs, this field is built into sun
+ #[cfg(any(target_os = "android",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux"
+ ))]
+ sun_len: u8
}
// linux man page unix(7) says there are 3 kinds of unix socket:
@@ -594,8 +604,10 @@ enum UnixAddrKind<'a> {
Abstract(&'a [u8]),
}
impl<'a> UnixAddrKind<'a> {
- /// Safety: sun & path_len must be valid
- unsafe fn get(sun: &'a libc::sockaddr_un, path_len: usize) -> Self {
+ /// Safety: sun & sun_len must be valid
+ unsafe fn get(sun: &'a libc::sockaddr_un, sun_len: u8) -> Self {
+ assert!(sun_len as usize >= offset_of!(libc::sockaddr_un, sun_path));
+ let path_len = sun_len as usize - offset_of!(libc::sockaddr_un, sun_path);
if path_len == 0 {
return Self::Unnamed;
}
@@ -605,8 +617,19 @@ impl<'a> UnixAddrKind<'a> {
slice::from_raw_parts(sun.sun_path.as_ptr().add(1) as *const u8, path_len - 1);
return Self::Abstract(name);
}
- let pathname = slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len - 1);
- Self::Pathname(Path::new(OsStr::from_bytes(pathname)))
+ let pathname = slice::from_raw_parts(sun.sun_path.as_ptr() as *const u8, path_len);
+ if pathname.last() == Some(&0) {
+ // A trailing NUL is not considered part of the path, and it does
+ // not need to be included in the addrlen passed to functions like
+ // bind(). However, Linux adds a trailing NUL, even if one was not
+ // originally present, when returning addrs from functions like
+ // getsockname() (the BSDs do not do that). So we need to filter
+ // out any trailing NUL here, so sockaddrs can round-trip through
+ // the kernel and still compare equal.
+ Self::Pathname(Path::new(OsStr::from_bytes(&pathname[0..pathname.len() - 1])))
+ } else {
+ Self::Pathname(Path::new(OsStr::from_bytes(pathname)))
+ }
}
}
@@ -626,19 +649,32 @@ impl UnixAddr {
return Err(Errno::ENAMETOOLONG);
}
+ let sun_len = (bytes.len() +
+ offset_of!(libc::sockaddr_un, sun_path)).try_into()
+ .unwrap();
+
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ {
+ ret.sun_len = sun_len;
+ }
ptr::copy_nonoverlapping(bytes.as_ptr(),
ret.sun_path.as_mut_ptr() as *mut u8,
bytes.len());
- Ok(UnixAddr::from_raw_parts(ret, bytes.len() + 1))
+ Ok(UnixAddr::from_raw_parts(ret, sun_len))
}
})?
}
/// Create a new `sockaddr_un` representing an address in the "abstract namespace".
///
- /// The leading null byte for the abstract namespace is automatically added;
- /// thus the input `path` is expected to be the bare name, not null-prefixed.
+ /// The leading nul byte for the abstract namespace is automatically added;
+ /// thus the input `path` is expected to be the bare name, not NUL-prefixed.
/// This is a Linux-specific extension, primarily used to allow chrooted
/// processes to communicate with processes having a different filesystem view.
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -653,6 +689,10 @@ impl UnixAddr {
if path.len() >= ret.sun_path.len() {
return Err(Errno::ENAMETOOLONG);
}
+ let sun_len = (path.len() +
+ 1 +
+ offset_of!(libc::sockaddr_un, sun_path)).try_into()
+ .unwrap();
// Abstract addresses are represented by sun_path[0] ==
// b'\0', so copy starting one byte in.
@@ -660,32 +700,40 @@ impl UnixAddr {
ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
path.len());
- Ok(UnixAddr::from_raw_parts(ret, path.len() + 1))
+ Ok(UnixAddr::from_raw_parts(ret, sun_len))
}
}
- /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `path_len` is the "addrlen"
- /// of this address, but minus `offsetof(struct sockaddr_un, sun_path)`. Basically the length
- /// of the data in `sun_path`.
+ /// Create a UnixAddr from a raw `sockaddr_un` struct and a size. `sun_len`
+ /// is the size of the valid portion of the struct, excluding any trailing
+ /// NUL.
///
/// # Safety
- /// This pair of sockaddr_un & path_len must be a valid unix addr, which means:
- /// - path_len <= sockaddr_un.sun_path.len()
- /// - if this is a unix addr with a pathname, sun.sun_path is a nul-terminated fs path and
- /// sun.sun_path[path_len - 1] == 0 || sun.sun_path[path_len] == 0
- pub(crate) unsafe fn from_raw_parts(sun: libc::sockaddr_un, mut path_len: usize) -> UnixAddr {
- if let UnixAddrKind::Pathname(_) = UnixAddrKind::get(&sun, path_len) {
- if sun.sun_path[path_len - 1] != 0 {
- assert_eq!(sun.sun_path[path_len], 0);
- path_len += 1
+ /// This pair of sockaddr_un & sun_len must be a valid unix addr, which
+ /// means:
+ /// - sun_len >= offset_of(sockaddr_un, sun_path)
+ /// - sun_len <= sockaddr_un.sun_path.len() - offset_of(sockaddr_un, sun_path)
+ /// - if this is a unix addr with a pathname, sun.sun_path is a
+ /// fs path, not necessarily nul-terminated.
+ pub(crate) unsafe fn from_raw_parts(sun: libc::sockaddr_un, sun_len: u8) -> UnixAddr {
+ cfg_if!{
+ if #[cfg(any(target_os = "android",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux"
+ ))]
+ {
+ UnixAddr { sun, sun_len }
+ } else {
+ assert_eq!(sun_len, sun.sun_len);
+ UnixAddr {sun}
}
}
- UnixAddr { sun, path_len }
}
fn kind(&self) -> UnixAddrKind<'_> {
// SAFETY: our sockaddr is always valid because of the invariant on the struct
- unsafe { UnixAddrKind::get(&self.sun, self.path_len) }
+ unsafe { UnixAddrKind::get(&self.sun, self.sun_len()) }
}
/// If this address represents a filesystem path, return that path.
@@ -699,7 +747,7 @@ impl UnixAddr {
/// If this address represents an abstract socket, return its name.
///
/// For abstract sockets only the bare name is returned, without the
- /// leading null byte. `None` is returned for unnamed or path-backed sockets.
+ /// leading NUL byte. `None` is returned for unnamed or path-backed sockets.
#[cfg(any(target_os = "android", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all())))]
pub fn as_abstract(&self) -> Option<&[u8]> {
@@ -712,7 +760,7 @@ impl UnixAddr {
/// Returns the addrlen of this socket - `offsetof(struct sockaddr_un, sun_path)`
#[inline]
pub fn path_len(&self) -> usize {
- self.path_len
+ self.sun_len() as usize - offset_of!(libc::sockaddr_un, sun_path)
}
/// Returns a pointer to the raw `sockaddr_un` struct
#[inline]
@@ -724,6 +772,21 @@ impl UnixAddr {
pub fn as_mut_ptr(&mut self) -> *mut libc::sockaddr_un {
&mut self.sun
}
+
+ fn sun_len(&self)-> u8 {
+ cfg_if!{
+ if #[cfg(any(target_os = "android",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux"
+ ))]
+ {
+ self.sun_len
+ } else {
+ self.sun.sun_len
+ }
+ }
+ }
}
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -957,12 +1020,12 @@ impl SockAddr {
},
mem::size_of_val(addr) as libc::socklen_t
),
- SockAddr::Unix(UnixAddr { ref sun, path_len }) => (
+ SockAddr::Unix(ref unix_addr) => (
// This cast is always allowed in C
unsafe {
- &*(sun as *const libc::sockaddr_un as *const libc::sockaddr)
+ &*(&unix_addr.sun as *const libc::sockaddr_un as *const libc::sockaddr)
},
- (path_len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t
+ unix_addr.sun_len() as libc::socklen_t
),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(NetlinkAddr(ref sa)) => (
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index f6d37c99..42a032c9 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -5,7 +5,7 @@ use cfg_if::cfg_if;
use crate::{Result, errno::Errno};
use libc::{self, c_void, c_int, iovec, socklen_t, size_t,
CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN};
-use memoffset::offset_of;
+use std::convert::TryInto;
use std::{mem, ptr, slice};
use std::os::unix::io::RawFd;
#[cfg(target_os = "linux")]
@@ -2007,10 +2007,10 @@ pub fn sockaddr_storage_to_addr(
Ok(SockAddr::Inet(InetAddr::V6(sin6)))
}
libc::AF_UNIX => {
- let pathlen = len - offset_of!(sockaddr_un, sun_path);
unsafe {
let sun = *(addr as *const _ as *const sockaddr_un);
- Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, pathlen)))
+ let sun_len = len.try_into().unwrap();
+ Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len)))
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
diff --git a/src/sys/time.rs b/src/sys/time.rs
index ac424718..1e62b76a 100644
--- a/src/sys/time.rs
+++ b/src/sys/time.rs
@@ -5,6 +5,129 @@ use libc::{timespec, timeval};
#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
pub use libc::{time_t, suseconds_t};
+#[cfg(any(
+ all(feature = "time", any(target_os = "android", target_os = "linux")),
+ all(
+ any(
+ target_os = "freebsd",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "netbsd"
+ ),
+ feature = "time",
+ feature = "signal"
+ )
+))]
+pub(crate) mod timer {
+ use crate::sys::time::TimeSpec;
+ use bitflags::bitflags;
+
+ #[derive(Debug, Clone, Copy)]
+ pub(crate) struct TimerSpec(libc::itimerspec);
+
+ impl TimerSpec {
+ pub const fn none() -> Self {
+ Self(libc::itimerspec {
+ it_interval: libc::timespec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ },
+ it_value: libc::timespec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ },
+ })
+ }
+ }
+
+ impl AsMut<libc::itimerspec> for TimerSpec {
+ fn as_mut(&mut self) -> &mut libc::itimerspec {
+ &mut self.0
+ }
+ }
+
+ impl AsRef<libc::itimerspec> for TimerSpec {
+ fn as_ref(&self) -> &libc::itimerspec {
+ &self.0
+ }
+ }
+
+ impl From<Expiration> for TimerSpec {
+ fn from(expiration: Expiration) -> TimerSpec {
+ match expiration {
+ Expiration::OneShot(t) => TimerSpec(libc::itimerspec {
+ it_interval: libc::timespec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ },
+ it_value: *t.as_ref(),
+ }),
+ Expiration::IntervalDelayed(start, interval) => TimerSpec(libc::itimerspec {
+ it_interval: *interval.as_ref(),
+ it_value: *start.as_ref(),
+ }),
+ Expiration::Interval(t) => TimerSpec(libc::itimerspec {
+ it_interval: *t.as_ref(),
+ it_value: *t.as_ref(),
+ }),
+ }
+ }
+ }
+
+ /// An enumeration allowing the definition of the expiration time of an alarm,
+ /// recurring or not.
+ #[derive(Debug, Clone, Copy, PartialEq)]
+ pub enum Expiration {
+ /// Alarm will trigger once after the time given in `TimeSpec`
+ OneShot(TimeSpec),
+ /// Alarm will trigger after a specified delay and then every interval of
+ /// time.
+ IntervalDelayed(TimeSpec, TimeSpec),
+ /// Alarm will trigger every specified interval of time.
+ Interval(TimeSpec),
+ }
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ bitflags! {
+ /// Flags that are used for arming the timer.
+ pub struct TimerSetTimeFlags: libc::c_int {
+ const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
+ }
+ }
+ #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly", target_os = "illumos"))]
+ bitflags! {
+ /// Flags that are used for arming the timer.
+ pub struct TimerSetTimeFlags: libc::c_int {
+ const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME;
+ }
+ }
+
+ impl From<TimerSpec> for Expiration {
+ fn from(timerspec: TimerSpec) -> Expiration {
+ match timerspec {
+ TimerSpec(libc::itimerspec {
+ it_interval:
+ libc::timespec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ },
+ it_value: ts,
+ }) => Expiration::OneShot(ts.into()),
+ TimerSpec(libc::itimerspec {
+ it_interval: int_ts,
+ it_value: val_ts,
+ }) => {
+ if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) {
+ Expiration::Interval(int_ts.into())
+ } else {
+ Expiration::IntervalDelayed(val_ts.into(), int_ts.into())
+ }
+ }
+ }
+ }
+ }
+}
+
pub trait TimeValLike: Sized {
#[inline]
fn zero() -> Self {
diff --git a/src/sys/timer.rs b/src/sys/timer.rs
new file mode 100644
index 00000000..349346bb
--- /dev/null
+++ b/src/sys/timer.rs
@@ -0,0 +1,175 @@
+//! Timer API via signals.
+//!
+//! Timer is a POSIX API to create timers and get expiration notifications
+//! through queued Unix signals, for the current process. This is similar to
+//! Linux's timerfd mechanism, except that API is specific to Linux and makes
+//! use of file polling.
+//!
+//! For more documentation, please read [timer_create](https://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_create.html).
+//!
+//! # Examples
+//!
+//! Create an interval timer that signals SIGALARM every 250 milliseconds.
+//!
+//! ```no_run
+//! use nix::sys::signal::{self, SigEvent, SigHandler, SigevNotify, Signal};
+//! use nix::sys::timer::{Expiration, Timer, TimerSetTimeFlags};
+//! use nix::time::ClockId;
+//! use std::convert::TryFrom;
+//! use std::sync::atomic::{AtomicU64, Ordering};
+//! use std::thread::yield_now;
+//! use std::time::Duration;
+//!
+//! const SIG: Signal = Signal::SIGALRM;
+//! static ALARMS: AtomicU64 = AtomicU64::new(0);
+//!
+//! extern "C" fn handle_alarm(signal: libc::c_int) {
+//! let signal = Signal::try_from(signal).unwrap();
+//! if signal == SIG {
+//! ALARMS.fetch_add(1, Ordering::Relaxed);
+//! }
+//! }
+//!
+//! fn main() {
+//! let clockid = ClockId::CLOCK_MONOTONIC;
+//! let sigevent = SigEvent::new(SigevNotify::SigevSignal {
+//! signal: SIG,
+//! si_value: 0,
+//! });
+//!
+//! let mut timer = Timer::new(clockid, sigevent).unwrap();
+//! let expiration = Expiration::Interval(Duration::from_millis(250).into());
+//! let flags = TimerSetTimeFlags::empty();
+//! timer.set(expiration, flags).expect("could not set timer");
+//!
+//! let handler = SigHandler::Handler(handle_alarm);
+//! unsafe { signal::signal(SIG, handler) }.unwrap();
+//!
+//! loop {
+//! let alarms = ALARMS.load(Ordering::Relaxed);
+//! if alarms >= 10 {
+//! println!("total alarms handled: {}", alarms);
+//! break;
+//! }
+//! yield_now()
+//! }
+//! }
+//! ```
+use crate::sys::signal::SigEvent;
+use crate::sys::time::timer::TimerSpec;
+pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags};
+use crate::time::ClockId;
+use crate::{errno::Errno, Result};
+use core::mem;
+
+/// A Unix signal per-process timer.
+#[derive(Debug)]
+#[repr(transparent)]
+pub struct Timer(libc::timer_t);
+
+impl Timer {
+ /// Creates a new timer based on the clock defined by `clockid`. The details
+ /// of the signal and its handler are defined by the passed `sigevent`.
+ pub fn new(clockid: ClockId, mut sigevent: SigEvent) -> Result<Self> {
+ let mut timer_id: mem::MaybeUninit<libc::timer_t> = mem::MaybeUninit::uninit();
+ Errno::result(unsafe {
+ libc::timer_create(
+ clockid.as_raw(),
+ sigevent.as_mut_ptr(),
+ timer_id.as_mut_ptr(),
+ )
+ })
+ .map(|_| {
+ // SAFETY: libc::timer_create is responsible for initializing
+ // timer_id.
+ unsafe { Self(timer_id.assume_init()) }
+ })
+ }
+
+ /// Set a new alarm on the timer.
+ ///
+ /// # Types of alarm
+ ///
+ /// There are 3 types of alarms you can set:
+ ///
+ /// - one shot: the alarm will trigger once after the specified amount of
+ /// time.
+ /// Example: I want an alarm to go off in 60s and then disable itself.
+ ///
+ /// - interval: the alarm will trigger every specified interval of time.
+ /// Example: I want an alarm to go off every 60s. The alarm will first
+ /// go off 60s after I set it and every 60s after that. The alarm will
+ /// not disable itself.
+ ///
+ /// - interval delayed: the alarm will trigger after a certain amount of
+ /// time and then trigger at a specified interval.
+ /// Example: I want an alarm to go off every 60s but only start in 1h.
+ /// The alarm will first trigger 1h after I set it and then every 60s
+ /// after that. The alarm will not disable itself.
+ ///
+ /// # Relative vs absolute alarm
+ ///
+ /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass
+ /// to the `Expiration` you want is relative. If however you want an alarm
+ /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`.
+ /// Then the one shot TimeSpec and the delay TimeSpec of the delayed
+ /// interval are going to be interpreted as absolute.
+ ///
+ /// # Disabling alarms
+ ///
+ /// Note: Only one alarm can be set for any given timer. Setting a new alarm
+ /// actually removes the previous one.
+ ///
+ /// Note: Setting a one shot alarm with a 0s TimeSpec disable the alarm
+ /// altogether.
+ pub fn set(&mut self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> {
+ let timerspec: TimerSpec = expiration.into();
+ Errno::result(unsafe {
+ libc::timer_settime(
+ self.0,
+ flags.bits(),
+ timerspec.as_ref(),
+ core::ptr::null_mut(),
+ )
+ })
+ .map(drop)
+ }
+
+ /// Get the parameters for the alarm currently set, if any.
+ pub fn get(&self) -> Result<Option<Expiration>> {
+ let mut timerspec = TimerSpec::none();
+ Errno::result(unsafe { libc::timer_gettime(self.0, timerspec.as_mut()) }).map(|_| {
+ if timerspec.as_ref().it_interval.tv_sec == 0
+ && timerspec.as_ref().it_interval.tv_nsec == 0
+ && timerspec.as_ref().it_value.tv_sec == 0
+ && timerspec.as_ref().it_value.tv_nsec == 0
+ {
+ None
+ } else {
+ Some(timerspec.into())
+ }
+ })
+ }
+
+ /// Return the number of timers that have overrun
+ ///
+ /// Each timer is able to queue one signal to the process at a time, meaning
+ /// if the signal is not handled before the next expiration the timer has
+ /// 'overrun'. This function returns how many times that has happened to
+ /// this timer, up to `libc::DELAYTIMER_MAX`. If more than the maximum
+ /// number of overruns have happened the return is capped to the maximum.
+ pub fn overruns(&self) -> i32 {
+ unsafe { libc::timer_getoverrun(self.0) }
+ }
+}
+
+impl Drop for Timer {
+ fn drop(&mut self) {
+ if !std::thread::panicking() {
+ let result = Errno::result(unsafe { libc::timer_delete(self.0) });
+ if let Err(Errno::EINVAL) = result {
+ panic!("close of Timer encountered EINVAL");
+ }
+ }
+ }
+}
diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs
index 705a3c4d..bc5a75d4 100644
--- a/src/sys/timerfd.rs
+++ b/src/sys/timerfd.rs
@@ -28,10 +28,10 @@
//! // We wait for the timer to expire.
//! timer.wait().unwrap();
//! ```
-use crate::sys::time::TimeSpec;
+use crate::sys::time::timer::TimerSpec;
+pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags};
use crate::unistd::read;
use crate::{errno::Errno, Result};
-use bitflags::bitflags;
use libc::c_int;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
@@ -77,93 +77,6 @@ libc_bitflags! {
}
}
-bitflags! {
- /// Flags that are used for arming the timer.
- pub struct TimerSetTimeFlags: libc::c_int {
- const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-struct TimerSpec(libc::itimerspec);
-
-impl TimerSpec {
- pub const fn none() -> Self {
- Self(libc::itimerspec {
- it_interval: libc::timespec {
- tv_sec: 0,
- tv_nsec: 0,
- },
- it_value: libc::timespec {
- tv_sec: 0,
- tv_nsec: 0,
- },
- })
- }
-}
-
-impl AsRef<libc::itimerspec> for TimerSpec {
- fn as_ref(&self) -> &libc::itimerspec {
- &self.0
- }
-}
-
-impl From<Expiration> for TimerSpec {
- fn from(expiration: Expiration) -> TimerSpec {
- match expiration {
- Expiration::OneShot(t) => TimerSpec(libc::itimerspec {
- it_interval: libc::timespec {
- tv_sec: 0,
- tv_nsec: 0,
- },
- it_value: *t.as_ref(),
- }),
- Expiration::IntervalDelayed(start, interval) => TimerSpec(libc::itimerspec {
- it_interval: *interval.as_ref(),
- it_value: *start.as_ref(),
- }),
- Expiration::Interval(t) => TimerSpec(libc::itimerspec {
- it_interval: *t.as_ref(),
- it_value: *t.as_ref(),
- }),
- }
- }
-}
-
-impl From<TimerSpec> for Expiration {
- fn from(timerspec: TimerSpec) -> Expiration {
- match timerspec {
- TimerSpec(libc::itimerspec {
- it_interval:
- libc::timespec {
- tv_sec: 0,
- tv_nsec: 0,
- },
- it_value: ts,
- }) => Expiration::OneShot(ts.into()),
- TimerSpec(libc::itimerspec {
- it_interval: int_ts,
- it_value: val_ts,
- }) => {
- if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) {
- Expiration::Interval(int_ts.into())
- } else {
- Expiration::IntervalDelayed(val_ts.into(), int_ts.into())
- }
- }
- }
- }
-}
-
-/// An enumeration allowing the definition of the expiration time of an alarm,
-/// recurring or not.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Expiration {
- OneShot(TimeSpec),
- IntervalDelayed(TimeSpec, TimeSpec),
- Interval(TimeSpec),
-}
-
impl TimerFd {
/// Creates a new timer based on the clock defined by `clockid`. The
/// underlying fd can be assigned specific flags with `flags` (CLOEXEC,
@@ -181,7 +94,7 @@ impl TimerFd {
///
/// - one shot: the alarm will trigger once after the specified amount of
/// time.
- /// Example: I want an alarm to go off in 60s and then disables itself.
+ /// Example: I want an alarm to go off in 60s and then disable itself.
///
/// - interval: the alarm will trigger every specified interval of time.
/// Example: I want an alarm to go off every 60s. The alarm will first
@@ -225,13 +138,11 @@ impl TimerFd {
/// Get the parameters for the alarm currently set, if any.
pub fn get(&self) -> Result<Option<Expiration>> {
let mut timerspec = TimerSpec::none();
- let timerspec_ptr: *mut libc::itimerspec = &mut timerspec.0;
-
- Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec_ptr) }).map(|_| {
- if timerspec.0.it_interval.tv_sec == 0
- && timerspec.0.it_interval.tv_nsec == 0
- && timerspec.0.it_value.tv_sec == 0
- && timerspec.0.it_value.tv_nsec == 0
+ Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec.as_mut()) }).map(|_| {
+ if timerspec.as_ref().it_interval.tv_sec == 0
+ && timerspec.as_ref().it_interval.tv_nsec == 0
+ && timerspec.as_ref().it_value.tv_sec == 0
+ && timerspec.as_ref().it_value.tv_nsec == 0
{
None
} else {
@@ -259,7 +170,7 @@ impl TimerFd {
pub fn wait(&self) -> Result<()> {
while let Err(e) = read(self.fd, &mut [0u8; 8]) {
if e != Errno::EINTR {
- return Err(e)
+ return Err(e);
}
}
@@ -270,9 +181,7 @@ impl TimerFd {
impl Drop for TimerFd {
fn drop(&mut self) {
if !std::thread::panicking() {
- let result = Errno::result(unsafe {
- libc::close(self.fd)
- });
+ let result = Errno::result(unsafe { libc::close(self.fd) });
if let Err(Errno::EBADF) = result {
panic!("close of TimerFd encountered EBADF");
}