Skip to content

Commit

Permalink
Add test for futex syscall.
Browse files Browse the repository at this point in the history
  • Loading branch information
m-ou-se committed Oct 3, 2020
1 parent 9d764c5 commit 47128fa
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 0 deletions.
132 changes: 132 additions & 0 deletions tests/run-pass/concurrency/linux-futex.rs
Original file line number Diff line number Diff line change
@@ -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::<libc::timespec>(),
), -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::<libc::timespec>(),
), 0);
}

assert!((200..500).contains(&start.elapsed().as_millis()));
}

fn main() {
wake_nobody();
wake_dangling();
wait_wrong_val();
wait_timeout();
wait_wake();
}
2 changes: 2 additions & 0 deletions tests/run-pass/concurrency/linux-futex.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
warning: thread support is experimental. For example, Miri does not detect data races yet.

0 comments on commit 47128fa

Please sign in to comment.