Skip to content

Commit b3e7543

Browse files
committed
Added clock_gettime, clock_getres, clock_settime, clock_getcpuclockid
1 parent 96054b6 commit b3e7543

File tree

6 files changed

+283
-1
lines changed

6 files changed

+283
-1
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55

66
## [Unreleased] - ReleaseDate
77
### Added
8+
- Added `clock_gettime`, `clock_settime`, `clock_getres`,
9+
`clock_getcpuclockid` functions and `ClockId` struct.
10+
(#[1281](https://github.com/nix-rust/nix/pull/1281))
811
### Changed
912
### Fixed
1013
### Removed

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.74", 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/time.rs

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

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;

test/test_time.rs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#[cfg(target_os = "linux")]
2+
use nix::time::clock_getcpuclockid;
3+
use nix::time::{clock_getres, clock_gettime, ClockId};
4+
5+
#[test]
6+
pub fn test_clock_getres() {
7+
assert!(clock_getres(ClockId::CLOCK_REALTIME).is_ok());
8+
}
9+
10+
#[test]
11+
pub fn test_clock_gettime() {
12+
assert!(clock_gettime(ClockId::CLOCK_REALTIME).is_ok());
13+
}
14+
15+
#[cfg(target_os = "linux")]
16+
#[test]
17+
pub fn test_clock_getcpuclockid() {
18+
let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap();
19+
assert!(clock_gettime(clock_id).is_ok());
20+
}
21+
22+
#[test]
23+
pub fn test_clock_id_res() {
24+
assert!(ClockId::CLOCK_REALTIME.res().is_ok());
25+
}
26+
27+
#[test]
28+
pub fn test_clock_id_time() {
29+
assert!(ClockId::CLOCK_REALTIME.time().is_ok());
30+
}
31+
32+
#[cfg(target_os = "linux")]
33+
#[test]
34+
pub fn test_clock_id_pid_cpu_clock_id() {
35+
assert!(ClockId::pid_cpu_clock_id(nix::unistd::Pid::this())
36+
.map(ClockId::time)
37+
.is_ok());
38+
}

0 commit comments

Comments
 (0)