Skip to content

Commit 47128fa

Browse files
committed
Add test for futex syscall.
1 parent 9d764c5 commit 47128fa

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed
+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Unfortunately, the test framework does not support 'only-linux',
2+
// so we need to ignore Windows and macOS instead.
3+
// ignore-macos: Uses Linux-only APIs
4+
// ignore-windows: Uses Linux-only APIs
5+
// compile-flags: -Zmiri-disable-isolation
6+
7+
#![feature(rustc_private)]
8+
extern crate libc;
9+
10+
use std::ptr;
11+
use std::thread;
12+
use std::time::{Duration, Instant};
13+
14+
fn wake_nobody() {
15+
let mut futex = 0;
16+
17+
// Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
18+
unsafe {
19+
assert_eq!(libc::syscall(
20+
libc::SYS_futex,
21+
&futex as *const i32,
22+
libc::FUTEX_WAKE,
23+
1,
24+
), 0);
25+
}
26+
27+
// Same, but without omitting the unused arguments.
28+
unsafe {
29+
assert_eq!(libc::syscall(
30+
libc::SYS_futex,
31+
&futex as *const i32,
32+
libc::FUTEX_WAKE,
33+
1,
34+
0,
35+
0,
36+
0,
37+
), 0);
38+
}
39+
}
40+
41+
fn wake_dangling() {
42+
let futex = Box::new(0);
43+
let ptr: *const i32 = &*futex;
44+
drop(futex);
45+
46+
// Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
47+
unsafe {
48+
assert_eq!(libc::syscall(
49+
libc::SYS_futex,
50+
ptr,
51+
libc::FUTEX_WAKE,
52+
1,
53+
), 0);
54+
}
55+
}
56+
57+
fn wait_wrong_val() {
58+
let mut futex: i32 = 123;
59+
60+
// Only wait if the futex value is 456.
61+
unsafe {
62+
assert_eq!(libc::syscall(
63+
libc::SYS_futex,
64+
&futex as *const i32,
65+
libc::FUTEX_WAIT,
66+
456,
67+
ptr::null::<libc::timespec>(),
68+
), -1);
69+
assert_eq!(*libc::__errno_location(), libc::EAGAIN);
70+
}
71+
}
72+
73+
fn wait_timeout() {
74+
let start = Instant::now();
75+
76+
let mut futex: i32 = 123;
77+
78+
// Wait for 200ms, with nobody waking us up early.
79+
unsafe {
80+
assert_eq!(libc::syscall(
81+
libc::SYS_futex,
82+
&futex as *const i32,
83+
libc::FUTEX_WAIT,
84+
123,
85+
&libc::timespec {
86+
tv_sec: 0,
87+
tv_nsec: 200_000_000,
88+
},
89+
), -1);
90+
assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
91+
}
92+
93+
assert!((200..500).contains(&start.elapsed().as_millis()));
94+
}
95+
96+
fn wait_wake() {
97+
let start = Instant::now();
98+
99+
static FUTEX: i32 = 0;
100+
101+
let t2 = thread::spawn(move || {
102+
thread::sleep(Duration::from_millis(200));
103+
unsafe {
104+
assert_eq!(libc::syscall(
105+
libc::SYS_futex,
106+
&FUTEX as *const i32,
107+
libc::FUTEX_WAKE,
108+
10, // Wake up at most 10 threads.
109+
), 1); // Woken up one thread.
110+
}
111+
});
112+
113+
unsafe {
114+
assert_eq!(libc::syscall(
115+
libc::SYS_futex,
116+
&FUTEX as *const i32,
117+
libc::FUTEX_WAIT,
118+
0,
119+
ptr::null::<libc::timespec>(),
120+
), 0);
121+
}
122+
123+
assert!((200..500).contains(&start.elapsed().as_millis()));
124+
}
125+
126+
fn main() {
127+
wake_nobody();
128+
wake_dangling();
129+
wait_wrong_val();
130+
wait_timeout();
131+
wait_wake();
132+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
warning: thread support is experimental. For example, Miri does not detect data races yet.
2+

0 commit comments

Comments
 (0)