supermachine 0.4.10

Run any OCI/Docker image as a hardware-isolated microVM on macOS HVF (Linux KVM and Windows WHP in progress). Single library API, zero flags for the common case, sub-100 ms cold-restore from snapshot.
//! Embed-vs-CLI perf comparison. Boots a 1-vcpu nginx via the
//! library API, exposes guest:80 on host:8081, sits there until
//! Ctrl-C. Compare wrk against this port vs port 8080 (CLI run).

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use supermachine::{Image, VmConfig};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let snap = format!(
        "{}/.local/supermachine-snapshots/nginx_1v",
        std::env::var("HOME")?
    );
    let port: u16 = std::env::var("PORT")
        .ok()
        .and_then(|s| s.parse().ok())
        .unwrap_or(8081);

    let image = Image::from_snapshot(&snap)?;
    let vm = image.start(&VmConfig::new())?;
    let _fwd = vm.expose_tcp(port, 80)?;
    println!("listening on http://127.0.0.1:{port}/  (Ctrl-C to stop)");

    let stop = Arc::new(AtomicBool::new(false));
    let s = stop.clone();
    ctrlc_handler(move || s.store(true, Ordering::SeqCst));
    while !stop.load(Ordering::SeqCst) {
        std::thread::sleep(std::time::Duration::from_millis(200));
    }
    vm.stop()?;
    Ok(())
}

fn ctrlc_handler<F: FnMut() + Send + 'static>(mut cb: F) {
    unsafe {
        let mut sa: libc::sigaction = std::mem::zeroed();
        sa.sa_sigaction = sigint_handler as usize;
        libc::sigemptyset(&mut sa.sa_mask);
        sa.sa_flags = libc::SA_RESTART;
        libc::sigaction(libc::SIGINT, &sa, std::ptr::null_mut());
    }
    std::thread::spawn(move || loop {
        let n = SIGINT_COUNT.load(Ordering::SeqCst);
        if n > 0 {
            cb();
            return;
        }
        std::thread::sleep(std::time::Duration::from_millis(100));
    });
}

static SIGINT_COUNT: std::sync::atomic::AtomicUsize =
    std::sync::atomic::AtomicUsize::new(0);

extern "C" fn sigint_handler(_sig: libc::c_int) {
    SIGINT_COUNT.fetch_add(1, Ordering::SeqCst);
}