Skip to content

Commit

Permalink
more spin-loop-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Jun 5, 2022
1 parent 4774538 commit 0fac550
Showing 1 changed file with 57 additions and 8 deletions.
65 changes: 57 additions & 8 deletions tests/pass/concurrency/spin_loops.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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();
}

0 comments on commit 0fac550

Please sign in to comment.