@@ -36,6 +36,7 @@ pub fn futex<'tcx>(
36
36
37
37
let futex_private = this. eval_libc_i32 ( "FUTEX_PRIVATE_FLAG" ) ?;
38
38
let futex_wait = this. eval_libc_i32 ( "FUTEX_WAIT" ) ?;
39
+ let futex_wait_bitset = this. eval_libc_i32 ( "FUTEX_WAIT_BITSET" ) ?;
39
40
let futex_wake = this. eval_libc_i32 ( "FUTEX_WAKE" ) ?;
40
41
let futex_realtime = this. eval_libc_i32 ( "FUTEX_CLOCK_REALTIME" ) ?;
41
42
@@ -45,12 +46,32 @@ pub fn futex<'tcx>(
45
46
// FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout)
46
47
// Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address,
47
48
// or *timeout expires. `timeout == null` for an infinite timeout.
48
- op if op & !futex_realtime == futex_wait => {
49
- if args. len ( ) < 5 {
50
- throw_ub_format ! (
51
- "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5" ,
52
- args. len( )
53
- ) ;
49
+ //
50
+ // FUTEX_WAIT_BITSET: (int *addr, int op = FUTEX_WAIT_BITSET, int val, const timespec *timeout, int *_ignored, unsigned int bitset)
51
+ // When bitset is u32::MAX, this is identical to FUTEX_WAIT, except the timeout is absolute rather than relative.
52
+ op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => {
53
+ let wait_bitset = op & !futex_realtime == futex_wait_bitset;
54
+
55
+ if wait_bitset {
56
+ if args. len ( ) != 7 {
57
+ throw_ub_format ! (
58
+ "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected 7" ,
59
+ args. len( )
60
+ ) ;
61
+ }
62
+
63
+ let bitset = this. read_scalar ( & args[ 6 ] ) ?. to_u32 ( ) ?;
64
+
65
+ if bitset != u32:: MAX {
66
+ throw_unsup_format ! ( "Miri does not support `futex` syscall with `op=FUTEX_WAIT_BITSET` with a bitset other than UINT_MAX" ) ;
67
+ }
68
+ } else {
69
+ if args. len ( ) < 5 {
70
+ throw_ub_format ! (
71
+ "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5" ,
72
+ args. len( )
73
+ ) ;
74
+ }
54
75
}
55
76
56
77
// `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!).
@@ -70,10 +91,20 @@ pub fn futex<'tcx>(
70
91
return Ok ( ( ) ) ;
71
92
}
72
93
} ;
73
- Some ( if op & futex_realtime != 0 {
74
- Time :: RealTime ( SystemTime :: now ( ) . checked_add ( duration) . unwrap ( ) )
94
+ Some ( if wait_bitset {
95
+ // FUTEX_WAIT_BITSET uses an absolute timestamp.
96
+ if op & futex_realtime != 0 {
97
+ Time :: RealTime ( SystemTime :: UNIX_EPOCH . checked_add ( duration) . unwrap ( ) )
98
+ } else {
99
+ Time :: Monotonic ( this. machine . time_anchor . checked_add ( duration) . unwrap ( ) )
100
+ }
75
101
} else {
76
- Time :: Monotonic ( Instant :: now ( ) . checked_add ( duration) . unwrap ( ) )
102
+ // FUTEX_WAIT uses a relative timestamp.
103
+ if op & futex_realtime != 0 {
104
+ Time :: RealTime ( SystemTime :: now ( ) . checked_add ( duration) . unwrap ( ) )
105
+ } else {
106
+ Time :: Monotonic ( Instant :: now ( ) . checked_add ( duration) . unwrap ( ) )
107
+ }
77
108
} )
78
109
} ;
79
110
// Check the pointer for alignment and validity.
0 commit comments