@@ -222,11 +222,17 @@ fn wait_wake_bitset() {
222
222
t. join ( ) . unwrap ( ) ;
223
223
}
224
224
225
- const FREE : i32 = 0 ;
226
- const HELD : i32 = 1 ;
227
225
fn concurrent_wait_wake ( ) {
226
+ const FREE : i32 = 0 ;
227
+ const HELD : i32 = 1 ;
228
+
228
229
static FUTEX : AtomicI32 = AtomicI32 :: new ( 0 ) ;
229
- for _ in 0 ..20 {
230
+ static mut DATA : i32 = 0 ;
231
+ static WOKEN : AtomicI32 = AtomicI32 :: new ( 0 ) ;
232
+
233
+ let rounds = 50 ;
234
+ for _ in 0 ..rounds {
235
+ unsafe { DATA = 0 } ; // Reset
230
236
// Suppose the main thread is holding a lock implemented using futex...
231
237
FUTEX . store ( HELD , Ordering :: Relaxed ) ;
232
238
@@ -239,23 +245,41 @@ fn concurrent_wait_wake() {
239
245
// the FUTEX is FREE != HELD and return without waiting
240
246
// or we'll deadlock.
241
247
unsafe {
242
- libc:: syscall (
248
+ let ret = libc:: syscall (
243
249
libc:: SYS_futex ,
244
250
& FUTEX as * const AtomicI32 ,
245
251
libc:: FUTEX_WAIT ,
246
252
HELD ,
247
253
ptr:: null :: < libc:: timespec > ( ) ,
248
254
) ;
255
+ if ret == 0 {
256
+ // We actually slept. And then woke up again. So we should be ordered-after
257
+ // what happened-before the FUTEX_WAKE. So this is not a race.
258
+ assert_eq ! ( DATA , 1 ) ;
259
+ // Also remember that this happened at least once.
260
+ WOKEN . fetch_add ( 1 , Ordering :: Relaxed ) ;
261
+ }
249
262
}
250
263
} ) ;
264
+ // Increase the chance that the other thread actually goes to sleep.
265
+ // (5 yields in a loop seem to make that happen around 40% of the time.)
266
+ for _ in 0 ..5 {
267
+ thread:: yield_now ( ) ;
268
+ }
251
269
252
270
FUTEX . store ( FREE , Ordering :: Relaxed ) ;
253
271
unsafe {
272
+ DATA = 1 ;
254
273
libc:: syscall ( libc:: SYS_futex , & FUTEX as * const AtomicI32 , libc:: FUTEX_WAKE , 1 ) ;
255
274
}
256
275
257
276
t. join ( ) . unwrap ( ) ;
258
277
}
278
+
279
+ // Make sure we got the interesting case (of having woken a thread) at least once, but not *each* time.
280
+ let woken = WOKEN . load ( Ordering :: Relaxed ) ;
281
+ assert ! ( woken > 0 && woken < rounds) ;
282
+ //eprintln!("waking happened {woken} times");
259
283
}
260
284
261
285
fn main ( ) {
0 commit comments