use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::time::{Duration, Instant};
use go_lib::{chan::chan, go, select};
static ITERS: AtomicU64 = AtomicU64::new(0);
static STOP: AtomicBool = AtomicBool::new(false);
static WORKERS_DONE: AtomicU64 = AtomicU64::new(0);
fn select_rt(seed: u64, max_iters: u64) {
let mut x = seed | 1;
let mut iters = 0u64;
while !STOP.load(Ordering::Relaxed) && iters < max_iters {
iters += 1;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
let wait_us = 50 + (x % 500);
go_lib::run(move || {
let (a_tx, a_rx) = chan::<u64>(0);
let (b_tx, b_rx) = chan::<u64>(0);
let (c_tx, c_rx) = chan::<u64>(0);
for _ in 0..6 {
let a_rx = a_rx.clone();
let b_rx = b_rx.clone();
let c_rx = c_rx.clone();
go!(move || {
for _ in 0..64 {
let got = select! {
recv(a_rx) -> v => { v }
recv(b_rx) -> v => { v }
recv(c_rx) -> v => { v }
};
if got.is_none() {
break; }
}
});
}
for (k, tx) in [a_tx, b_tx, c_tx].into_iter().enumerate() {
go!(move || {
for i in 0..64u64 {
tx.send((k as u64) << 32 | i);
}
});
}
let t0 = Instant::now();
while t0.elapsed() < Duration::from_micros(wait_us) {
std::hint::spin_loop();
}
});
ITERS.fetch_add(1, Ordering::Relaxed);
}
WORKERS_DONE.fetch_add(1, Ordering::Relaxed);
}
fn main() {
let secs: u64 = std::env::args()
.nth(1)
.and_then(|s| s.parse().ok())
.unwrap_or(30);
let max_iters: u64 = std::env::args()
.nth(2)
.and_then(|s| s.parse().ok())
.unwrap_or(300);
const N_WORKERS: u64 = 8;
let mut handles = Vec::new();
for i in 0..N_WORKERS {
handles.push(std::thread::spawn(move || {
select_rt(0x9e3779b9 ^ (i + 1), max_iters)
}));
}
let start = Instant::now();
while start.elapsed() < Duration::from_secs(secs) {
std::thread::sleep(Duration::from_secs(1));
let elapsed = start.elapsed().as_secs();
let done = WORKERS_DONE.load(Ordering::Relaxed);
println!("[{elapsed:>3}s] iters: {}, workers done: {done}",
ITERS.load(Ordering::Relaxed));
if done == N_WORKERS {
break;
}
}
STOP.store(true, Ordering::Relaxed);
for h in handles {
h.join().unwrap();
}
println!("stress completed without crash");
}