Skip to content

Commit

Permalink
Add more clocks to ClockId under linux_4_11 (#911)
Browse files Browse the repository at this point in the history
* Add more clocks to `ClockId` under `linux_4_11`

Add several more clocks to `ClockId` for use with the infallible
`clock_gettiem` when the `linux_4_11` feature is enabled.

* Don't test `test_boottime_alarm_clock` on platforms that don't have it.
  • Loading branch information
sunfishcode authored Nov 6, 2023
1 parent bc4fa30 commit eb774c1
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 1 deletion.
8 changes: 8 additions & 0 deletions src/backend/linux_raw/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,14 @@ pub(crate) const CLOCK_THREAD_CPUTIME_ID: c_int =
linux_raw_sys::general::CLOCK_THREAD_CPUTIME_ID as _;
pub(crate) const CLOCK_PROCESS_CPUTIME_ID: c_int =
linux_raw_sys::general::CLOCK_PROCESS_CPUTIME_ID as _;
#[cfg(all(feature = "time", feature = "linux_4_11"))]
pub(crate) const CLOCK_BOOTTIME: c_int = linux_raw_sys::general::CLOCK_BOOTTIME as _;
#[cfg(all(feature = "time", feature = "linux_4_11"))]
pub(crate) const CLOCK_BOOTTIME_ALARM: c_int = linux_raw_sys::general::CLOCK_BOOTTIME_ALARM as _;
#[cfg(all(feature = "time", feature = "linux_4_11"))]
pub(crate) const CLOCK_TAI: c_int = linux_raw_sys::general::CLOCK_TAI as _;
#[cfg(all(feature = "time", feature = "linux_4_11"))]
pub(crate) const CLOCK_REALTIME_ALARM: c_int = linux_raw_sys::general::CLOCK_REALTIME_ALARM as _;

#[cfg(feature = "system")]
mod reboot_symbols {
Expand Down
5 changes: 4 additions & 1 deletion src/backend/linux_raw/fs/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@

use crate::backend::c;
use crate::backend::conv::fs::oflags_for_open_how;
#[cfg(not(feature = "linux_4_11"))]
use crate::backend::conv::zero;
use crate::backend::conv::{
by_ref, c_int, c_uint, dev_t, opt_mut, pass_usize, raw_fd, ret, ret_c_int, ret_c_uint,
ret_infallible, ret_owned_fd, ret_usize, size_of, slice, slice_mut, zero,
ret_infallible, ret_owned_fd, ret_usize, size_of, slice, slice_mut,
};
#[cfg(target_pointer_width = "64")]
use crate::backend::conv::{loff_t, loff_t_from_u64, ret_u64};
Expand Down Expand Up @@ -839,6 +841,7 @@ pub(crate) fn statx(
}
}

#[cfg(not(feature = "linux_4_11"))]
#[inline]
pub(crate) fn is_statx_available() -> bool {
unsafe {
Expand Down
27 changes: 27 additions & 0 deletions src/clockid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,33 @@ pub enum ClockId {
/// `CLOCK_MONOTONIC_RAW`
#[cfg(linux_kernel)]
MonotonicRaw = c::CLOCK_MONOTONIC_RAW,

/// `CLOCK_REALTIME_ALARM`, available on Linux >= 3.0
#[cfg(all(linux_kernel, feature = "linux_4_11"))]
#[doc(alias = "CLOCK_REALTIME_ALARM")]
RealtimeAlarm = bitcast!(c::CLOCK_REALTIME_ALARM),

/// `CLOCK_TAI`, available on Linux >= 3.10
#[cfg(all(linux_kernel, feature = "linux_4_11"))]
#[doc(alias = "CLOCK_TAI")]
Tai = bitcast!(c::CLOCK_TAI),

/// `CLOCK_BOOTTIME`, available on Linux >= 2.6.39
///
/// On FreeBSD, use [`Self::Uptime`], as `CLOCK_BOOTTIME` is an alias for
/// `CLOCK_UPTIME`.
#[cfg(any(
all(linux_kernel, feature = "linux_4_11"),
target_os = "fuchsia",
target_os = "openbsd"
))]
#[doc(alias = "CLOCK_BOOTTIME")]
Boottime = bitcast!(c::CLOCK_BOOTTIME),

/// `CLOCK_BOOTTIME_ALARM`, available on Linux >= 2.6.39
#[cfg(any(all(linux_kernel, feature = "linux_4_11"), target_os = "fuchsia"))]
#[doc(alias = "CLOCK_BOOTTIME_ALARM")]
BoottimeAlarm = bitcast!(c::CLOCK_BOOTTIME_ALARM),
}

