From e667ccb4594b5415626f18dbe34c1713b59e3941 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 23:22:42 -0400 Subject: [PATCH] test that futexes induce appropriate synchronization --- tests/pass/concurrency/linux-futex.rs | 32 +++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 2c60df1ee13..b65dd46d597 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -222,11 +222,17 @@ fn wait_wake_bitset() { t.join().unwrap(); } -const FREE: i32 = 0; -const HELD: i32 = 1; fn concurrent_wait_wake() { + const FREE: i32 = 0; + const HELD: i32 = 1; + static FUTEX: AtomicI32 = AtomicI32::new(0); - for _ in 0..20 { + static mut DATA: i32 = 0; + static WOKEN: AtomicI32 = AtomicI32::new(0); + + let rounds = 50; + for _ in 0..rounds { + unsafe { DATA = 0 }; // Reset // Suppose the main thread is holding a lock implemented using futex... FUTEX.store(HELD, Ordering::Relaxed); @@ -239,23 +245,41 @@ fn concurrent_wait_wake() { // the FUTEX is FREE != HELD and return without waiting // or we'll deadlock. unsafe { - libc::syscall( + let ret = libc::syscall( libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAIT, HELD, ptr::null::(), ); + if ret == 0 { + // We actually slept. And then woke up again. So we should be ordered-after + // what happened-before the FUTEX_WAKE. So this is not a race. + assert_eq!(DATA, 1); + // Also remember that this happened at least once. + WOKEN.fetch_add(1, Ordering::Relaxed); + } } }); + // Increase the chance that the other thread actually goes to sleep. + // (5 yields in a loop seem to make that happen around 40% of the time.) + for _ in 0..5 { + thread::yield_now(); + } FUTEX.store(FREE, Ordering::Relaxed); unsafe { + DATA = 1; libc::syscall(libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAKE, 1); } t.join().unwrap(); } + + // Make sure we got the interesting case (of having woken a thread) at least once, but not *each* time. + let woken = WOKEN.load(Ordering::Relaxed); + assert!(woken > 0 && woken < rounds); + //eprintln!("waking happened {woken} times"); } fn main() { -- 2.44.0