more spin-loop-tests
This commit is contained in:
parent
47745380cd
commit
34b359be1e
2 changed files with 59 additions and 8 deletions
|
|
@ -1,16 +1,17 @@
|
|||
// ignore-windows: Concurrency on Windows is not supported yet.
|
||||
|
||||
use std::thread;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::mpsc;
|
||||
use std::cell::Cell;
|
||||
|
||||
static FLAG: AtomicUsize = AtomicUsize::new(0);
|
||||
/// When a thread yields, Miri's scheduler used to pick the thread with the lowest ID
|
||||
/// that can run. IDs are assigned in thread creation order.
|
||||
/// This means we could make 2 threads infinitely ping-pong with each other while
|
||||
/// really there is a 3rd thread that we should schedule to make progress.
|
||||
fn two_player_ping_pong() {
|
||||
static FLAG: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
// When a thread yields, Miri's scheduler used to pick the thread with the lowest ID
|
||||
// that can run. IDs are assigned in thread creation order.
|
||||
// This means we could make 2 threads infinitely ping-pong with each other while
|
||||
// really there is a 3rd thread that we should schedule to make progress.
|
||||
|
||||
fn main() {
|
||||
let waiter1 = thread::spawn(|| {
|
||||
while FLAG.load(Ordering::Acquire) == 0 {
|
||||
// spin and wait
|
||||
|
|
@ -31,3 +32,51 @@ fn main() {
|
|||
waiter2.join().unwrap();
|
||||
progress.join().unwrap();
|
||||
}
|
||||
|
||||
/// Based on a test by @jethrogb.
|
||||
fn launcher() {
|
||||
static THREAD2_LAUNCHED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
for _ in 0..10 {
|
||||
let (tx, rx) = mpsc::sync_channel(0);
|
||||
THREAD2_LAUNCHED.store(false, Ordering::SeqCst);
|
||||
|
||||
let jh = thread::spawn(move || {
|
||||
struct RecvOnDrop(Cell<Option<mpsc::Receiver<()>>>);
|
||||
|
||||
impl Drop for RecvOnDrop {
|
||||
fn drop(&mut self) {
|
||||
let rx = self.0.take().unwrap();
|
||||
while !THREAD2_LAUNCHED.load(Ordering::SeqCst) {
|
||||
thread::yield_now();
|
||||
}
|
||||
rx.recv().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let tl_rx: RecvOnDrop = RecvOnDrop(Cell::new(None));
|
||||
tl_rx.0.set(Some(rx));
|
||||
});
|
||||
|
||||
let tx_clone = tx.clone();
|
||||
let jh2 = thread::spawn(move || {
|
||||
THREAD2_LAUNCHED.store(true, Ordering::SeqCst);
|
||||
jh.join().unwrap();
|
||||
tx_clone.send(()).expect_err(
|
||||
"Expecting channel to be closed because thread 1 TLS destructors must've run",
|
||||
);
|
||||
});
|
||||
|
||||
while !THREAD2_LAUNCHED.load(Ordering::SeqCst) {
|
||||
thread::yield_now();
|
||||
}
|
||||
thread::yield_now();
|
||||
tx.send(()).expect("Expecting channel to be live because thread 2 must block on join");
|
||||
jh2.join().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
two_player_ping_pong();
|
||||
launcher();
|
||||
}
|
||||
|
|
|
|||
2
tests/pass/concurrency/spin_loops.stderr
Normal file
2
tests/pass/concurrency/spin_loops.stderr
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
warning: thread support is experimental and incomplete: weak memory effects are not emulated.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue