summaryrefslogtreecommitdiffstats
path: root/vendor/nix/src/sys/timerfd.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /vendor/nix/src/sys/timerfd.rs
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/nix/src/sys/timerfd.rs')
-rw-r--r--vendor/nix/src/sys/timerfd.rs222
1 files changed, 222 insertions, 0 deletions
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<Self> {
+ 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<Option<Expiration>> {
+ 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(())
+ }
+}