use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, OnceLock};
use std::time::Duration;
use wasmtime::*;
pub const EPOCH_TICK_MS: u64 = 10;
static SHARED: OnceLock<SharedEngines> = OnceLock::new();
struct SharedEngines {
fast: Engine,
guarded: Engine,
epoch_counter: Arc<AtomicU64>,
}
fn base_config() -> Config {
let mut cfg = Config::new();
cfg.parallel_compilation(true);
#[cfg(debug_assertions)]
{
cfg.strategy(Strategy::Winch);
}
#[cfg(not(debug_assertions))]
{
cfg.cranelift_opt_level(OptLevel::Speed);
}
cfg
}
impl SharedEngines {
fn new() -> Self {
let fast = Engine::new(&base_config()).expect("failed to create fast wasmtime Engine");
let mut guarded_cfg = base_config();
guarded_cfg.epoch_interruption(true);
let guarded = Engine::new(&guarded_cfg).expect("failed to create guarded wasmtime Engine");
let epoch_counter = Arc::new(AtomicU64::new(0));
let counter = epoch_counter.clone();
let engine_clone = guarded.clone();
std::thread::Builder::new()
.name("surrealism-epoch-ticker".into())
.spawn(move || {
loop {
std::thread::sleep(Duration::from_millis(EPOCH_TICK_MS));
counter.fetch_add(1, Ordering::Release);
engine_clone.increment_epoch();
}
})
.expect("failed to spawn epoch ticker thread");
Self {
fast,
guarded,
epoch_counter,
}
}
}
pub struct EngineHandle {
engine: Engine,
epoch_counter: Arc<AtomicU64>,
guarded: bool,
}
impl EngineHandle {
pub fn engine(&self) -> &Engine {
&self.engine
}
pub fn epoch_counter(&self) -> &Arc<AtomicU64> {
&self.epoch_counter
}
pub fn is_guarded(&self) -> bool {
self.guarded
}
}
pub fn shared_engine(guarded: bool) -> EngineHandle {
let shared = SHARED.get_or_init(SharedEngines::new);
let engine = if guarded {
shared.guarded.clone()
} else {
shared.fast.clone()
};
EngineHandle {
engine,
epoch_counter: shared.epoch_counter.clone(),
guarded,
}
}