Skip to content

Commit 91effec

Browse files
committed
Added clock_gettime, clock_getres, clock_settime, clock_getcpuclockid
1 parent 2c24405 commit 91effec

File tree

7 files changed

+346
-1
lines changed

7 files changed

+346
-1
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
77
### Added
88
- Added Netlink protocol families to the `SockProtocol` enum
99
(#[1289](https://github.com/nix-rust/nix/pull/1289))
10+
- Added `clock_gettime`, `clock_settime`, `clock_getres`,
11+
`clock_getcpuclockid` functions and `ClockId` struct.
12+
(#[1281](https://github.com/nix-rust/nix/pull/1281))
1013
### Changed
1114
- Expose `SeekData` and `SeekHole` on all Linux targets
1215
(#[1284](https://github.com/nix-rust/nix/pull/1284))

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ exclude = [
1717
]
1818

1919
[dependencies]
20-
libc = { version = "0.2.73", features = [ "extra_traits" ] }
20+
libc = { version = "0.2.77", features = [ "extra_traits" ] }
2121
bitflags = "1.1"
2222
cfg-if = "0.1.10"
2323

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ pub mod poll;
6161
pub mod pty;
6262
pub mod sched;
6363
pub mod sys;
64+
pub mod time;
6465
// This can be implemented for other platforms as soon as libc
6566
// provides bindings for them.
6667
#[cfg(all(target_os = "linux",

src/sys/time.rs

+26
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::{cmp, fmt, ops};
2+
use std::time::Duration;
23
use std::convert::From;
34
use libc::{c_long, timespec, timeval};
45
pub use libc::{time_t, suseconds_t};
@@ -66,6 +67,21 @@ impl From<timespec> for TimeSpec {
6667
}
6768
}
6869

70+
impl From<Duration> for TimeSpec {
71+
fn from(duration: Duration) -> Self {
72+
TimeSpec(timespec {
73+
tv_sec: duration.as_secs() as time_t,
74+
tv_nsec: duration.subsec_nanos() as c_long
75+
})
76+
}
77+
}
78+
79+
impl From<TimeSpec> for Duration {
80+
fn from(timespec: TimeSpec) -> Self {
81+
Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32)
82+
}
83+
}
84+
6985
impl AsRef<timespec> for TimeSpec {
7086
fn as_ref(&self) -> &timespec {
7187
&self.0
@@ -484,6 +500,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
484500
#[cfg(test)]
485501
mod test {
486502
use super::{TimeSpec, TimeVal, TimeValLike};
503+
use std::time::Duration;
487504

488505
#[test]
489506
pub fn test_timespec() {
@@ -494,6 +511,15 @@ mod test {
494511
TimeSpec::seconds(182));
495512
}
496513

514+
#[test]
515+
pub fn test_timespec_from() {
516+
let duration = Duration::new(123, 123_456_789);
517+
let timespec = TimeSpec::nanoseconds(123_123_456_789);
518+
519+
assert_eq!(TimeSpec::from(duration), timespec);
520+
assert_eq!(Duration::from(timespec), duration);
521+
}
522+
497523
#[test]
498524
pub fn test_timespec_neg() {
499525
let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);

src/time.rs

+258
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
use crate::sys::time::TimeSpec;
2+
#[cfg(any(
3+
target_os = "freebsd",
4+
target_os = "dragonfly",
5+
target_os = "linux",
6+
target_os = "android",
7+
target_os = "emscripten",
8+
))]
9+
use crate::{unistd::Pid, Error};
10+
use crate::{Errno, Result};
11+
use libc::{self, clockid_t};
12+
use std::mem::MaybeUninit;
13+
14+
/// Clock identifier
15+
///
16+
/// Newtype pattern around `clockid_t` (which is just alias). It pervents bugs caused by
17+
/// accidentally passing wrong value.
18+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
19+
pub struct ClockId(clockid_t);
20+
21+
impl ClockId {
22+
/// Creates `ClockId` from raw `clockid_t`
23+
pub fn from_raw(clk_id: clockid_t) -> Self {
24+
ClockId(clk_id)
25+
}
26+
27+
/// Returns `ClockId` of a `pid` CPU-time clock
28+
#[cfg(any(
29+
target_os = "freebsd",
30+
target_os = "dragonfly",
31+
target_os = "linux",
32+
target_os = "android",
33+
target_os = "emscripten",
34+
))]
35+
pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> {
36+
clock_getcpuclockid(pid)
37+
}
38+
39+
/// Returns resolution of the clock id
40+
pub fn res(self) -> Result<TimeSpec> {
41+
clock_getres(self)
42+
}
43+
44+
/// Returns the current time on the clock id
45+
pub fn now(self) -> Result<TimeSpec> {
46+
clock_gettime(self)
47+
}
48+
49+
/// Sets time to `timespec` on the clock id
50+
#[cfg(not(any(
51+
target_os = "macos",
52+
target_os = "ios",
53+
all(
54+
not(any(target_env = "uclibc", target_env = "newlibc")),
55+
any(target_os = "redox", target_os = "hermit",),
56+
),
57+
)))]
58+
pub fn set_time(self, timespec: TimeSpec) -> Result<()> {
59+
clock_settime(self, timespec)
60+
}
61+
62+
/// Gets the raw `clockid_t` wrapped by `self`
63+
pub fn as_raw(self) -> clockid_t {
64+
self.0
65+
}
66+
67+
#[cfg(any(
68+
target_os = "fuchsia",
69+
all(
70+
not(any(target_env = "uclibc", target_env = "newlib")),
71+
any(target_os = "linux", target_os = "android", target_os = "emscripten"),
72+
)
73+
))]
74+
pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME);
75+
#[cfg(any(
76+
target_os = "fuchsia",
77+
all(
78+
not(any(target_env = "uclibc", target_env = "newlib")),
79+
any(target_os = "linux", target_os = "android", target_os = "emscripten")
80+
)
81+
))]
82+
pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM);
83+
pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC);
84+
#[cfg(any(
85+
target_os = "fuchsia",
86+
all(
87+
not(any(target_env = "uclibc", target_env = "newlib")),
88+
any(target_os = "linux", target_os = "android", target_os = "emscripten")
89+
)
90+
))]
91+
pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE);
92+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
93+
pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST);
94+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
95+
pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE);
96+
#[cfg(any(
97+
target_os = "fuchsia",
98+
all(
99+
not(any(target_env = "uclibc", target_env = "newlib")),
100+
any(target_os = "linux", target_os = "android", target_os = "emscripten")
101+
)
102+
))]
103+
pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW);
104+
#[cfg(any(
105+
target_os = "fuchsia",
106+
target_env = "uclibc",
107+
target_os = "macos",
108+
target_os = "ios",
109+
target_os = "freebsd",
110+
target_os = "dragonfly",
111+
all(
112+
not(target_env = "newlib"),
113+
any(target_os = "linux", target_os = "android", target_os = "emscripten")
114+
)
115+
))]
116+
pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID);
117+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
118+
pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF);
119+
pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME);
120+
#[cfg(any(
121+
target_os = "fuchsia",
122+
all(
123+
not(any(target_env = "uclibc", target_env = "newlib")),
124+
any(target_os = "linux", target_os = "android", target_os = "emscripten")
125+
)
126+
))]
127+
pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM);
128+
#[cfg(any(
129+
target_os = "fuchsia",
130+
all(
131+
not(any(target_env = "uclibc", target_env = "newlib")),
132+
any(target_os = "linux", target_os = "android", target_os = "emscripten")
133+
)
134+
))]
135+
pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE);
136+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
137+
pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST);
138+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
139+
pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE);
140+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
141+
pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND);
142+
#[cfg(any(
143+
target_os = "fuchsia",
144+
all(
145+
not(any(target_env = "uclibc", target_env = "newlib")),
146+
any(
147+
target_os = "emscripten",
148+
all(target_os = "linux", target_env = "musl")
149+
)
150+
)
151+
))]
152+
pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE);
153+
#[cfg(any(
154+
target_os = "fuchsia",
155+
all(
156+
not(any(target_env = "uclibc", target_env = "newlib")),
157+
any(
158+
target_os = "emscripten",
159+
all(target_os = "linux", target_env = "musl")
160+
)
161+
)
162+
))]
163+
pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI);
164+
#[cfg(any(
165+
target_env = "uclibc",
166+
target_os = "fuchsia",
167+
target_os = "ios",
168+
target_os = "macos",
169+
target_os = "freebsd",
170+
target_os = "dragonfly",
171+
all(
172+
not(target_env = "newlib"),
173+
any(target_os = "linux", target_os = "android", target_os = "emscripten",),
174+
),
175+
))]
176+
pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID);
177+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
178+
pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME);
179+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
180+
pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST);
181+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
182+
pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE);
183+
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
184+
pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL);
185+
}
186+
187+
impl Into<clockid_t> for ClockId {
188+
fn into(self) -> clockid_t {
189+
self.as_raw()
190+
}
191+
}
192+
193+
impl From<clockid_t> for ClockId {
194+
fn from(clk_id: clockid_t) -> Self {
195+
ClockId::from_raw(clk_id)
196+
}
197+
}
198+
199+
impl std::fmt::Display for ClockId {
200+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
201+
std::fmt::Display::fmt(&self.0, f)
202+
}
203+
}
204+
205+
/// Get the resolution of the specified clock, (see
206+
/// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)).
207+
pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
208+
let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
209+
let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) };
210+
Errno::result(ret)?;
211+
let res = unsafe { c_time.assume_init() };
212+
Ok(TimeSpec::from(res))
213+
}
214+
215+
/// Get the time of the specified clock, (see
216+
/// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)).
217+
pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> {
218+
let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
219+
let ret = unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) };
220+
Errno::result(ret)?;
221+
let res = unsafe { c_time.assume_init() };
222+
Ok(TimeSpec::from(res))
223+
}
224+
225+
/// Set the time of the specified clock, (see
226+
/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)).
227+
#[cfg(not(any(
228+
target_os = "macos",
229+
target_os = "ios",
230+
all(
231+
not(any(target_env = "uclibc", target_env = "newlibc")),
232+
any(target_os = "redox", target_os = "hermit",),
233+
),
234+
)))]
235+
pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
236+
let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) };
237+
Errno::result(ret).map(drop)
238+
}
239+
240+
/// Get the clock id of the specified process id, (see
241+
/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)).
242+
#[cfg(any(
243+
target_os = "freebsd",
244+
target_os = "dragonfly",
245+
target_os = "linux",
246+
target_os = "android",
247+
target_os = "emscripten",
248+
))]
249+
pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
250+
let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit();
251+
let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) };
252+
if ret == 0 {
253+
let res = unsafe { clk_id.assume_init() };
254+
Ok(ClockId::from(res))
255+
} else {
256+
Err(Error::Sys(Errno::from_i32(ret)))
257+
}
258+
}

test/test.rs

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ mod test_sched;
139139
target_os = "macos"))]
140140
mod test_sendfile;
141141
mod test_stat;
142+
mod test_time;
142143
mod test_unistd;
143144

144145
use std::os::unix::io::RawFd;

0 commit comments

Comments
 (0)