@@ -17,73 +17,71 @@ pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Du
1717
1818impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
1919pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
20- fn clock_gettime (
21- & mut self ,
22- clk_id_op : & OpTy < ' tcx > ,
23- tp_op : & OpTy < ' tcx > ,
24- dest : & MPlaceTy < ' tcx > ,
25- ) -> InterpResult < ' tcx > {
20+ fn parse_clockid ( & self , clk_id : Scalar ) -> Option < TimeoutClock > {
2621 // This clock support is deliberately minimal because a lot of clock types have fiddly
2722 // properties (is it possible for Miri to be suspended independently of the host?). If you
2823 // have a use for another clock type, please open an issue.
24+ let this = self . eval_context_ref ( ) ;
2925
30- let this = self . eval_context_mut ( ) ;
31-
32- this. assert_target_os_is_unix ( "clock_gettime" ) ;
33- let clockid_t_size = this. libc_ty_layout ( "clockid_t" ) . size ;
34-
35- let clk_id = this. read_scalar ( clk_id_op) ?. to_int ( clockid_t_size) ?;
36- let tp = this. deref_pointer_as ( tp_op, this. libc_ty_layout ( "timespec" ) ) ?;
37-
38- let absolute_clocks;
39- let mut relative_clocks;
26+ // Portable names that exist everywhere.
27+ if clk_id == this. eval_libc ( "CLOCK_REALTIME" ) {
28+ return Some ( TimeoutClock :: RealTime ) ;
29+ } else if clk_id == this. eval_libc ( "CLOCK_MONOTONIC" ) {
30+ return Some ( TimeoutClock :: Monotonic ) ;
31+ }
4032
33+ // Some further platform-specific names we support.
4134 match this. tcx . sess . target . os . as_ref ( ) {
4235 "linux" | "freebsd" | "android" => {
43- // Linux, Android, and FreeBSD have two main kinds of clocks. REALTIME clocks return the actual time since the
44- // Unix epoch, including effects which may cause time to move backwards such as NTP.
4536 // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
46- // is just specified to be "faster and less precise", so we implement both the same way.
47- absolute_clocks = vec ! [
48- this. eval_libc( "CLOCK_REALTIME" ) . to_int( clockid_t_size) ?,
49- this. eval_libc( "CLOCK_REALTIME_COARSE" ) . to_int( clockid_t_size) ?,
50- ] ;
51- // The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are
52- // never allowed to go backwards. We don't need to do any additional monotonicity
53- // enforcement because std::time::Instant already guarantees that it is monotonic.
54- relative_clocks = vec ! [
55- this. eval_libc( "CLOCK_MONOTONIC" ) . to_int( clockid_t_size) ?,
56- this. eval_libc( "CLOCK_MONOTONIC_COARSE" ) . to_int( clockid_t_size) ?,
57- ] ;
37+ // is just specified to be "faster and less precise", so we treat it like normal
38+ // clocks.
39+ if clk_id == this. eval_libc ( "CLOCK_REALTIME_COARSE" ) {
40+ return Some ( TimeoutClock :: RealTime ) ;
41+ } else if clk_id == this. eval_libc ( "CLOCK_MONOTONIC_COARSE" ) {
42+ return Some ( TimeoutClock :: Monotonic ) ;
43+ }
5844 }
5945 "macos" => {
60- absolute_clocks = vec ! [ this. eval_libc( "CLOCK_REALTIME" ) . to_int( clockid_t_size) ?] ;
61- relative_clocks = vec ! [ this. eval_libc( "CLOCK_MONOTONIC" ) . to_int( clockid_t_size) ?] ;
6246 // `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but
6347 // that's not really something a program running inside Miri can tell, anyway.
6448 // We need to support it because std uses it.
65- relative_clocks. push ( this. eval_libc ( "CLOCK_UPTIME_RAW" ) . to_int ( clockid_t_size) ?) ;
66- }
67- "solaris" | "illumos" => {
68- // The REALTIME clock returns the actual time since the Unix epoch.
69- absolute_clocks = vec ! [ this. eval_libc( "CLOCK_REALTIME" ) . to_int( clockid_t_size) ?] ;
70- // MONOTONIC, in the other hand, is the high resolution, non-adjustable
71- // clock from an arbitrary time in the past.
72- // Note that the man page mentions HIGHRES but it is just
73- // an alias of MONOTONIC and the libc crate does not expose it anyway.
74- // https://docs.oracle.com/cd/E23824_01/html/821-1465/clock-gettime-3c.html
75- relative_clocks = vec ! [ this. eval_libc( "CLOCK_MONOTONIC" ) . to_int( clockid_t_size) ?] ;
49+ if clk_id == this. eval_libc ( "CLOCK_UPTIME_RAW" ) {
50+ return Some ( TimeoutClock :: Monotonic ) ;
51+ }
7652 }
77- target => throw_unsup_format ! ( "`clock_gettime` is not supported on target OS {target}" ) ,
53+ _ => { }
7854 }
7955
80- let duration = if absolute_clocks. contains ( & clk_id) {
81- this. check_no_isolation ( "`clock_gettime` with `REALTIME` clocks" ) ?;
82- system_time_to_duration ( & SystemTime :: now ( ) ) ?
83- } else if relative_clocks. contains ( & clk_id) {
84- this. machine . monotonic_clock . now ( ) . duration_since ( this. machine . monotonic_clock . epoch ( ) )
85- } else {
86- return this. set_last_error_and_return ( LibcError ( "EINVAL" ) , dest) ;
56+ None
57+ }
58+
59+ fn clock_gettime (
60+ & mut self ,
61+ clk_id_op : & OpTy < ' tcx > ,
62+ tp_op : & OpTy < ' tcx > ,
63+ dest : & MPlaceTy < ' tcx > ,
64+ ) -> InterpResult < ' tcx > {
65+ let this = self . eval_context_mut ( ) ;
66+
67+ this. assert_target_os_is_unix ( "clock_gettime" ) ;
68+
69+ let clk_id = this. read_scalar ( clk_id_op) ?;
70+ let tp = this. deref_pointer_as ( tp_op, this. libc_ty_layout ( "timespec" ) ) ?;
71+
72+ let duration = match this. parse_clockid ( clk_id) {
73+ Some ( TimeoutClock :: RealTime ) => {
74+ this. check_no_isolation ( "`clock_gettime` with `REALTIME` clocks" ) ?;
75+ system_time_to_duration ( & SystemTime :: now ( ) ) ?
76+ }
77+ Some ( TimeoutClock :: Monotonic ) =>
78+ this. machine
79+ . monotonic_clock
80+ . now ( )
81+ . duration_since ( this. machine . monotonic_clock . epoch ( ) ) ,
82+ None => {
83+ return this. set_last_error_and_return ( LibcError ( "EINVAL" ) , dest) ;
84+ }
8785 } ;
8886
8987 let tv_sec = duration. as_secs ( ) ;
0 commit comments