From 9918693037dce8aa4bb6f08741b6812923486c18 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 11:26:03 +0200 Subject: Merging upstream version 1.76.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/nix/src/sys/timerfd.rs | 222 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 vendor/nix/src/sys/timerfd.rs (limited to 'vendor/nix/src/sys/timerfd.rs') diff --git a/vendor/nix/src/sys/timerfd.rs b/vendor/nix/src/sys/timerfd.rs new file mode 100644 index 000000000..c4337c9df --- /dev/null +++ b/vendor/nix/src/sys/timerfd.rs @@ -0,0 +1,222 @@ +//! Timer API via file descriptors. +//! +//! Timer FD is a Linux-only API to create timers and get expiration +//! notifications through file descriptors. +//! +//! For more documentation, please read [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). +//! +//! # Examples +//! +//! Create a new one-shot timer that expires after 1 second. +//! ``` +//! # use std::os::unix::io::AsRawFd; +//! # use nix::sys::timerfd::{TimerFd, ClockId, TimerFlags, TimerSetTimeFlags, +//! # Expiration}; +//! # use nix::sys::time::{TimeSpec, TimeValLike}; +//! # use nix::unistd::read; +//! # +//! // We create a new monotonic timer. +//! let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()) +//! .unwrap(); +//! +//! // We set a new one-shot timer in 1 seconds. +//! timer.set( +//! Expiration::OneShot(TimeSpec::seconds(1)), +//! TimerSetTimeFlags::empty() +//! ).unwrap(); +//! +//! // We wait for the timer to expire. +//! timer.wait().unwrap(); +//! ``` +use crate::sys::time::timer::TimerSpec; +pub use crate::sys::time::timer::{Expiration, TimerSetTimeFlags}; +use crate::unistd::read; +use crate::{errno::Errno, Result}; +use libc::c_int; +use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd}; + +/// A timerfd instance. This is also a file descriptor, you can feed it to +/// other interfaces taking file descriptors as arguments, [`epoll`] for example. +/// +/// [`epoll`]: crate::sys::epoll +#[derive(Debug)] +pub struct TimerFd { + fd: OwnedFd, +} + +impl AsFd for TimerFd { + fn as_fd(&self) -> BorrowedFd<'_> { + self.fd.as_fd() + } +} + +impl FromRawFd for TimerFd { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + TimerFd { + fd: OwnedFd::from_raw_fd(fd), + } + } +} + +libc_enum! { + /// The type of the clock used to mark the progress of the timer. For more + /// details on each kind of clock, please refer to [timerfd_create(2)](https://man7.org/linux/man-pages/man2/timerfd_create.2.html). + #[repr(i32)] + #[non_exhaustive] + pub enum ClockId { + /// A settable system-wide real-time clock. + CLOCK_REALTIME, + /// A non-settable monotonically increasing clock. + /// + /// Does not change after system startup. + /// Does not measure time while the system is suspended. + CLOCK_MONOTONIC, + /// Like `CLOCK_MONOTONIC`, except that `CLOCK_BOOTTIME` includes the time + /// that the system was suspended. + CLOCK_BOOTTIME, + /// Like `CLOCK_REALTIME`, but will wake the system if it is suspended. + CLOCK_REALTIME_ALARM, + /// Like `CLOCK_BOOTTIME`, but will wake the system if it is suspended. + CLOCK_BOOTTIME_ALARM, + } +} + +libc_bitflags! { + /// Additional flags to change the behaviour of the file descriptor at the + /// time of creation. + pub struct TimerFlags: c_int { + /// Set the `O_NONBLOCK` flag on the open file description referred to by the new file descriptor. + TFD_NONBLOCK; + /// Set the `FD_CLOEXEC` flag on the file descriptor. + TFD_CLOEXEC; + } +} + +impl TimerFd { + /// Creates a new timer based on the clock defined by `clockid`. The + /// underlying fd can be assigned specific flags with `flags` (CLOEXEC, + /// NONBLOCK). The underlying fd will be closed on drop. + #[doc(alias("timerfd_create"))] + pub fn new(clockid: ClockId, flags: TimerFlags) -> Result { + Errno::result(unsafe { + libc::timerfd_create(clockid as i32, flags.bits()) + }) + .map(|fd| Self { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + }) + } + + /// Sets 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. + /// + /// # Cancel on a clock change + /// + /// If you set a `TFD_TIMER_CANCEL_ON_SET` alongside `TFD_TIMER_ABSTIME` + /// and the clock for this timer is `CLOCK_REALTIME` or `CLOCK_REALTIME_ALARM`, + /// then this timer is marked as cancelable if the real-time clock undergoes + /// a discontinuous change. + /// + /// # 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 disables the alarm + /// altogether. + #[doc(alias("timerfd_settime"))] + pub fn set( + &self, + expiration: Expiration, + flags: TimerSetTimeFlags, + ) -> Result<()> { + let timerspec: TimerSpec = expiration.into(); + Errno::result(unsafe { + libc::timerfd_settime( + self.fd.as_fd().as_raw_fd(), + flags.bits(), + timerspec.as_ref(), + std::ptr::null_mut(), + ) + }) + .map(drop) + } + + /// Get the parameters for the alarm currently set, if any. + #[doc(alias("timerfd_gettime"))] + pub fn get(&self) -> Result> { + let mut timerspec = TimerSpec::none(); + Errno::result(unsafe { + libc::timerfd_gettime( + self.fd.as_fd().as_raw_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 { + Some(timerspec.into()) + } + }) + } + + /// Remove the alarm if any is set. + #[doc(alias("timerfd_settime"))] + pub fn unset(&self) -> Result<()> { + Errno::result(unsafe { + libc::timerfd_settime( + self.fd.as_fd().as_raw_fd(), + TimerSetTimeFlags::empty().bits(), + TimerSpec::none().as_ref(), + std::ptr::null_mut(), + ) + }) + .map(drop) + } + + /// Wait for the configured alarm to expire. + /// + /// Note: If the alarm is unset, then you will wait forever. + pub fn wait(&self) -> Result<()> { + while let Err(e) = read(self.fd.as_fd().as_raw_fd(), &mut [0u8; 8]) { + if e == Errno::ECANCELED { + break; + } + if e != Errno::EINTR { + return Err(e); + } + } + + Ok(()) + } +} -- cgit v1.2.3