]> git.lizzy.rs Git - rust.git/blob - tests/run-pass/concurrency/linux-futex.rs
Auto merge of #2055 - RalfJung:rustup, r=RalfJung
[rust.git] / tests / run-pass / concurrency / linux-futex.rs
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::mem::MaybeUninit;
11 use std::ptr;
12 use std::thread;
13 use std::time::{Duration, Instant};
14
15 fn wake_nobody() {
16     let futex = 0;
17
18     // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
19     unsafe {
20         assert_eq!(libc::syscall(
21             libc::SYS_futex,
22             &futex as *const i32,
23             libc::FUTEX_WAKE,
24             1,
25         ), 0);
26     }
27
28     // Same, but without omitting the unused arguments.
29     unsafe {
30         assert_eq!(libc::syscall(
31             libc::SYS_futex,
32             &futex as *const i32,
33             libc::FUTEX_WAKE,
34             1,
35             ptr::null::<libc::timespec>(),
36             0usize,
37             0,
38         ), 0);
39     }
40 }
41
42 fn wake_dangling() {
43     let futex = Box::new(0);
44     let ptr: *const i32 = &*futex;
45     drop(futex);
46
47     // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
48     unsafe {
49         assert_eq!(libc::syscall(
50             libc::SYS_futex,
51             ptr,
52             libc::FUTEX_WAKE,
53             1,
54         ), 0);
55     }
56 }
57
58 fn wait_wrong_val() {
59     let futex: i32 = 123;
60
61     // Only wait if the futex value is 456.
62     unsafe {
63         assert_eq!(libc::syscall(
64             libc::SYS_futex,
65             &futex as *const i32,
66             libc::FUTEX_WAIT,
67             456,
68             ptr::null::<libc::timespec>(),
69         ), -1);
70         assert_eq!(*libc::__errno_location(), libc::EAGAIN);
71     }
72 }
73
74 fn wait_timeout() {
75     let start = Instant::now();
76
77     let futex: i32 = 123;
78
79     // Wait for 200ms, with nobody waking us up early.
80     unsafe {
81         assert_eq!(libc::syscall(
82             libc::SYS_futex,
83             &futex as *const i32,
84             libc::FUTEX_WAIT,
85             123,
86             &libc::timespec {
87                 tv_sec: 0,
88                 tv_nsec: 200_000_000,
89             },
90         ), -1);
91         assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
92     }
93
94     assert!((200..1000).contains(&start.elapsed().as_millis()));
95 }
96
97 fn wait_absolute_timeout() {
98     let start = Instant::now();
99
100     // Get the current monotonic timestamp as timespec.
101     let mut timeout = unsafe {
102         let mut now: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
103         assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, now.as_mut_ptr()), 0);
104         now.assume_init()
105     };
106
107     // Add 200ms.
108     timeout.tv_nsec += 200_000_000;
109     if timeout.tv_nsec > 1_000_000_000 {
110         timeout.tv_nsec -= 1_000_000_000;
111         timeout.tv_sec += 1;
112     }
113
114     let futex: i32 = 123;
115
116     // Wait for 200ms from now, with nobody waking us up early.
117     unsafe {
118         assert_eq!(libc::syscall(
119             libc::SYS_futex,
120             &futex as *const i32,
121             libc::FUTEX_WAIT_BITSET,
122             123,
123             &timeout,
124             0usize,
125             u32::MAX,
126         ), -1);
127         assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
128     }
129
130     assert!((200..1000).contains(&start.elapsed().as_millis()));
131 }
132
133 fn wait_wake() {
134     let start = Instant::now();
135
136     static FUTEX: i32 = 0;
137
138     thread::spawn(move || {
139         thread::sleep(Duration::from_millis(200));
140         unsafe {
141             assert_eq!(libc::syscall(
142                 libc::SYS_futex,
143                 &FUTEX as *const i32,
144                 libc::FUTEX_WAKE,
145                 10, // Wake up at most 10 threads.
146             ), 1); // Woken up one thread.
147         }
148     });
149
150     unsafe {
151         assert_eq!(libc::syscall(
152             libc::SYS_futex,
153             &FUTEX as *const i32,
154             libc::FUTEX_WAIT,
155             0,
156             ptr::null::<libc::timespec>(),
157         ), 0);
158     }
159
160     assert!((200..1000).contains(&start.elapsed().as_millis()));
161 }
162
163 fn wait_wake_bitset() {
164     let start = Instant::now();
165
166     static FUTEX: i32 = 0;
167
168     thread::spawn(move || {
169         thread::sleep(Duration::from_millis(200));
170         unsafe {
171             assert_eq!(libc::syscall(
172                 libc::SYS_futex,
173                 &FUTEX as *const i32,
174                 libc::FUTEX_WAKE_BITSET,
175                 10, // Wake up at most 10 threads.
176                 ptr::null::<libc::timespec>(),
177                 0usize,
178                 0b1001, // bitset
179             ), 0); // Didn't match any thread.
180         }
181         thread::sleep(Duration::from_millis(200));
182         unsafe {
183             assert_eq!(libc::syscall(
184                 libc::SYS_futex,
185                 &FUTEX as *const i32,
186                 libc::FUTEX_WAKE_BITSET,
187                 10, // Wake up at most 10 threads.
188                 ptr::null::<libc::timespec>(),
189                 0usize,
190                 0b0110, // bitset
191             ), 1); // Woken up one thread.
192         }
193     });
194
195     unsafe {
196         assert_eq!(libc::syscall(
197             libc::SYS_futex,
198             &FUTEX as *const i32,
199             libc::FUTEX_WAIT_BITSET,
200             0,
201             ptr::null::<libc::timespec>(),
202             0usize,
203             0b0100, // bitset
204         ), 0);
205     }
206
207     assert!((400..1000).contains(&start.elapsed().as_millis()));
208 }
209
210 fn main() {
211     wake_nobody();
212     wake_dangling();
213     wait_wrong_val();
214     wait_timeout();
215     wait_absolute_timeout();
216     wait_wake();
217     wait_wake_bitset();
218 }