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:
@@ -11,4 +11,5 @@ bench = false
|
||||
[dependencies]
|
||||
types = { workspace = true }
|
||||
manifest = { workspace = true }
|
||||
flaky = { path = "../flaky" }
|
||||
libkos = { workspace = true }
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user