feat(init): spawn service over IPC with per-client allowance refunded on child death; up to 4 death watchers; spawntest on test image

This commit is contained in:
2026-10-27 16:21:08 +01:00
parent 817a38993b
commit 8587661684
23 changed files with 564 additions and 28 deletions

View File

@@ -0,0 +1,13 @@
[package]
name = "spawntest"
version = "0.1.0"
edition = "2024"
[[bin]]
name = "spawntest"
test = false
bench = false
[dependencies]
types = { workspace = true }
libkos = { workspace = true }

View File

@@ -0,0 +1,61 @@
//! The test image's last check, started by init with a spawn allowance:
//! programs run through init, the allowance holds, and it comes back when
//! a child dies. Reports the whole self-test and halts.
#![no_std]
#![no_main]
extern crate libkos;
use libkos::spawn::{SpawnError, spawn};
use libkos::syscall;
use types::bounded::CapSlot;
use types::budget::Limits;
/// Where init put them (see init's manifest: spawn endpoint, then control).
const INIT: CapSlot = CapSlot::const_new(0);
const CONTROL: CapSlot = CapSlot::const_new(1);
/// Over half the allowance (128 pages), so a second one fits only after
/// the first has died and its limits came back.
const HELLO: Limits = Limits { pages: 80, endpoints: 0, notifications: 0, regions: 0 };
/// Spawns hello, runs it, and waits for it to die.
fn run_hello(died: CapSlot) -> Result<(), &'static str> {
let child = spawn(INIT, b"hello.elf", HELLO).map_err(|_| "init would not spawn hello")?;
syscall::watch_death(child.process, died).map_err(|_| "cannot watch hello")?;
if !child.start() {
return Err("cannot start hello");
}
syscall::wait(died).map_err(|_| "wait failed")?;
Ok(())
}
fn check() -> Result<(), &'static str> {
let died = syscall::create_notification().map_err(|_| "no notification")?;
run_hello(died)?;
libkos::println!("spawntest: spawned program runs and its death is heard: ok");
let greedy = Limits { pages: 200, ..HELLO };
if spawn(INIT, b"hello.elf", greedy).err() != Some(SpawnError::OverAllowance) {
return Err("init spawned past the allowance");
}
let tiny = Limits { pages: 1, ..HELLO };
if spawn(INIT, b"nothere.elf", tiny).err() != Some(SpawnError::NotFound) {
return Err("a missing program was not reported");
}
libkos::println!("spawntest: allowance and missing files refused: ok");
run_hello(died)?;
libkos::println!("spawntest: allowance comes back when a child dies: ok");
Ok(())
}
#[unsafe(no_mangle)]
extern "C" fn main() {
match check() {
Ok(()) => libkos::println!("SMPTEST PASS"),
Err(why) => libkos::println!("SMPTEST FAIL: {}", why),
}
syscall::halt(CONTROL);
}