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}"
);
}