/// `CLOCK_*` constants for use with [`clock_gettime`].
Expand Down
139 changes: 139 additions & 0 deletions tests/time/clocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use rustix::time::{clock_gettime, ClockId};
fn test_boottime_clock() {
use rustix::time::{clock_gettime_dynamic, DynamicClockId};

let monotonic = clock_gettime(ClockId::Monotonic);

if let Ok(a) = clock_gettime_dynamic(DynamicClockId::Boottime) {
if let Ok(b) = clock_gettime_dynamic(DynamicClockId::Boottime) {
if b.tv_sec == a.tv_sec {
Expand All @@ -25,6 +27,78 @@ fn test_boottime_clock() {
assert!(b.tv_sec > a.tv_sec);
}
}

// Test that boot time is after monotonic.
if a.tv_sec == monotonic.tv_sec {
assert!(a.tv_nsec >= monotonic.tv_nsec);
} else {
assert!(a.tv_sec > monotonic.tv_sec);
}
}

#[cfg(feature = "linux_4_11")]
{
let a = clock_gettime(ClockId::Boottime);
let b = clock_gettime(ClockId::Boottime);

if b.tv_sec == a.tv_sec {
assert!(b.tv_nsec >= a.tv_nsec);
} else {
assert!(b.tv_sec > a.tv_sec);
}

// Test that boot time is after monotonic.
if a.tv_sec == monotonic.tv_sec {
assert!(a.tv_nsec >= monotonic.tv_nsec);
} else {
assert!(a.tv_sec > monotonic.tv_sec);
}
}
}

/// Attempt to test that the boot alarm clock is monotonic. Time may or may not
/// advance, but it shouldn't regress.
#[cfg(any(linux_kernel, target_os = "fuchsia"))]
#[test]
fn test_boottime_alarm_clock() {
use rustix::time::{clock_gettime_dynamic, DynamicClockId};

let monotonic = clock_gettime(ClockId::Monotonic);

if let Ok(a) = clock_gettime_dynamic(DynamicClockId::BoottimeAlarm) {
if let Ok(b) = clock_gettime_dynamic(DynamicClockId::BoottimeAlarm) {
if b.tv_sec == a.tv_sec {
assert!(b.tv_nsec >= a.tv_nsec);
} else {
assert!(b.tv_sec > a.tv_sec);
}
}

// Test that boot alarm time is after monotonic.
if a.tv_sec == monotonic.tv_sec {
assert!(a.tv_nsec >= monotonic.tv_nsec);
} else {
assert!(a.tv_sec > monotonic.tv_sec);
}
}

#[cfg(feature = "linux_4_11")]
{
let a = clock_gettime(ClockId::BoottimeAlarm);
let b = clock_gettime(ClockId::BoottimeAlarm);

if b.tv_sec == a.tv_sec {
assert!(b.tv_nsec >= a.tv_nsec);
} else {
assert!(b.tv_sec > a.tv_sec);
}

// Test that boot alarm time is after monotonic.
if a.tv_sec == monotonic.tv_sec {
assert!(a.tv_nsec >= monotonic.tv_nsec);
} else {
assert!(a.tv_sec > monotonic.tv_sec);
}
}
}

Expand Down Expand Up @@ -79,6 +153,71 @@ fn test_realtime_coarse_clock() {
assert!(a.tv_nsec < 1_000_000_000);
}

#[cfg(linux_kernel)]
#[test]
fn test_realtime_alarm_clock() {
use rustix::time::{clock_gettime_dynamic, DynamicClockId};

if let Ok(a) = clock_gettime_dynamic(DynamicClockId::RealtimeAlarm) {
// Test that the timespec is valid; there's not much else we can say.
assert!(a.tv_nsec < 1_000_000_000);
}

#[cfg(feature = "linux_4_11")]
{
let a = clock_gettime(ClockId::RealtimeAlarm);

// Test that the timespec is valid; there's not much else we can say.
assert!(a.tv_nsec < 1_000_000_000);
}
}

/// Attempt to test that the TAI clock is monotonic. Time may or may not
/// advance, but it shouldn't regress.
#[cfg(linux_kernel)]
#[test]
fn test_tai_clock() {
use rustix::time::{clock_gettime_dynamic, DynamicClockId};

let realtime = clock_gettime(ClockId::Realtime);

if let Ok(a) = clock_gettime_dynamic(DynamicClockId::Tai) {
if let Ok(b) = clock_gettime_dynamic(DynamicClockId::Tai) {
if b.tv_sec == a.tv_sec {
assert!(b.tv_nsec >= a.tv_nsec);
} else {
assert!(b.tv_sec > a.tv_sec);
}
}

// Test that TAI time is after realtime.
if a.tv_sec == realtime.tv_sec {
assert!(a.tv_nsec >= realtime.tv_nsec);
} else {
assert!(a.tv_sec > realtime.tv_sec);
}
}

#[cfg(feature = "linux_4_11")]
{
let a = clock_gettime(ClockId::Tai);
let b = clock_gettime(ClockId::Tai);

if b.tv_sec == a.tv_sec {
assert!(b.tv_nsec >= a.tv_nsec);
} else {
assert!(b.tv_sec > a.tv_sec);
}

// Test that TAI time is after realtime.
if a.tv_sec == realtime.tv_sec {
assert!(a.tv_nsec >= realtime.tv_nsec);
} else {
assert!(a.tv_sec > realtime.tv_sec);
}
}
}

/// Attempt to test that the coarse monotonic clock is monotonic. Time may or
/// may not advance, but it shouldn't regress.
#[cfg(any(linux_kernel, target_os = "freebsd"))]
Expand Down

0 comments on commit eb774c1

Please sign in to comment.