Skip to content

Commit ab88ba4

Browse files
committed
Auto merge of rust-lang#2270 - RalfJung:futex-ordering, r=RalfJung
test that futexes induce appropriate synchronization This fails when I remove the `validate_lock_acquire` or `validate_lock_release` from `futex_wake`. So finally we got those code paths actually covered in tests. :)
2 parents 4e67b63 + e667ccb commit ab88ba4

File tree

1 file changed

+28
-4
lines changed

1 file changed

+28
-4
lines changed

tests/pass/concurrency/linux-futex.rs

+28-4
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,17 @@ fn wait_wake_bitset() {
222222
t.join().unwrap();
223223
}
224224

225-
const FREE: i32 = 0;
226-
const HELD: i32 = 1;
227225
fn concurrent_wait_wake() {
226+
const FREE: i32 = 0;
227+
const HELD: i32 = 1;
228+
228229
static FUTEX: AtomicI32 = AtomicI32::new(0);
229-
for _ in 0..20 {
230+
static mut DATA: i32 = 0;
231+
static WOKEN: AtomicI32 = AtomicI32::new(0);
232+
233+
let rounds = 50;
234+
for _ in 0..rounds {
235+
unsafe { DATA = 0 }; // Reset
230236
// Suppose the main thread is holding a lock implemented using futex...
231237
FUTEX.store(HELD, Ordering::Relaxed);
232238

@@ -239,23 +245,41 @@ fn concurrent_wait_wake() {
239245
// the FUTEX is FREE != HELD and return without waiting
240246
// or we'll deadlock.
241247
unsafe {
242-
libc::syscall(
248+
let ret = libc::syscall(
243249
libc::SYS_futex,
244250
&FUTEX as *const AtomicI32,
245251
libc::FUTEX_WAIT,
246252
HELD,
247253
ptr::null::<libc::timespec>(),
248254
);
255+
if ret == 0 {
256+
// We actually slept. And then woke up again. So we should be ordered-after
257+
// what happened-before the FUTEX_WAKE. So this is not a race.
258+
assert_eq!(DATA, 1);
259+
// Also remember that this happened at least once.
260+
WOKEN.fetch_add(1, Ordering::Relaxed);
261+
}
249262
}
250263
});
264+
// Increase the chance that the other thread actually goes to sleep.
265+
// (5 yields in a loop seem to make that happen around 40% of the time.)
266+
for _ in 0..5 {
267+
thread::yield_now();
268+
}
251269

252270
FUTEX.store(FREE, Ordering::Relaxed);
253271
unsafe {
272+
DATA = 1;
254273
libc::syscall(libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAKE, 1);
255274
}
256275

257276
t.join().unwrap();
258277
}
278+
279+
// Make sure we got the interesting case (of having woken a thread) at least once, but not *each* time.
280+
let woken = WOKEN.load(Ordering::Relaxed);
281+
assert!(woken > 0 && woken < rounds);
282+
//eprintln!("waking happened {woken} times");
259283
}
260284

261285
fn main() {

0 commit comments

Comments
 (0)