Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/heimdall

crates/heimdall-wasm/tests/no_compile_pool.rs

// SPDX-License-Identifier: AGPL-3.0-only
//! The wasm host compiles a guest on the calling thread: no compile pool
//! (lane HEIM-04, Holger HOL-HEIMDALL-04-DECISION). wasmtime's
//! `parallel-compilation` starts rayon's global pool, one thread per host CPU,
//! whatever the job's own limits say. Inside Holger's scan sidecar a job has
//! `RLIMIT_AS` = its memory plus 64 MiB; each pool thread takes a stack and a
//! 64 MiB malloc arena of that space, so on a 32-core host the pool could not
//! start (EAGAIN, holger-sandbox-9), and without `RLIMIT_AS` 32 threads burnt
//! the job's `RLIMIT_CPU` (killed, holger-sandbox-3). Heimdall is a defensive
//! sandbox; this test runs in its own child process.
//!
//! The parent re-runs this test binary as a child with
//! `HEIMDALL_NO_POOL_CHILD=1` and `RAYON_NUM_THREADS=8` (so a pool, were one
//! started, has 8 threads on any host). The child counts its threads, builds a
//! host, loads and runs a guest twice, and counts again: only the host's epoch
//! ticker may be new.

mod common;
use common::*;
use heimdall_wasm::{RunLimits, Verdict};

const CHILD: &str = "HEIMDALL_NO_POOL_CHILD";

fn threads() -> usize {
    std::fs::read_dir("/proc/self/task").unwrap().count()
}

fn run_good(kit: &Kit) {
    let g = kit.guest("good", &good_wat());
    for _ in 0..2 {
        let o = g.run(b"hello bundle", &none(), &RunLimits::default());
        assert_eq!(
            o.verdict,
            Verdict::Accepted {
                note: "accepted".into()
            },
            "{o:?}"
        );
        assert_eq!(o.files[0].bytes, b"hello bundle");
    }
}

#[test]
fn a_guest_compiles_on_the_calling_thread_with_no_pool() {
    if std::env::var_os(CHILD).is_some() {
        let before = threads();
        let kit = Kit::new("no-pool");
        run_good(&kit);
        let after = threads();
        assert!(
            after <= before + 1,
            "a host and two runs left {after} threads, {before} before: a compile pool started"
        );
        return;
    }
    let out = std::process::Command::new(std::env::current_exe().unwrap())
        .args([
            "--exact",
            "a_guest_compiles_on_the_calling_thread_with_no_pool",
            "--nocapture",
            "--test-threads=1",
        ])
        .env(CHILD, "1")
        .env("RAYON_NUM_THREADS", "8")
        .output()
        .expect("the child test runs");
    let text = format!(
        "{}{}",
        String::from_utf8_lossy(&out.stdout),
        String::from_utf8_lossy(&out.stderr)
    );
    assert!(out.status.success(), "child failed:\n{text}");
    assert!(
        text.contains("1 passed"),
        "the child did not run the test:\n{text}"
    );
}