diff --git a/CHANGELOG.md b/CHANGELOG.md index e1ab7f3c4c..78659a7b47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - ReleaseDate +### Added +- Add `clock_gettime`, `clock_settime`, `clock_getres` + ([#1100](https://github.com/nix-rust/nix/pull/1100)) ## [0.16.0] - 1 December 2019 ### Added diff --git a/src/lib.rs b/src/lib.rs index d9ba026e2e..e7c5d07938 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,7 @@ pub mod poll; pub mod pty; pub mod sched; pub mod sys; +pub mod time; // This can be implemented for other platforms as soon as libc // provides bindings for them. #[cfg(all(target_os = "linux", diff --git a/src/sys/time.rs b/src/sys/time.rs index 606bbd9d9b..9c4e2b970f 100644 --- a/src/sys/time.rs +++ b/src/sys/time.rs @@ -67,6 +67,12 @@ impl AsRef for TimeSpec { } } +impl From for TimeSpec { + fn from(ts: timespec) -> Self { + TimeSpec(ts) + } +} + impl Ord for TimeSpec { // The implementation of cmp is simplified by assuming that the struct is // normalized. That is, tv_nsec must always be within [0, 1_000_000_000) diff --git a/src/time.rs b/src/time.rs new file mode 100644 index 0000000000..8d26ac7c0b --- /dev/null +++ b/src/time.rs @@ -0,0 +1,184 @@ +use sys::time::TimeSpec; +use std::mem::MaybeUninit; +use {Result, Errno}; +use libc; + +libc_enum! { + #[cfg_attr(any( + target_env = "uclibc", + target_os = "fuchsia", + target_os = "redox", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd", + target_os = "haiku", + all(not(target_env = "newlib"), + any(target_os = "linux", + target_os = "android", + target_os = "emscripten", + target_os = "solaris", + target_os = "illumos")), + ), repr(i32))] + #[cfg_attr(any( + all(target_env = "newlib", target_arch = "arm"), + target_os = "macos", + target_os = "ios", + ), repr(u32))] + #[cfg_attr(any( + all(target_env = "newlib", target_arch = "aarch64"), + all(not(any(target_env = "newlib", target_env = "uclibc")), target_os = "hermit"), + target_os = "dragonfly", + ), repr(u64))] + pub enum ClockId { + #[cfg(any(target_os = "fuchsia", + all(not(any(target_env = "uclibc", + target_env = "newlib")), + any(target_os = "linux", + target_os = "android", + target_os = "emscripten"), + ) + ))] + CLOCK_BOOTTIME, + #[cfg(any(target_os = "fuchsia", + all(not(any(target_env = "uclibc", + target_env = "newlib")), + any(target_os = "linux", + target_os = "android", + target_os = "emscripten"))))] + CLOCK_BOOTTIME_ALARM, + CLOCK_MONOTONIC, + #[cfg(any(target_os = "fuchsia", + all(not(any(target_env = "uclibc", + target_env = "newlib")), + any(target_os = "linux", + target_os = "android", + target_os = "emscripten"))))] + CLOCK_MONOTONIC_COARSE, + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly"))] + CLOCK_MONOTONIC_FAST, + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly"))] + CLOCK_MONOTONIC_PRECISE, + #[cfg(any(target_os = "fuchsia", + all(not(any(target_env = "uclibc", + target_env = "newlib")), + any(target_os = "linux", + target_os = "android", + target_os = "emscripten"))))] + CLOCK_MONOTONIC_RAW, + #[cfg(any(target_os = "fuchsia", + target_env = "uclibc", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + all(not(target_env = "newlib"), + any(target_os = "linux", + target_os = "android", + target_os = "emscripten"))))] + CLOCK_PROCESS_CPUTIME_ID, + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly"))] + CLOCK_PROF, + CLOCK_REALTIME, + #[cfg(any(target_os = "fuchsia", + all(not(any(target_env = "uclibc", + target_env = "newlib")), + any(target_os = "linux", + target_os = "android", + target_os = "emscripten"))))] + CLOCK_REALTIME_ALARM, + #[cfg(any(target_os = "fuchsia", + all(not(any(target_env = "uclibc", + target_env = "newlib")), + any(target_os = "linux", + target_os = "android", + target_os = "emscripten"))))] + CLOCK_REALTIME_COARSE, + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly"))] + CLOCK_REALTIME_FAST, + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly"))] + CLOCK_REALTIME_PRECISE, + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly"))] + CLOCK_SECOND, + #[cfg(any(target_os = "fuchsia", + all(not(any(target_env = "uclibc", target_env = "newlib")), + any(target_os = "emscripten", + all(target_os = "linux", target_env = "musl")))))] + CLOCK_SGI_CYCLE, + #[cfg(any(target_os = "fuchsia", + all(not(any(target_env = "uclibc", target_env = "newlib")), + any(target_os = "emscripten", + all(target_os = "linux", target_env = "musl")))))] + CLOCK_TAI, + #[cfg(any( + target_env = "uclibc", + target_os = "fuchsia", + target_os = "ios", + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + all( + not(target_env = "newlib"), + any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + ), + ), + ) + )] + CLOCK_THREAD_CPUTIME_ID, + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly"))] + CLOCK_UPTIME, + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly"))] + CLOCK_UPTIME_FAST, + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly"))] + CLOCK_UPTIME_PRECISE, + #[cfg(any(target_os = "freebsd", + target_os = "dragonfly"))] + CLOCK_VIRTUAL, + } +} + +pub fn clock_getres(clk_id: ClockId) -> Result { + let mut c_time: MaybeUninit = MaybeUninit::uninit(); + let errno = unsafe { libc::clock_getres(clk_id as libc::clockid_t, c_time.as_mut_ptr()) }; + Errno::result(errno)?; + let res = unsafe { c_time.assume_init() }; + Ok(TimeSpec::from(res)) +} + +pub fn clock_gettime(clk_id: ClockId) -> Result { + let mut c_time: MaybeUninit = MaybeUninit::uninit(); + let errno = unsafe { libc::clock_gettime(clk_id as libc::clockid_t, c_time.as_mut_ptr()) }; + Errno::result(errno)?; + let res = unsafe { c_time.assume_init() }; + Ok(TimeSpec::from(res)) +} + +#[cfg(not( + any( + target_os = "macos", + target_os = "ios", + all( + not(any(target_env = "uclibc", target_env = "newlibc")), + any( + target_os = "redox", + target_os = "hermit", + ), + ), + ) + ) + )] +pub fn clock_settime(clk_id: ClockId, timespec: TimeSpec) -> Result<()> { + let res = unsafe { libc::clock_settime(clk_id as libc::clockid_t, timespec.as_ref()) }; + Errno::result(res).map(drop) +} diff --git a/test/test.rs b/test/test.rs index 370ae03917..a1afc9af6b 100644 --- a/test/test.rs +++ b/test/test.rs @@ -126,6 +126,7 @@ mod test_sched; target_os = "macos"))] mod test_sendfile; mod test_stat; +mod test_time; mod test_unistd; use std::os::unix::io::RawFd; diff --git a/test/test_time.rs b/test/test_time.rs new file mode 100644 index 0000000000..2cbc53a770 --- /dev/null +++ b/test/test_time.rs @@ -0,0 +1,11 @@ +use nix::time::{clock_getres, clock_gettime, ClockId}; + +#[test] +pub fn test_clock_getres() { + assert!(clock_getres(ClockId::CLOCK_REALTIME).is_ok()); +} + +#[test] +pub fn test_clock_gettime() { + assert!(clock_gettime(ClockId::CLOCK_REALTIME).is_ok()); +}