Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 57d8206

Browse files
committed
Auto merge of rust-lang#2165 - saethlin:more-clocks, r=RalfJung
Add support for _COARSE clocks Original idea does not work, so I'm just going to try expanding support to include the `_COARSE` clocks. The original motivation for this PR is that the test suite for the crate [`minstant`](https://crates.io/crates/minstant) reports UB, because it tries to use a clock type Miri didn't support, but never checked for an error code and so just used the uninit `libc::timespec`. So, that's technically a bug in `minstant`, but outside of Miri you'd have to be using an incredibly old Linux to ever see an `EINVAL` so the more helpful thing for Miri to do is behave like a newer Linux. So now we don't detect UB in `minstant`, but we have a test failure: ``` failures: ---- src/instant.rs - instant::Instant::as_unix_nanos (line 150) stdout ---- Test executable failed (exit status: 101). stderr: thread 'main' panicked at 'assertion failed: (instant.as_unix_nanos(&anchor) as i64 - expected as i64).abs() < 1_000_000', src/instant.rs:11:1 ``` I'm having trouble getting my head around the code in `minstant` that's involved in this test, but as far as I can tell from the man pages, these `_COARSE` clocks meet the requirements. Closes rust-lang/miri#1983 at least as best as I can.
2 parents 065ff89 + ba93913 commit 57d8206

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

src/shims/time.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
1616
clk_id_op: &OpTy<'tcx, Tag>,
1717
tp_op: &OpTy<'tcx, Tag>,
1818
) -> InterpResult<'tcx, i32> {
19+
// This clock support is deliberately minimal because a lot of clock types have fiddly
20+
// properties (is it possible for Miri to be suspended independently of the host?). If you
21+
// have a use for another clock type, please open an issue.
22+
1923
let this = self.eval_context_mut();
2024

2125
this.assert_target_os("linux", "clock_gettime");
2226
this.check_no_isolation("`clock_gettime`")?;
2327

2428
let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
2529

26-
let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? {
30+
// Linux has two main kinds of clocks. REALTIME clocks return the actual time since the
31+
// Unix epoch, including effects which may cause time to move backwards such as NTP.
32+
// Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
33+
// is just specified to be "faster and less precise", so we implement both the same way.
34+
let absolute_clocks =
35+
[this.eval_libc_i32("CLOCK_REALTIME")?, this.eval_libc_i32("CLOCK_REALTIME_COARSE")?];
36+
// The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are
37+
// never allowed to go backwards. We don't need to do any additonal monotonicity
38+
// enforcement because std::time::Instant already guarantees that it is monotonic.
39+
let relative_clocks =
40+
[this.eval_libc_i32("CLOCK_MONOTONIC")?, this.eval_libc_i32("CLOCK_MONOTONIC_COARSE")?];
41+
42+
let duration = if absolute_clocks.contains(&clk_id) {
2743
system_time_to_duration(&SystemTime::now())?
28-
} else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
29-
// Absolute time does not matter, only relative time does, so we can just
30-
// use our own time anchor here.
44+
} else if relative_clocks.contains(&clk_id) {
3145
Instant::now().duration_since(this.machine.time_anchor)
3246
} else {
3347
let einval = this.eval_libc("EINVAL")?;

tests/run-pass/libc.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,28 @@ fn test_thread_local_errno() {
230230
}
231231
}
232232

233+
/// Tests whether clock support exists at all
234+
#[cfg(target_os = "linux")]
235+
fn test_clocks() {
236+
let mut tp = std::mem::MaybeUninit::<libc::timespec>::uninit();
237+
let is_error = unsafe {
238+
libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr())
239+
};
240+
assert_eq!(is_error, 0);
241+
let is_error = unsafe {
242+
libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr())
243+
};
244+
assert_eq!(is_error, 0);
245+
let is_error = unsafe {
246+
libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr())
247+
};
248+
assert_eq!(is_error, 0);
249+
let is_error = unsafe {
250+
libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr())
251+
};
252+
assert_eq!(is_error, 0);
253+
}
254+
233255
fn main() {
234256
#[cfg(target_os = "linux")]
235257
test_posix_fadvise();
@@ -249,4 +271,7 @@ fn main() {
249271
test_prctl_thread_name();
250272

251273
test_thread_local_errno();
274+
275+
#[cfg(target_os = "linux")]
276+
test_clocks();
252277
}

0 commit comments

Comments
 (0)