From ba9391334e8d23261eb09ce7162015993f7c2aa3 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 29 May 2022 18:00:06 -0400 Subject: [PATCH] Add support for _COARSE clocks, spruce up comments --- src/shims/time.rs | 22 ++++++++++++++++++---- tests/run-pass/libc.rs | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 78bf6f59b349..be453a429ec5 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -16,6 +16,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx clk_id_op: &OpTy<'tcx, Tag>, tp_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { + // This clock support is deliberately minimal because a lot of clock types have fiddly + // properties (is it possible for Miri to be suspended independently of the host?). If you + // have a use for another clock type, please open an issue. + let this = self.eval_context_mut(); this.assert_target_os("linux", "clock_gettime"); @@ -23,11 +27,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; - let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? { + // Linux has two main kinds of clocks. REALTIME clocks return the actual time since the + // Unix epoch, including effects which may cause time to move backwards such as NTP. + // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version + // is just specified to be "faster and less precise", so we implement both the same way. + let absolute_clocks = + [this.eval_libc_i32("CLOCK_REALTIME")?, this.eval_libc_i32("CLOCK_REALTIME_COARSE")?]; + // The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are + // never allowed to go backwards. We don't need to do any additonal monotonicity + // enforcement because std::time::Instant already guarantees that it is monotonic. + let relative_clocks = + [this.eval_libc_i32("CLOCK_MONOTONIC")?, this.eval_libc_i32("CLOCK_MONOTONIC_COARSE")?]; + + let duration = if absolute_clocks.contains(&clk_id) { system_time_to_duration(&SystemTime::now())? - } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { - // Absolute time does not matter, only relative time does, so we can just - // use our own time anchor here. + } else if relative_clocks.contains(&clk_id) { Instant::now().duration_since(this.machine.time_anchor) } else { let einval = this.eval_libc("EINVAL")?; diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index fd3625639bfd..bf5ae9829011 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -230,6 +230,28 @@ fn test_thread_local_errno() { } } +/// Tests whether clock support exists at all +#[cfg(target_os = "linux")] +fn test_clocks() { + let mut tp = std::mem::MaybeUninit::::uninit(); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); +} + fn main() { #[cfg(target_os = "linux")] test_posix_fadvise(); @@ -249,4 +271,7 @@ fn main() { test_prctl_thread_name(); test_thread_local_errno(); + + #[cfg(target_os = "linux")] + test_clocks(); }