Skip to content

Commit ec84a22

Browse files
committed
MIRI add clock_nanosleep support
This is intended to support the std's new sleep_until. Only the clocks REALTIME and MONOTONIC are supported. The first because it was trivial to add the second as its needed for sleep_until. Only passing no flags or passing only TIMER_ABSTIME is supported. If an unsupported flags or clocks are passed this implementation panics.
1 parent e69a490 commit ec84a22

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

library/std/src/sys/pal/unix/thread.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ impl Thread {
297297
}
298298

299299
// Any unix that has clock_nanosleep
300+
// If this list changes update the MIRI chock_nanosleep shim
300301
#[cfg(any(
301302
target_os = "freebsd",
302303
target_os = "netbsd",

src/tools/miri/src/shims/time.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,71 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
362362
interp_ok(Scalar::from_i32(0))
363363
}
364364

365+
fn clock_nanosleep(
366+
&mut self,
367+
clock_id: &OpTy<'tcx>,
368+
flags: &OpTy<'tcx>,
369+
req_op: &OpTy<'tcx>,
370+
_rem: &OpTy<'tcx>, // Signal handlers are not supported, so rem will never be written to.
371+
) -> InterpResult<'tcx, Scalar> {
372+
let this = self.eval_context_mut();
373+
374+
let clock_id: libc::clockid_t = this.read_scalar(clock_id)?.to_i32()?;
375+
match clock_id {
376+
libc::CLOCK_MONOTONIC => (),
377+
libc::CLOCK_REALTIME
378+
| libc::CLOCK_TAI
379+
| libc::CLOCK_BOOTTIME
380+
| libc::CLOCK_PROCESS_CPUTIME_ID => {
381+
// The standard lib through sleep_until only needs CLOCK_MONOTONIC
382+
panic!("MIRI only supports CLOCK_MONOTONIC for clock_nanosleep")
383+
}
384+
_other => return this.set_last_error_and_return_i32(LibcError("EINVAL")),
385+
}
386+
387+
let req = this.deref_pointer_as(req_op, this.libc_ty_layout("timespec"))?;
388+
let duration = match this.read_timespec(&req)? {
389+
Some(duration) => duration,
390+
None => {
391+
return this.set_last_error_and_return_i32(LibcError("EINVAL"));
392+
}
393+
};
394+
395+
let flags: libc::c_int = this.read_scalar(flags)?.to_i32()?;
396+
if flags == 0 {
397+
this.block_thread(
398+
BlockReason::Sleep,
399+
Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)),
400+
callback!(
401+
@capture<'tcx> {}
402+
|_this, unblock: UnblockKind| {
403+
assert_eq!(unblock, UnblockKind::TimedOut);
404+
interp_ok(())
405+
}
406+
),
407+
);
408+
interp_ok(Scalar::from_i32(0))
409+
} else if flags == libc::TIMER_ABSTIME {
410+
this.block_thread(
411+
BlockReason::Sleep,
412+
Some((TimeoutClock::Monotonic, TimeoutAnchor::Absolute, duration)),
413+
// PR Author review note: no idea what this does, I copied it
414+
// form nanosleep, please check carefully if it is correct
415+
callback!(
416+
@capture<'tcx> {}
417+
|_this, unblock: UnblockKind| {
418+
assert_eq!(unblock, UnblockKind::TimedOut);
419+
interp_ok(())
420+
}
421+
),
422+
);
423+
interp_ok(Scalar::from_i32(0))
424+
} else {
425+
// The standard lib through sleep_until only needs TIMER_ABSTIME
426+
panic!("MIRI only supports no flags (0) or flag TIMER_ABSTIME for clock_nanosleep")
427+
}
428+
}
429+
365430
#[allow(non_snake_case)]
366431
fn Sleep(&mut self, timeout: &OpTy<'tcx>) -> InterpResult<'tcx> {
367432
let this = self.eval_context_mut();

src/tools/miri/src/shims/unix/foreign_items.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,28 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
967967
let result = this.nanosleep(req, rem)?;
968968
this.write_scalar(result, dest)?;
969969
}
970+
"clock_nanosleep" => {
971+
// Currently this function does not exist on all Unixes, e.g. on macOS.
972+
this.check_target_os(
973+
&[
974+
"freebsd",
975+
"netbsd",
976+
"linux",
977+
"android",
978+
"solaris",
979+
"illumos",
980+
"dragonfly",
981+
"hurd",
982+
"fuchsia",
983+
"vxworks",
984+
],
985+
link_name,
986+
)?;
987+
let [clock_id, flags, req, rem] =
988+
this.check_shim(abi, CanonAbi::C, link_name, args)?;
989+
let result = this.clock_nanosleep(clock_id, flags, req, rem)?;
990+
this.write_scalar(result, dest)?;
991+
}
970992
"sched_getaffinity" => {
971993
// Currently this function does not exist on all Unixes, e.g. on macOS.
972994
this.check_target_os(&["linux", "freebsd", "android"], link_name)?;

0 commit comments

Comments
 (0)