From 957ec2be10e628c0d31cfa4af7b7a26eccb89dfc Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Wed, 1 Apr 2020 20:35:56 -0400 Subject: [PATCH] Add support for 'std::time::Instant' in Windows --- src/shims/foreign_items/windows.rs | 13 +++++++----- src/shims/time.rs | 32 ++++++++++++++++++++++++++++++ tests/run-pass/time.rs | 29 ++++++++++++--------------- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index ee39773d71f8..5e1bffef8a4b 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -24,27 +24,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_u32(result), dest)?; } - "SetEnvironmentVariableW" => { let result = this.SetEnvironmentVariableW(args[0], args[1])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "GetEnvironmentStringsW" => { let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } - "FreeEnvironmentStringsW" => { let result = this.FreeEnvironmentStringsW(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "GetCurrentDirectoryW" => { let result = this.GetCurrentDirectoryW(args[0], args[1])?; this.write_scalar(Scalar::from_u32(result), dest)?; } - "SetCurrentDirectoryW" => { let result = this.SetCurrentDirectoryW(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -171,6 +166,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetSystemTimeAsFileTime" => { this.GetSystemTimeAsFileTime(args[0])?; } + "QueryPerformanceCounter" => { + let result = this.QueryPerformanceCounter(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "QueryPerformanceFrequency" => { + let result = this.QueryPerformanceFrequency(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Miscellaneous "SystemFunction036" => { diff --git a/src/shims/time.rs b/src/shims/time.rs index d501fa8a0fdb..65e83ab0af78 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -117,6 +117,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + #[allow(non_snake_case)] + fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.assert_target_os("windows", "QueryPerformanceCounter"); + this.check_no_isolation("QueryPerformanceCounter")?; + + // QPC uses a hardware counter as its basis. + // Miri will assume that the machine's hardware counter has a resolution of 1 nanosecond. + let duration = Instant::now().duration_since(this.machine.time_anchor); + let qpc = i64::try_from(duration.as_nanos()) + .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported"))?; + this.write_scalar(Scalar::from_i64(qpc), this.deref_operand(lpPerformanceCount_op)?.into())?; + Ok(-1) // return non-zero on success + } + + #[allow(non_snake_case)] + fn QueryPerformanceFrequency(&mut self, lpFrequency_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.assert_target_os("windows", "QueryPerformanceFrequency"); + this.check_no_isolation("QueryPerformanceFrequency")?; + + // Retrieves the frequency of the hardware performance counter. + // The frequency of the performance counter is fixed at system boot and + // is consistent across all processors. + // Miri will assume that the frequency of + // the machine's hardware performance counter is 1 GHz ( = 1 x 10^9 Hz). + this.write_scalar(Scalar::from_i64(1_000_000_000), this.deref_operand(lpFrequency_op)?.into())?; + Ok(-1) // Return non-zero on success + } + fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { let this = self.eval_context_ref(); diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index a9ca28161cac..264fa9de0352 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -19,22 +19,19 @@ fn main() { assert!(2020 <= year && year < 2100); // Check `Instant`. - #[cfg(not(windows))] // `Instant` shims not yet implemented on Windows - { - let now1 = Instant::now(); - // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } - let now2 = Instant::now(); - assert!(now2 > now1); + let now1 = Instant::now(); + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + let now2 = Instant::now(); + assert!(now2 > now1); - #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction - { - let diff = now2.duration_since(now1); - assert_eq!(now1 + diff, now2); - assert_eq!(now2 - diff, now1); - // Sanity-check the difference we got. - assert!(diff.as_micros() > 1); - assert!(diff.as_micros() < 1_000_000); - } + #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction + { + let diff = now2.duration_since(now1); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); + // Sanity-check the difference we got. + assert!(diff.as_micros() > 1); + assert!(diff.as_micros() < 1_000_000); } }