feat(init): supervise servers+session progs: restart on death, same endpoint, backoff 0/1/5/30s then give up, restarts_clients cascade; release grants/spawn at stop (stale-slot safe); storage death fatal; init output via printer thread (never blocks on log); terminal Ctrl+C via CONTROL-badged copy, latest wins; flaky test server + spawntest restart/backoff check

This commit is contained in:
2026-10-28 01:44:24 +01:00
parent c4871320a0
commit 28f1ace00a
23 changed files with 736 additions and 144 deletions

View File

@@ -11,4 +11,5 @@ bench = false
[dependencies]
types = { workspace = true }
manifest = { workspace = true }
flaky = { path = "../flaky" }
libkos = { workspace = true }

View File

@@ -17,10 +17,11 @@ use types::budget::Limits;
/// Where init put them (see init's manifest: `uses`, storage (the disk,
/// the user's home), the spawn endpoint, then control).
const PERMISSION: CapSlot = CapSlot::const_new(0);
const STORAGE: CapSlot = CapSlot::const_new(1);
const HOME: CapSlot = CapSlot::const_new(2);
const INIT: CapSlot = CapSlot::const_new(3);
const CONTROL: CapSlot = CapSlot::const_new(4);
const FLAKY: CapSlot = CapSlot::const_new(1);
const STORAGE: CapSlot = CapSlot::const_new(2);
const HOME: CapSlot = CapSlot::const_new(3);
const INIT: CapSlot = CapSlot::const_new(4);
const CONTROL: CapSlot = CapSlot::const_new(5);
/// Where storage's buffers are mapped: the whole disk's, a narrowed one's.
const STORAGE_BUF_VA: types::address::VirtualAddress = types::address::VirtualAddress::from_raw(0x0180_0000);
const NARROW_BUF_VA: types::address::VirtualAddress = types::address::VirtualAddress::from_raw(0x0190_0000);
@@ -172,6 +173,33 @@ fn encrypted_home(fs: &mut Storage, home_fs: &mut Storage) -> Result<(), &'stati
Ok(())
}
/// How many requests the `flaky` answering now has served.
fn flaky() -> Result<usize, &'static str> {
syscall::request(FLAKY, [flaky::op::WHO, 0, 0, 0]).map(|r| r[0]).map_err(|_| "flaky does not answer")
}
/// A server that dies is started again on the same endpoint: the caller's
/// capability reaches the new one. Twice in a row, the second waits.
fn restarted_after_crashes() -> Result<(), &'static str> {
if flaky()? != 1 || flaky()? != 2 {
return Err("flaky counts wrong");
}
// Dies mid-call: the call comes back with an error.
let _ = syscall::request(FLAKY, [flaky::op::CRASH, 0, 0, 0]);
if flaky()? != 1 {
return Err("the crashed server still answers");
}
let crashed = syscall::get_time().raw();
let _ = syscall::request(FLAKY, [flaky::op::CRASH, 0, 0, 0]);
let fresh = flaky()? == 1;
// QEMU virt's timebase is 10 MHz.
let waited_ms = (syscall::get_time().raw() - crashed) / 10_000;
if !fresh || waited_ms < 900 {
return Err("a second crash in a row was not backed off");
}
Ok(())
}
fn check() -> Result<(), &'static str> {
let mut fs = Storage::attach(STORAGE, STORAGE_BUF_VA).map_err(|_| "cannot attach to storage")?;
write_a_file(&mut fs)?;
@@ -201,6 +229,9 @@ fn check() -> Result<(), &'static str> {
revoke_stops_a_running_app(died)?;
libkos::println!("spawntest: revoking stops a running app, allowing lets it run: ok");
restarted_after_crashes()?;
libkos::println!("spawntest: a crashed server is restarted, a crash loop backs off: ok");
Ok(())
}