@@ -9,7 +9,7 @@ struct LinuxFutex {
9
9
/// Implementation of the SYS_futex syscall.
10
10
/// `args` is the arguments *including* the syscall number.
11
11
pub fn futex < ' tcx > (
12
- this : & mut MiriInterpCx < ' tcx > ,
12
+ ecx : & mut MiriInterpCx < ' tcx > ,
13
13
args : & [ OpTy < ' tcx > ] ,
14
14
dest : & MPlaceTy < ' tcx > ,
15
15
) -> InterpResult < ' tcx > {
@@ -26,19 +26,19 @@ pub fn futex<'tcx>(
26
26
// The first three arguments (after the syscall number itself) are the same to all futex operations:
27
27
// (int *addr, int op, int val).
28
28
// We checked above that these definitely exist.
29
- let addr = this . read_pointer ( addr) ?;
30
- let op = this . read_scalar ( op) ?. to_i32 ( ) ?;
31
- let val = this . read_scalar ( val) ?. to_i32 ( ) ?;
29
+ let addr = ecx . read_pointer ( addr) ?;
30
+ let op = ecx . read_scalar ( op) ?. to_i32 ( ) ?;
31
+ let val = ecx . read_scalar ( val) ?. to_i32 ( ) ?;
32
32
33
33
// This is a vararg function so we have to bring our own type for this pointer.
34
- let addr = this . ptr_to_mplace ( addr, this . machine . layouts . i32 ) ;
34
+ let addr = ecx . ptr_to_mplace ( addr, ecx . machine . layouts . i32 ) ;
35
35
36
- let futex_private = this . eval_libc_i32 ( "FUTEX_PRIVATE_FLAG" ) ;
37
- let futex_wait = this . eval_libc_i32 ( "FUTEX_WAIT" ) ;
38
- let futex_wait_bitset = this . eval_libc_i32 ( "FUTEX_WAIT_BITSET" ) ;
39
- let futex_wake = this . eval_libc_i32 ( "FUTEX_WAKE" ) ;
40
- let futex_wake_bitset = this . eval_libc_i32 ( "FUTEX_WAKE_BITSET" ) ;
41
- let futex_realtime = this . eval_libc_i32 ( "FUTEX_CLOCK_REALTIME" ) ;
36
+ let futex_private = ecx . eval_libc_i32 ( "FUTEX_PRIVATE_FLAG" ) ;
37
+ let futex_wait = ecx . eval_libc_i32 ( "FUTEX_WAIT" ) ;
38
+ let futex_wait_bitset = ecx . eval_libc_i32 ( "FUTEX_WAIT_BITSET" ) ;
39
+ let futex_wake = ecx . eval_libc_i32 ( "FUTEX_WAKE" ) ;
40
+ let futex_wake_bitset = ecx . eval_libc_i32 ( "FUTEX_WAKE_BITSET" ) ;
41
+ let futex_realtime = ecx . eval_libc_i32 ( "FUTEX_CLOCK_REALTIME" ) ;
42
42
43
43
// FUTEX_PRIVATE enables an optimization that stops it from working across processes.
44
44
// Miri doesn't support that anyway, so we ignore that flag.
@@ -57,31 +57,31 @@ pub fn futex<'tcx>(
57
57
let ( timeout, bitset) = if wait_bitset {
58
58
let [ _, _, _, _, timeout, uaddr2, bitset] =
59
59
check_min_arg_count ( "`syscall(SYS_futex, FUTEX_WAIT_BITSET, ...)`" , args) ?;
60
- let _timeout = this . read_pointer ( timeout) ?;
61
- let _uaddr2 = this . read_pointer ( uaddr2) ?;
62
- ( timeout, this . read_scalar ( bitset) ?. to_u32 ( ) ?)
60
+ let _timeout = ecx . read_pointer ( timeout) ?;
61
+ let _uaddr2 = ecx . read_pointer ( uaddr2) ?;
62
+ ( timeout, ecx . read_scalar ( bitset) ?. to_u32 ( ) ?)
63
63
} else {
64
64
let [ _, _, _, _, timeout] =
65
65
check_min_arg_count ( "`syscall(SYS_futex, FUTEX_WAIT, ...)`" , args) ?;
66
66
( timeout, u32:: MAX )
67
67
} ;
68
68
69
69
if bitset == 0 {
70
- return this . set_last_error_and_return ( LibcError ( "EINVAL" ) , dest) ;
70
+ return ecx . set_last_error_and_return ( LibcError ( "EINVAL" ) , dest) ;
71
71
}
72
72
73
- let timeout = this . deref_pointer_as ( timeout, this . libc_ty_layout ( "timespec" ) ) ?;
74
- let timeout = if this . ptr_is_null ( timeout. ptr ( ) ) ? {
73
+ let timeout = ecx . deref_pointer_as ( timeout, ecx . libc_ty_layout ( "timespec" ) ) ?;
74
+ let timeout = if ecx . ptr_is_null ( timeout. ptr ( ) ) ? {
75
75
None
76
76
} else {
77
- let duration = match this . read_timespec ( & timeout) ? {
77
+ let duration = match ecx . read_timespec ( & timeout) ? {
78
78
Some ( duration) => duration,
79
79
None => {
80
- return this . set_last_error_and_return ( LibcError ( "EINVAL" ) , dest) ;
80
+ return ecx . set_last_error_and_return ( LibcError ( "EINVAL" ) , dest) ;
81
81
}
82
82
} ;
83
83
let timeout_clock = if op & futex_realtime == futex_realtime {
84
- this . check_no_isolation (
84
+ ecx . check_no_isolation (
85
85
"`futex` syscall with `op=FUTEX_WAIT` and non-null timeout with `FUTEX_CLOCK_REALTIME`" ,
86
86
) ?;
87
87
TimeoutClock :: RealTime
@@ -139,36 +139,36 @@ pub fn futex<'tcx>(
139
139
//
140
140
// Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to
141
141
// do anything special to guarantee fence-load-comparison atomicity.
142
- this . atomic_fence ( AtomicFenceOrd :: SeqCst ) ?;
142
+ ecx . atomic_fence ( AtomicFenceOrd :: SeqCst ) ?;
143
143
// Read an `i32` through the pointer, regardless of any wrapper types.
144
144
// It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
145
145
// We do an acquire read -- it only seems reasonable that if we observe a value here, we
146
146
// actually establish an ordering with that value.
147
- let futex_val = this . read_scalar_atomic ( & addr, AtomicReadOrd :: Acquire ) ?. to_i32 ( ) ?;
147
+ let futex_val = ecx . read_scalar_atomic ( & addr, AtomicReadOrd :: Acquire ) ?. to_i32 ( ) ?;
148
148
if val == futex_val {
149
149
// The value still matches, so we block the thread and make it wait for FUTEX_WAKE.
150
150
151
151
// This cannot fail since we already did an atomic acquire read on that pointer.
152
152
// Acquire reads are only allowed on mutable memory.
153
- let futex_ref = this
153
+ let futex_ref = ecx
154
154
. get_sync_or_init ( addr. ptr ( ) , |_| LinuxFutex { futex : Default :: default ( ) } )
155
155
. unwrap ( )
156
156
. futex
157
157
. clone ( ) ;
158
158
159
- this . futex_wait (
159
+ ecx . futex_wait (
160
160
futex_ref,
161
161
bitset,
162
162
timeout,
163
- Scalar :: from_target_isize ( 0 , this ) , // retval_succ
164
- Scalar :: from_target_isize ( -1 , this ) , // retval_timeout
163
+ Scalar :: from_target_isize ( 0 , ecx ) , // retval_succ
164
+ Scalar :: from_target_isize ( -1 , ecx ) , // retval_timeout
165
165
dest. clone ( ) ,
166
166
LibcError ( "ETIMEDOUT" ) , // errno_timeout
167
167
) ;
168
168
} else {
169
169
// The futex value doesn't match the expected value, so we return failure
170
170
// right away without sleeping: -1 and errno set to EAGAIN.
171
- return this . set_last_error_and_return ( LibcError ( "EAGAIN" ) , dest) ;
171
+ return ecx . set_last_error_and_return ( LibcError ( "EAGAIN" ) , dest) ;
172
172
}
173
173
}
174
174
// FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
@@ -179,42 +179,42 @@ pub fn futex<'tcx>(
179
179
// Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up.
180
180
op if op == futex_wake || op == futex_wake_bitset => {
181
181
let Some ( futex_ref) =
182
- this . get_sync_or_init ( addr. ptr ( ) , |_| LinuxFutex { futex : Default :: default ( ) } )
182
+ ecx . get_sync_or_init ( addr. ptr ( ) , |_| LinuxFutex { futex : Default :: default ( ) } )
183
183
else {
184
184
// No AllocId, or no live allocation at that AllocId.
185
185
// Return an error code. (That seems nicer than silently doing something non-intuitive.)
186
186
// This means that if an address gets reused by a new allocation,
187
187
// we'll use an independent futex queue for this... that seems acceptable.
188
- return this . set_last_error_and_return ( LibcError ( "EFAULT" ) , dest) ;
188
+ return ecx . set_last_error_and_return ( LibcError ( "EFAULT" ) , dest) ;
189
189
} ;
190
190
let futex_ref = futex_ref. futex . clone ( ) ;
191
191
192
192
let bitset = if op == futex_wake_bitset {
193
193
let [ _, _, _, _, timeout, uaddr2, bitset] =
194
194
check_min_arg_count ( "`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`" , args) ?;
195
- let _timeout = this . read_pointer ( timeout) ?;
196
- let _uaddr2 = this . read_pointer ( uaddr2) ?;
197
- this . read_scalar ( bitset) ?. to_u32 ( ) ?
195
+ let _timeout = ecx . read_pointer ( timeout) ?;
196
+ let _uaddr2 = ecx . read_pointer ( uaddr2) ?;
197
+ ecx . read_scalar ( bitset) ?. to_u32 ( ) ?
198
198
} else {
199
199
u32:: MAX
200
200
} ;
201
201
if bitset == 0 {
202
- return this . set_last_error_and_return ( LibcError ( "EINVAL" ) , dest) ;
202
+ return ecx . set_last_error_and_return ( LibcError ( "EINVAL" ) , dest) ;
203
203
}
204
204
// Together with the SeqCst fence in futex_wait, this makes sure that futex_wait
205
205
// will see the latest value on addr which could be changed by our caller
206
206
// before doing the syscall.
207
- this . atomic_fence ( AtomicFenceOrd :: SeqCst ) ?;
207
+ ecx . atomic_fence ( AtomicFenceOrd :: SeqCst ) ?;
208
208
let mut n = 0 ;
209
209
#[ expect( clippy:: arithmetic_side_effects) ]
210
210
for _ in 0 ..val {
211
- if this . futex_wake ( & futex_ref, bitset) ? {
211
+ if ecx . futex_wake ( & futex_ref, bitset) ? {
212
212
n += 1 ;
213
213
} else {
214
214
break ;
215
215
}
216
216
}
217
- this . write_scalar ( Scalar :: from_target_isize ( n, this ) , dest) ?;
217
+ ecx . write_scalar ( Scalar :: from_target_isize ( n, ecx ) , dest) ?;
218
218
}
219
219
op => throw_unsup_format ! ( "Miri does not support `futex` syscall with op={}" , op) ,
220
220
}
0 commit comments