use std::thread;
use std::time::Duration;
use examples_common::get_wasm_module_path;
use hyperlight_wasm::{HyperlightError, Result, SandboxBuilder};
fn get_time_since_boot_microsecond() -> Result<i64> {
let res = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)?
.as_micros();
i64::try_from(res).map_err(HyperlightError::IntConversionFailure)
}
fn main() -> Result<()> {
println!("=== Hyperlight-Wasm Interruption Example ===\n");
let mut sandbox = SandboxBuilder::new().build()?;
sandbox.register(
"GetTimeSinceBootMicrosecond",
get_time_since_boot_microsecond,
)?;
let wasm_sandbox = sandbox.load_runtime()?;
let mod_path = get_wasm_module_path("RunWasm.aot")?;
let mut loaded = wasm_sandbox.load_module(mod_path)?;
println!("1. Sandbox created and module loaded");
assert!(!loaded.is_poisoned()?);
println!(" is_poisoned: {}", loaded.is_poisoned()?);
let snapshot = loaded.snapshot()?;
println!("2. Snapshot taken for later recovery\n");
let interrupt = loaded.interrupt_handle()?;
println!("3. Interrupt handle obtained\n");
println!("4. Starting long-running guest function...");
println!(" (A background thread will interrupt it after 1 second)\n");
thread::spawn(move || {
thread::sleep(Duration::from_secs(1));
println!(" [Background thread] Calling interrupt.kill()...");
interrupt.kill();
});
let result = loaded.call_guest_function::<i32>("KeepCPUBusy", 100000i32);
match result {
Ok(_) => panic!(" Guest function completed (unexpected!)"),
Err(HyperlightError::ExecutionCanceledByHost()) => {
println!(" Guest function was interrupted (ExecutionCanceledByHost)");
}
Err(e) => panic!(" Unexpected error: {:?}", e),
}
println!("\n5. Checking sandbox state after interruption:");
println!(" is_poisoned: {}", loaded.is_poisoned()?);
println!("\n6. Attempting to call guest function on poisoned sandbox...");
let result = loaded.call_guest_function::<i32>("CalcFib", 10i32);
match result {
Ok(_) => panic!(" Call succeeded (unexpected!)"),
Err(HyperlightError::PoisonedSandbox) => {
println!(" Call failed with PoisonedSandbox error (expected)");
}
Err(e) => panic!(" Unexpected error: {:?}", e),
}
println!("\n7. Recovering sandbox using restore()...");
loaded.restore(snapshot.clone())?;
assert!(!loaded.is_poisoned()?);
println!(" is_poisoned after restore: {}", loaded.is_poisoned()?);
println!("\n8. Calling guest function after recovery...");
let result: i32 = loaded.call_guest_function("CalcFib", 10i32)?;
println!(" CalcFib(10) returned: {} (expected 55)", result);
println!("\n9. Demonstrating unload_module recovery...");
let interrupt = loaded.interrupt_handle()?;
thread::spawn(move || {
thread::sleep(Duration::from_millis(500));
interrupt.kill();
});
let _ = loaded.call_guest_function::<i32>("KeepCPUBusy", 100000i32);
assert!(loaded.is_poisoned()?);
println!(" Sandbox poisoned again {}", loaded.is_poisoned()?);
let wasm_sandbox = loaded.unload_module()?;
println!(" Module unloaded (this calls restore internally)");
let hello_path = get_wasm_module_path("HelloWorld.aot")?;
let mut new_loaded = wasm_sandbox.load_module(hello_path)?;
assert!(!new_loaded.is_poisoned()?);
println!(
" New module loaded, is_poisoned: {}",
new_loaded.is_poisoned()?
);
let result: i32 =
new_loaded.call_guest_function("HelloWorld", "Recovery successful!".to_string())?;
println!(" HelloWorld returned: {}", result);
println!("\n=== Example Complete ===");
Ok(())
}