use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use truce_core::wrapper::PluginCell;
struct Scratch {
counter: u64,
buf: Vec<u32>,
}
struct Gui {
opened: u64,
}
struct Instance {
audio: PluginCell<Scratch>,
gui: PluginCell<Gui>,
latency: AtomicU64,
}
#[cfg(miri)]
const BLOCKS: u64 = 60;
#[cfg(not(miri))]
const BLOCKS: u64 = 20_000;
#[test]
fn audio_cell_and_host_access_do_not_alias() {
let inst = Arc::new(Instance {
audio: PluginCell::new(Scratch {
counter: 0,
buf: vec![0; 8],
}),
gui: PluginCell::new(Gui { opened: 0 }),
latency: AtomicU64::new(0),
});
let stop = Arc::new(AtomicBool::new(false));
let host = {
let inst = Arc::clone(&inst);
let stop = Arc::clone(&stop);
std::thread::spawn(move || {
let mut last = 0u64;
while !stop.load(Ordering::Relaxed) {
inst.gui.enter().opened += 1;
last = last.max(inst.latency.load(Ordering::Relaxed));
std::thread::yield_now();
}
last
})
};
for block in 0..BLOCKS {
{
let mut scr = inst.audio.enter();
scr.counter += 1;
let len = scr.buf.len() as u64;
let n = usize::try_from(scr.counter % len).unwrap_or(0);
scr.buf[n] = scr.buf[n].wrapping_add(1);
}
inst.latency.store(block, Ordering::Relaxed);
std::thread::yield_now();
}
stop.store(true, Ordering::Relaxed);
host.join().expect("host thread panicked");
assert_eq!(inst.audio.enter().counter, BLOCKS);
assert!(inst.gui.enter().opened >= 1);
}