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:
13
crates/apps/spawntest/Cargo.toml
Normal file
13
crates/apps/spawntest/Cargo.toml
Normal 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 }
|
||||
61
crates/apps/spawntest/src/main.rs
Normal file
61
crates/apps/spawntest/src/main.rs
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user