Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more clocks to ClockId under linux_4_11 #911

Merged
merged 2 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading