Skip to content

Commit 4370538

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

File tree

6 files changed

+286
-1
lines changed

6 files changed

+286
-1
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 0 deletions
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

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

test/test.rs

Lines changed: 1 addition & 0 deletions
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

Lines changed: 38 additions & 0 deletions
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)