diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs new file mode 100644 index 0000000000..e78577bf2d --- /dev/null +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -0,0 +1,132 @@ +// Unfortunately, the test framework does not support 'only-linux', +// so we need to ignore Windows and macOS instead. +// ignore-macos: Uses Linux-only APIs +// ignore-windows: Uses Linux-only APIs +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] +extern crate libc; + +use std::ptr; +use std::thread; +use std::time::{Duration, Instant}; + +fn wake_nobody() { + let mut futex = 0; + + // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAKE, + 1, + ), 0); + } + + // Same, but without omitting the unused arguments. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAKE, + 1, + 0, + 0, + 0, + ), 0); + } +} + +fn wake_dangling() { + let futex = Box::new(0); + let ptr: *const i32 = &*futex; + drop(futex); + + // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + ptr, + libc::FUTEX_WAKE, + 1, + ), 0); + } +} + +fn wait_wrong_val() { + let mut futex: i32 = 123; + + // Only wait if the futex value is 456. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT, + 456, + ptr::null::(), + ), -1); + assert_eq!(*libc::__errno_location(), libc::EAGAIN); + } +} + +fn wait_timeout() { + let start = Instant::now(); + + let mut futex: i32 = 123; + + // Wait for 200ms, with nobody waking us up early. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT, + 123, + &libc::timespec { + tv_sec: 0, + tv_nsec: 200_000_000, + }, + ), -1); + assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); + } + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn wait_wake() { + let start = Instant::now(); + + static FUTEX: i32 = 0; + + let t2 = thread::spawn(move || { + thread::sleep(Duration::from_millis(200)); + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE, + 10, // Wake up at most 10 threads. + ), 1); // Woken up one thread. + } + }); + + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAIT, + 0, + ptr::null::(), + ), 0); + } + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn main() { + wake_nobody(); + wake_dangling(); + wait_wrong_val(); + wait_timeout(); + wait_wake(); +} diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/run-pass/concurrency/linux-futex.stderr new file mode 100644 index 0000000000..2dbfb7721d --- /dev/null +++ b/tests/run-pass/concurrency/linux-futex.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. +