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

@@ -8,9 +8,11 @@ mod factory;
mod launch;
mod load;
mod manifest;
mod output;
mod selftest;
mod session;
mod spawn;
mod supervise;
use libkos::fs::Storage;
use libkos::syscall;
@@ -25,37 +27,44 @@ pub(crate) const STORAGE_EP: CapSlot = CapSlot::const_new(2);
pub fn run() -> ! {
libkos::start::set_console(devices::console());
libkos::println!("init: started (pid={:#x})", syscall::get_process_id().raw());
let printer = output::start();
crate::outln!("init: started (pid={:#x})", syscall::get_process_id().raw());
if !printer {
crate::outln!("init: no printer thread; output waits on the log server");
}
// Storage waits for its disk before serving, so this comes first.
let found = devices::discover();
let disk =
libkos::device::give_device(STORAGE_EP, found.disk).is_ok() && found.disk.mmio.is_some();
libkos::println!(
crate::outln!(
"init: disk: {}",
if disk { "handed to its driver" } else { "none" }
);
let Ok(mut storage) = Storage::attach(STORAGE_EP, STORAGE_BUF_VA) else {
libkos::println!("init: cannot reach storage, nothing to load");
crate::outln!("init: cannot reach storage, nothing to load");
idle();
};
// Storage has nothing to print with yet; init speaks for it.
libkos::println!("init: storage: up");
crate::outln!("init: storage: up");
let Some(scratch) = load::scratch() else {
libkos::println!("init: no memory to load programs into");
crate::outln!("init: no memory to load programs into");
idle();
};
let mut launcher = match launch::Launcher::new(&mut storage, scratch, found) {
Ok(l) => l,
Err(why) => {
libkos::println!("init: {}", why);
crate::outln!("init: {}", why);
idle();
}
};
launch_all(&mut launcher, manifest::SERVERS);
give_storage_the_log();
if !launcher.watch_storage() {
crate::outln!("init: cannot watch storage");
}
// The test image carries the SMP self-test; it and the tests run
// instead of the desktop, and the last one halts the machine.
@@ -64,7 +73,7 @@ pub fn run() -> ! {
.open(b"bin/smptest")
.is_ok_and(|h| storage.close(h).is_ok())
{
libkos::println!("init: running the SMP self-test");
crate::outln!("init: running the SMP self-test");
selftest::run(storage, scratch);
manifest::TESTS
} else {
@@ -72,22 +81,22 @@ pub fn run() -> ! {
};
// Nothing that touches a user's files starts before someone is in.
if let Err(why) = session::sign_in(&mut launcher) {
libkos::println!("init: STOP ({})", why);
crate::outln!("init: STOP ({})", why);
idle();
}
libkos::println!("init: all loaded, serving spawns");
crate::outln!("init: all loaded, serving spawns");
let _ = syscall::bind_notification(launcher.deaths);
let ep = launcher.spawn_ep;
server_framework::serve(&mut launcher, ep)
}
fn launch_all(launcher: &mut launch::Launcher, programs: &[manifest::Program]) {
fn launch_all(launcher: &mut launch::Launcher, programs: &'static [manifest::Program]) {
for p in programs {
libkos::print!("init: loading {}... ", p.name);
match launcher.launch(p) {
Ok(started) => libkos::println!("ok{}", started.note),
Err(why) => libkos::println!("SKIP ({})", why),
crate::out!("init: loading {}... ", p.name);
match launcher.run(p, false) {
Ok(note) => crate::outln!("ok{}", note),
Err(why) => crate::outln!("SKIP ({})", why),
}
}
}