use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::JoinHandle;
use std::time::Duration;
use anyhow::Result;
use wasmtime::{Config, Engine, InstanceAllocationStrategy, PoolingAllocationConfig};
const TRUSTED_POOL_SLOTS: usize = 256;
pub(crate) const TRUSTED_POOL_MAX: usize = TRUSTED_POOL_SLOTS;
pub(crate) enum Allocation {
Pooling,
OnDemand,
}
pub(crate) fn build_engine(alloc: Allocation) -> Result<Engine> {
let mut config = Config::new();
config.wasm_component_model(true);
#[cfg(any(
feature = "outbound-http",
feature = "outbound-tcp",
feature = "fat-guest"
))]
config.wasm_component_model_async(true);
config.epoch_interruption(true);
if let Allocation::Pooling = alloc {
let mut pool = PoolingAllocationConfig::default();
#[cfg(not(feature = "instruction-bench"))]
let slots = TRUSTED_POOL_SLOTS as u32;
#[cfg(feature = "instruction-bench")]
let slots = 4u32;
pool.total_memories(slots);
pool.total_tables(slots);
pool.total_core_instances(slots);
pool.total_component_instances(slots);
pool.max_memory_size(64 << 20); config.allocation_strategy(InstanceAllocationStrategy::Pooling(pool));
}
Ok(Engine::new(&config)?)
}
const EPOCH_TICK: Duration = Duration::from_millis(1);
pub(crate) struct EpochTicker {
stop: Arc<AtomicBool>,
handle: Option<JoinHandle<()>>,
}
impl EpochTicker {
pub(crate) fn spawn(engines: Vec<Engine>) -> Self {
let stop = Arc::new(AtomicBool::new(false));
let flag = stop.clone();
let handle = std::thread::spawn(move || {
while !flag.load(Ordering::Relaxed) {
std::thread::sleep(EPOCH_TICK);
for e in &engines {
e.increment_epoch();
}
}
});
Self {
stop,
handle: Some(handle),
}
}
}
impl Drop for EpochTicker {
fn drop(&mut self) {
self.stop.store(true, Ordering::Relaxed);
if let Some(h) = self.handle.take() {
let _ = h.join();
}
}
}