1
Fork 0

implement clock_gettime on macos

This commit is contained in:
Ralf Jung 2022-11-19 20:21:48 +01:00
parent 81ee8c13dc
commit 21321f57c2
4 changed files with 56 additions and 27 deletions

View file

@ -22,21 +22,44 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.assert_target_os("linux", "clock_gettime"); this.assert_target_os_is_unix("clock_gettime");
let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
// Linux has two main kinds of clocks. REALTIME clocks return the actual time since the let absolute_clocks;
// Unix epoch, including effects which may cause time to move backwards such as NTP. let mut relative_clocks;
// 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. match this.tcx.sess.target.os.as_ref() {
let absolute_clocks = "linux" => {
[this.eval_libc_i32("CLOCK_REALTIME")?, this.eval_libc_i32("CLOCK_REALTIME_COARSE")?]; // Linux has two main kinds of clocks. REALTIME clocks return the actual time since the
// The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are // Unix epoch, including effects which may cause time to move backwards such as NTP.
// never allowed to go backwards. We don't need to do any additonal monotonicity // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
// enforcement because std::time::Instant already guarantees that it is monotonic. // is just specified to be "faster and less precise", so we implement both the same way.
let relative_clocks = absolute_clocks = vec![
[this.eval_libc_i32("CLOCK_MONOTONIC")?, this.eval_libc_i32("CLOCK_MONOTONIC_COARSE")?]; 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.
relative_clocks = vec![
this.eval_libc_i32("CLOCK_MONOTONIC")?,
this.eval_libc_i32("CLOCK_MONOTONIC_COARSE")?,
];
}
"macos" => {
absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")?];
relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")?];
// Some clocks only seem to exist in the aarch64 version of the target.
if this.tcx.sess.target.arch == "aarch64" {
// `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but
// that's not really something a program running inside Miri can tell, anyway.
// We need to support it because std uses it.
relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW")?);
}
}
target => throw_unsup_format!("`clock_gettime` is not supported on target OS {target}"),
}
let duration = if absolute_clocks.contains(&clk_id) { let duration = if absolute_clocks.contains(&clk_id) {
this.check_no_isolation("`clock_gettime` with `REALTIME` clocks")?; this.check_no_isolation("`clock_gettime` with `REALTIME` clocks")?;
@ -44,6 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} else if relative_clocks.contains(&clk_id) { } else if relative_clocks.contains(&clk_id) {
this.machine.clock.now().duration_since(this.machine.clock.anchor()) this.machine.clock.now().duration_since(this.machine.clock.anchor())
} else { } else {
// Unsupported clock.
let einval = this.eval_libc("EINVAL")?; let einval = this.eval_libc("EINVAL")?;
this.set_last_error(einval)?; this.set_last_error(einval)?;
return Ok(Scalar::from_i32(-1)); return Ok(Scalar::from_i32(-1));

View file

@ -180,6 +180,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let result = this.gettimeofday(tv, tz)?; let result = this.gettimeofday(tv, tz)?;
this.write_scalar(Scalar::from_i32(result), dest)?; this.write_scalar(Scalar::from_i32(result), dest)?;
} }
"clock_gettime" => {
let [clk_id, tp] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.clock_gettime(clk_id, tp)?;
this.write_scalar(result, dest)?;
}
// Allocation // Allocation
"posix_memalign" => { "posix_memalign" => {

View file

@ -43,15 +43,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(result, dest)?; this.write_scalar(result, dest)?;
} }
// Time related shims
"clock_gettime" => {
// This is a POSIX function but it has only been tested on linux.
let [clk_id, tp] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.clock_gettime(clk_id, tp)?;
this.write_scalar(result, dest)?;
}
// Threading // Threading
"pthread_condattr_setclock" => { "pthread_condattr_setclock" => {
let [attr, clock_id] = let [attr, clock_id] =

View file

@ -181,17 +181,25 @@ fn test_thread_local_errno() {
} }
/// Tests whether clock support exists at all /// Tests whether clock support exists at all
#[cfg(target_os = "linux")]
fn test_clocks() { fn test_clocks() {
let mut tp = std::mem::MaybeUninit::<libc::timespec>::uninit(); let mut tp = std::mem::MaybeUninit::<libc::timespec>::uninit();
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) };
assert_eq!(is_error, 0); 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()) }; let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) };
assert_eq!(is_error, 0); assert_eq!(is_error, 0);
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) }; #[cfg(target_os = "linux")]
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_COARSE, tp.as_mut_ptr()) };
assert_eq!(is_error, 0);
}
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
{
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_UPTIME_RAW, tp.as_mut_ptr()) };
assert_eq!(is_error, 0);
}
} }
fn test_posix_gettimeofday() { fn test_posix_gettimeofday() {
@ -293,11 +301,11 @@ fn main() {
test_thread_local_errno(); test_thread_local_errno();
test_isatty(); test_isatty();
test_clocks();
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
test_posix_fadvise(); test_posix_fadvise();
test_sync_file_range(); test_sync_file_range();
test_clocks();
} }
} }