summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/imp/libc/time
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/imp/libc/time')
-rw-r--r--vendor/rustix/src/imp/libc/time/mod.rs3
-rw-r--r--vendor/rustix/src/imp/libc/time/syscalls.rs414
-rw-r--r--vendor/rustix/src/imp/libc/time/types.rs362
3 files changed, 779 insertions, 0 deletions
diff --git a/vendor/rustix/src/imp/libc/time/mod.rs b/vendor/rustix/src/imp/libc/time/mod.rs
new file mode 100644
index 000000000..bff7fd564
--- /dev/null
+++ b/vendor/rustix/src/imp/libc/time/mod.rs
@@ -0,0 +1,3 @@
+#[cfg(not(windows))]
+pub(crate) mod syscalls;
+pub(crate) mod types;
diff --git a/vendor/rustix/src/imp/libc/time/syscalls.rs b/vendor/rustix/src/imp/libc/time/syscalls.rs
new file mode 100644
index 000000000..2bbaf8ff1
--- /dev/null
+++ b/vendor/rustix/src/imp/libc/time/syscalls.rs
@@ -0,0 +1,414 @@
+//! libc syscalls supporting `rustix::time`.
+
+use super::super::c;
+use super::super::conv::ret;
+#[cfg(feature = "time")]
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+use super::super::time::types::LibcItimerspec;
+use super::super::time::types::LibcTimespec;
+use super::types::Timespec;
+#[cfg(not(target_os = "wasi"))]
+use super::types::{ClockId, DynamicClockId};
+use crate::io;
+use core::mem::MaybeUninit;
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(feature = "time")]
+use {
+ super::super::conv::{borrowed_fd, ret_owned_fd},
+ crate::fd::BorrowedFd,
+ crate::io::OwnedFd,
+ crate::time::{Itimerspec, TimerfdClockId, TimerfdFlags, TimerfdTimerFlags},
+};
+
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+weak!(fn __clock_gettime64(c::clockid_t, *mut LibcTimespec) -> c::c_int);
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+weak!(fn __clock_getres64(c::clockid_t, *mut LibcTimespec) -> c::c_int);
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[cfg(feature = "time")]
+weak!(fn __timerfd_gettime64(c::c_int, *mut LibcItimerspec) -> c::c_int);
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[cfg(feature = "time")]
+weak!(fn __timerfd_settime64(c::c_int, c::c_int, *const LibcItimerspec, *mut LibcItimerspec) -> c::c_int);
+
+#[cfg(not(any(target_os = "redox", target_os = "wasi")))]
+#[inline]
+#[must_use]
+pub(crate) fn clock_getres(id: ClockId) -> Timespec {
+ let mut timespec = MaybeUninit::<LibcTimespec>::uninit();
+
+ // 32-bit gnu version: libc has `clock_getres` but it is not y2038 safe by
+ // default.
+ #[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+ ))]
+ unsafe {
+ if let Some(libc_clock_getres) = __clock_getres64.get() {
+ ret(libc_clock_getres(id as c::clockid_t, timespec.as_mut_ptr())).unwrap();
+ timespec.assume_init().into()
+ } else {
+ clock_getres_old(id)
+ }
+ }
+
+ // Main version: libc is y2038 safe and has `clock_getres`.
+ #[cfg(not(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+ )))]
+ unsafe {
+ let _ = c::clock_getres(id as c::clockid_t, timespec.as_mut_ptr());
+ timespec.assume_init()
+ }
+}
+
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[must_use]
+unsafe fn clock_getres_old(id: ClockId) -> Timespec {
+ let mut old_timespec = MaybeUninit::<c::timespec>::uninit();
+ ret(c::clock_getres(
+ id as c::clockid_t,
+ old_timespec.as_mut_ptr(),
+ ))
+ .unwrap();
+ let old_timespec = old_timespec.assume_init();
+ Timespec {
+ tv_sec: old_timespec.tv_sec.into(),
+ tv_nsec: old_timespec.tv_nsec.into(),
+ }
+}
+
+#[cfg(not(target_os = "wasi"))]
+#[inline]
+#[must_use]
+pub(crate) fn clock_gettime(id: ClockId) -> Timespec {
+ let mut timespec = MaybeUninit::<LibcTimespec>::uninit();
+
+ #[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+ ))]
+ unsafe {
+ if let Some(libc_clock_gettime) = __clock_gettime64.get() {
+ ret(libc_clock_gettime(
+ id as c::clockid_t,
+ timespec.as_mut_ptr(),
+ ))
+ .unwrap();
+ timespec.assume_init().into()
+ } else {
+ clock_gettime_old(id)
+ }
+ }
+
+ // Use `unwrap()` here because `clock_getres` can fail if the clock itself
+ // overflows a number of seconds, but if that happens, the monotonic clocks
+ // can't maintain their invariants, or the realtime clocks aren't properly
+ // configured.
+ #[cfg(not(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+ )))]
+ unsafe {
+ ret(c::clock_gettime(id as c::clockid_t, timespec.as_mut_ptr())).unwrap();
+ timespec.assume_init()
+ }
+}
+
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[must_use]
+unsafe fn clock_gettime_old(id: ClockId) -> Timespec {
+ let mut old_timespec = MaybeUninit::<c::timespec>::uninit();
+ ret(c::clock_gettime(
+ id as c::clockid_t,
+ old_timespec.as_mut_ptr(),
+ ))
+ .unwrap();
+ let old_timespec = old_timespec.assume_init();
+ Timespec {
+ tv_sec: old_timespec.tv_sec.into(),
+ tv_nsec: old_timespec.tv_nsec.into(),
+ }
+}
+
+#[cfg(not(target_os = "wasi"))]
+#[inline]
+pub(crate) fn clock_gettime_dynamic(id: DynamicClockId<'_>) -> io::Result<Timespec> {
+ let mut timespec = MaybeUninit::<LibcTimespec>::uninit();
+ unsafe {
+ let id: c::clockid_t = match id {
+ DynamicClockId::Known(id) => id as c::clockid_t,
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ DynamicClockId::Dynamic(fd) => {
+ use crate::fd::AsRawFd;
+ const CLOCKFD: i32 = 3;
+ (!fd.as_raw_fd() << 3) | CLOCKFD
+ }
+
+ #[cfg(not(any(target_os = "android", target_os = "linux")))]
+ DynamicClockId::Dynamic(_fd) => {
+ // Dynamic clocks are not supported on this platform.
+ return Err(io::Errno::INVAL);
+ }
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ DynamicClockId::RealtimeAlarm => c::CLOCK_REALTIME_ALARM,
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ DynamicClockId::Tai => c::CLOCK_TAI,
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ DynamicClockId::Boottime => c::CLOCK_BOOTTIME,
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ DynamicClockId::BoottimeAlarm => c::CLOCK_BOOTTIME_ALARM,
+ };
+
+ #[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+ ))]
+ {
+ if let Some(libc_clock_gettime) = __clock_gettime64.get() {
+ ret(libc_clock_gettime(
+ id as c::clockid_t,
+ timespec.as_mut_ptr(),
+ ))?;
+
+ Ok(timespec.assume_init().into())
+ } else {
+ clock_gettime_dynamic_old(id)
+ }
+ }
+
+ #[cfg(not(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+ )))]
+ {
+ ret(c::clock_gettime(id as c::clockid_t, timespec.as_mut_ptr()))?;
+
+ Ok(timespec.assume_init())
+ }
+ }
+}
+
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[inline]
+unsafe fn clock_gettime_dynamic_old(id: c::clockid_t) -> io::Result<Timespec> {
+ let mut old_timespec = MaybeUninit::<c::timespec>::uninit();
+
+ ret(c::clock_gettime(
+ id as c::clockid_t,
+ old_timespec.as_mut_ptr(),
+ ))?;
+
+ let old_timespec = old_timespec.assume_init();
+ Ok(Timespec {
+ tv_sec: old_timespec.tv_sec.into(),
+ tv_nsec: old_timespec.tv_nsec.into(),
+ })
+}
+
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(feature = "time")]
+pub(crate) fn timerfd_create(id: TimerfdClockId, flags: TimerfdFlags) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(c::timerfd_create(id as c::clockid_t, flags.bits())) }
+}
+
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(feature = "time")]
+pub(crate) fn timerfd_settime(
+ fd: BorrowedFd<'_>,
+ flags: TimerfdTimerFlags,
+ new_value: &Itimerspec,
+) -> io::Result<Itimerspec> {
+ let mut result = MaybeUninit::<LibcItimerspec>::uninit();
+
+ #[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+ ))]
+ unsafe {
+ if let Some(libc_timerfd_settime) = __timerfd_settime64.get() {
+ ret(libc_timerfd_settime(
+ borrowed_fd(fd),
+ flags.bits(),
+ &new_value.clone().into(),
+ result.as_mut_ptr(),
+ ))
+ .map(|()| result.assume_init().into())
+ } else {
+ timerfd_settime_old(fd, flags, new_value)
+ }
+ }
+
+ #[cfg(not(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+ )))]
+ unsafe {
+ ret(c::timerfd_settime(
+ borrowed_fd(fd),
+ flags.bits(),
+ new_value,
+ result.as_mut_ptr(),
+ ))
+ .map(|()| result.assume_init())
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[cfg(feature = "time")]
+unsafe fn timerfd_settime_old(
+ fd: BorrowedFd<'_>,
+ flags: TimerfdTimerFlags,
+ new_value: &Itimerspec,
+) -> io::Result<Itimerspec> {
+ use core::convert::TryInto;
+
+ let mut old_result = MaybeUninit::<c::itimerspec>::uninit();
+
+ // Convert `new_value` to the old `itimerspec` format.
+ let old_new_value = c::itimerspec {
+ it_interval: c::timespec {
+ tv_sec: new_value
+ .it_interval
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ tv_nsec: new_value
+ .it_interval
+ .tv_nsec
+ .try_into()
+ .map_err(|_| io::Errno::INVAL)?,
+ },
+ it_value: c::timespec {
+ tv_sec: new_value
+ .it_value
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ tv_nsec: new_value
+ .it_value
+ .tv_nsec
+ .try_into()
+ .map_err(|_| io::Errno::INVAL)?,
+ },
+ };
+
+ ret(c::timerfd_settime(
+ borrowed_fd(fd),
+ flags.bits(),
+ &old_new_value,
+ old_result.as_mut_ptr(),
+ ))?;
+
+ let old_result = old_result.assume_init();
+ Ok(Itimerspec {
+ it_interval: Timespec {
+ tv_sec: old_result
+ .it_interval
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ tv_nsec: old_result.it_interval.tv_nsec as _,
+ },
+ it_value: Timespec {
+ tv_sec: old_result
+ .it_interval
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ tv_nsec: old_result.it_interval.tv_nsec as _,
+ },
+ })
+}
+
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(feature = "time")]
+pub(crate) fn timerfd_gettime(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> {
+ let mut result = MaybeUninit::<LibcItimerspec>::uninit();
+
+ #[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+ ))]
+ unsafe {
+ if let Some(libc_timerfd_gettime) = __timerfd_gettime64.get() {
+ ret(libc_timerfd_gettime(borrowed_fd(fd), result.as_mut_ptr()))
+ .map(|()| result.assume_init().into())
+ } else {
+ timerfd_gettime_old(fd)
+ }
+ }
+
+ #[cfg(not(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+ )))]
+ unsafe {
+ ret(c::timerfd_gettime(borrowed_fd(fd), result.as_mut_ptr())).map(|()| result.assume_init())
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[cfg(feature = "time")]
+unsafe fn timerfd_gettime_old(fd: BorrowedFd<'_>) -> io::Result<Itimerspec> {
+ use core::convert::TryInto;
+
+ let mut old_result = MaybeUninit::<c::itimerspec>::uninit();
+
+ ret(c::timerfd_gettime(borrowed_fd(fd), old_result.as_mut_ptr()))?;
+
+ let old_result = old_result.assume_init();
+ Ok(Itimerspec {
+ it_interval: Timespec {
+ tv_sec: old_result
+ .it_interval
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ tv_nsec: old_result.it_interval.tv_nsec as _,
+ },
+ it_value: Timespec {
+ tv_sec: old_result
+ .it_interval
+ .tv_sec
+ .try_into()
+ .map_err(|_| io::Errno::OVERFLOW)?,
+ tv_nsec: old_result.it_interval.tv_nsec as _,
+ },
+ })
+}
diff --git a/vendor/rustix/src/imp/libc/time/types.rs b/vendor/rustix/src/imp/libc/time/types.rs
new file mode 100644
index 000000000..4aa2b22e5
--- /dev/null
+++ b/vendor/rustix/src/imp/libc/time/types.rs
@@ -0,0 +1,362 @@
+use super::super::c;
+#[cfg(not(target_os = "wasi"))]
+use crate::fd::BorrowedFd;
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+use bitflags::bitflags;
+
+/// `struct timespec`
+#[cfg(not(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+)))]
+pub type Timespec = c::timespec;
+
+/// `struct timespec`
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[derive(Debug, Clone)]
+#[repr(C)]
+pub struct Timespec {
+ /// Seconds.
+ pub tv_sec: Secs,
+
+ /// Nanoseconds. Must be less than 1_000_000_000.
+ pub tv_nsec: Nsecs,
+}
+
+/// A type for the `tv_sec` field of [`Timespec`].
+#[cfg(not(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+)))]
+#[allow(deprecated)]
+pub type Secs = c::time_t;
+
+/// A type for the `tv_sec` field of [`Timespec`].
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+pub type Secs = i64;
+
+/// A type for the `tv_nsec` field of [`Timespec`].
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
+pub type Nsecs = i64;
+
+/// A type for the `tv_nsec` field of [`Timespec`].
+#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
+pub type Nsecs = c::c_long;
+
+/// On most platforms, `LibcTimespec` is just `Timespec`.
+#[cfg(not(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+)))]
+pub(crate) type LibcTimespec = Timespec;
+
+/// On 32-bit glibc platforms, `timespec` has anonymous padding fields, which
+/// Rust doesn't support yet (see `unnamed_fields`), so we define our own
+/// struct with explicit padding, with bidirectional `From` impls.
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[repr(C)]
+#[derive(Debug, Clone)]
+pub(crate) struct LibcTimespec {
+ pub(crate) tv_sec: Secs,
+
+ #[cfg(target_endian = "big")]
+ padding: core::mem::MaybeUninit<u32>,
+
+ pub(crate) tv_nsec: Nsecs,
+
+ #[cfg(target_endian = "little")]
+ padding: core::mem::MaybeUninit<u32>,
+}
+
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+impl From<LibcTimespec> for Timespec {
+ #[inline]
+ fn from(t: LibcTimespec) -> Self {
+ Self {
+ tv_sec: t.tv_sec,
+ tv_nsec: t.tv_nsec,
+ }
+ }
+}
+
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+impl From<Timespec> for LibcTimespec {
+ #[inline]
+ fn from(t: Timespec) -> Self {
+ Self {
+ tv_sec: t.tv_sec,
+ tv_nsec: t.tv_nsec,
+ padding: core::mem::MaybeUninit::uninit(),
+ }
+ }
+}
+
+/// `CLOCK_*` constants for use with [`clock_gettime`].
+///
+/// These constants are always supported at runtime so `clock_gettime` never
+/// has to fail with `INVAL` due to an unsupported clock. See
+/// [`DynamicClockId`] for a greater set of clocks, with the caveat that not
+/// all of them are always supported.
+///
+/// [`clock_gettime`]: crate::time::clock_gettime
+#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "wasi")))]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+#[cfg_attr(not(target_os = "dragonfly"), repr(i32))]
+#[cfg_attr(target_os = "dragonfly", repr(u64))]
+#[non_exhaustive]
+pub enum ClockId {
+ /// `CLOCK_REALTIME`
+ Realtime = c::CLOCK_REALTIME,
+
+ /// `CLOCK_MONOTONIC`
+ Monotonic = c::CLOCK_MONOTONIC,
+
+ /// `CLOCK_PROCESS_CPUTIME_ID`
+ #[cfg(not(any(
+ target_os = "illumos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "redox",
+ )))]
+ ProcessCPUTime = c::CLOCK_PROCESS_CPUTIME_ID,
+
+ /// `CLOCK_THREAD_CPUTIME_ID`
+ #[cfg(not(any(
+ target_os = "illumos",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "redox",
+ )))]
+ ThreadCPUTime = c::CLOCK_THREAD_CPUTIME_ID,
+
+ /// `CLOCK_REALTIME_COARSE`
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ RealtimeCoarse = c::CLOCK_REALTIME_COARSE,
+
+ /// `CLOCK_MONOTONIC_COARSE`
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MonotonicCoarse = c::CLOCK_MONOTONIC_COARSE,
+
+ /// `CLOCK_MONOTONIC_RAW`
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MonotonicRaw = c::CLOCK_MONOTONIC_RAW,
+}
+
+/// `CLOCK_*` constants for use with [`clock_gettime`].
+///
+/// These constants are always supported at runtime so `clock_gettime` never
+/// has to fail with `INVAL` due to an unsupported clock. See
+/// [`DynamicClockId`] for a greater set of clocks, with the caveat that not
+/// all of them are always supported.
+#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+#[repr(u32)]
+#[non_exhaustive]
+pub enum ClockId {
+ /// `CLOCK_REALTIME`
+ Realtime = c::CLOCK_REALTIME,
+
+ /// `CLOCK_MONOTONIC`
+ Monotonic = c::CLOCK_MONOTONIC,
+
+ /// `CLOCK_PROCESS_CPUTIME_ID`
+ ProcessCPUTime = c::CLOCK_PROCESS_CPUTIME_ID,
+
+ /// `CLOCK_THREAD_CPUTIME_ID`
+ ThreadCPUTime = c::CLOCK_THREAD_CPUTIME_ID,
+}
+
+/// `CLOCK_*` constants for use with [`clock_gettime_dynamic`].
+///
+/// These constants may be unsupported at runtime, depending on the OS version,
+/// and `clock_gettime_dynamic` may fail with `INVAL`. See [`ClockId`] for
+/// clocks which are always supported at runtime.
+///
+/// [`clock_gettime_dynamic`]: crate::time::clock_gettime_dynamic
+#[cfg(not(target_os = "wasi"))]
+#[derive(Debug, Copy, Clone)]
+#[non_exhaustive]
+pub enum DynamicClockId<'a> {
+ /// `ClockId` values that are always supported at runtime.
+ Known(ClockId),
+
+ /// Linux dynamic clocks.
+ Dynamic(BorrowedFd<'a>),
+
+ /// `CLOCK_REALTIME_ALARM`, available on Linux >= 3.0
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ RealtimeAlarm,
+
+ /// `CLOCK_TAI`, available on Linux >= 3.10
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Tai,
+
+ /// `CLOCK_BOOTTIME`, available on Linux >= 2.6.39
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Boottime,
+
+ /// `CLOCK_BOOTTIME_ALARM`, available on Linux >= 2.6.39
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ BoottimeAlarm,
+}
+
+/// `struct itimerspec`
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(not(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+)))]
+pub type Itimerspec = c::itimerspec;
+
+/// `struct itimerspec`
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[allow(missing_docs)]
+#[repr(C)]
+#[derive(Debug, Clone)]
+pub struct Itimerspec {
+ pub it_interval: Timespec,
+ pub it_value: Timespec,
+}
+
+/// On most platforms, `LibcItimerspec` is just `Itimerspec`.
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(not(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+)))]
+pub(crate) type LibcItimerspec = Itimerspec;
+
+/// On 32-bit glibc platforms, `LibcTimespec` differs from `Timespec`, so we
+/// define our own struct, with bidirectional `From` impls.
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+#[repr(C)]
+#[derive(Debug, Clone)]
+pub(crate) struct LibcItimerspec {
+ pub it_interval: LibcTimespec,
+ pub it_value: LibcTimespec,
+}
+
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+impl From<LibcItimerspec> for Itimerspec {
+ #[inline]
+ fn from(t: LibcItimerspec) -> Self {
+ Self {
+ it_interval: t.it_interval.into(),
+ it_value: t.it_value.into(),
+ }
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[cfg(all(
+ any(target_arch = "arm", target_arch = "mips", target_arch = "x86"),
+ target_env = "gnu",
+))]
+impl From<Itimerspec> for LibcItimerspec {
+ #[inline]
+ fn from(t: Itimerspec) -> Self {
+ Self {
+ it_interval: t.it_interval.into(),
+ it_value: t.it_value.into(),
+ }
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+bitflags! {
+ /// `TFD_*` flags for use with [`timerfd_create`].
+ pub struct TimerfdFlags: c::c_int {
+ /// `TFD_NONBLOCK`
+ const NONBLOCK = c::TFD_NONBLOCK;
+
+ /// `TFD_CLOEXEC`
+ const CLOEXEC = c::TFD_CLOEXEC;
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+bitflags! {
+ /// `TFD_TIMER_*` flags for use with [`timerfd_settime`].
+ pub struct TimerfdTimerFlags: c::c_int {
+ /// `TFD_TIMER_ABSTIME`
+ const ABSTIME = c::TFD_TIMER_ABSTIME;
+
+ /// `TFD_TIMER_CANCEL_ON_SET`
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ const CANCEL_ON_SET = 2; // TODO: upstream TFD_TIMER_CANCEL_ON_SET
+ }
+}
+
+/// `CLOCK_*` constants for use with [`timerfd_create`].
+///
+/// [`timerfd_create`]: crate::time::timerfd_create
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+#[repr(i32)]
+#[non_exhaustive]
+pub enum TimerfdClockId {
+ /// `CLOCK_REALTIME`—A clock that tells the "real" time.
+ ///
+ /// This is a clock that tells the amount of time elapsed since the
+ /// Unix epoch, 1970-01-01T00:00:00Z. The clock is externally settable, so
+ /// it is not monotonic. Successive reads may see decreasing times, so it
+ /// isn't reliable for measuring durations.
+ Realtime = c::CLOCK_REALTIME,
+
+ /// `CLOCK_MONOTONIC`—A clock that tells an abstract time.
+ ///
+ /// Unlike `Realtime`, this clock is not based on a fixed known epoch, so
+ /// individual times aren't meaningful. However, since it isn't settable,
+ /// it is reliable for measuring durations.
+ ///
+ /// This clock does not advance while the system is suspended; see
+ /// `Boottime` for a clock that does.
+ Monotonic = c::CLOCK_MONOTONIC,
+
+ /// `CLOCK_BOOTTIME`—Like `Monotonic`, but advances while suspended.
+ ///
+ /// This clock is similar to `Monotonic`, but does advance while the system
+ /// is suspended.
+ Boottime = c::CLOCK_BOOTTIME,
+
+ /// `CLOCK_REALTIME_ALARM`—Like `Realtime`, but wakes a suspended system.
+ ///
+ /// This clock is like `Realtime`, but can wake up a suspended system.
+ ///
+ /// Use of this clock requires the `CAP_WAKE_ALARM` Linux capability.
+ RealtimeAlarm = c::CLOCK_REALTIME_ALARM,
+
+ /// `CLOCK_BOOTTIME_ALARM`—Like `Boottime`, but wakes a suspended system.
+ ///
+ /// This clock is like `Boottime`, but can wake up a suspended system.
+ ///
+ /// Use of this clock requires the `CAP_WAKE_ALARM` Linux capability.
+ BoottimeAlarm = c::CLOCK_BOOTTIME_ALARM,
+}