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

@@ -78,9 +78,9 @@ fn purge(fs: &mut Storage, folder: UserFolder) -> Result<(), &'static str> {
/// Runs the gatekeeper until someone is in and starts their session.
pub(crate) fn sign_in(l: &mut Launcher) -> Result<(), &'static str> {
libkos::print!("init: loading gatekeeper... ");
crate::out!("init: loading gatekeeper... ");
let gatekeeper = l.launch(&GATEKEEPER)?;
libkos::println!("ok{}", gatekeeper.note);
crate::outln!("ok{}", gatekeeper.note);
let handover = gatekeeper.ep.ok_or("the gatekeeper serves nothing").and_then(ask);
// It exits on its own once it has handed over.
syscall::drop_cap(gatekeeper.process);
@@ -91,11 +91,11 @@ pub(crate) fn sign_in(l: &mut Launcher) -> Result<(), &'static str> {
// While storage is locked: it removes trees only then.
if h.flags & unlocked::FRESH != 0 {
fs.purge(b"users").map_err(|_| "cannot clear the users of an old keystore")?;
libkos::println!("init: a new keystore, every earlier user's files removed");
crate::outln!("init: a new keystore, every earlier user's files removed");
}
for id in h.removed.iter().flatten() {
purge(fs, UserFolder::of(*id))?;
libkos::println!("init: a removed user's files removed");
crate::outln!("init: a removed user's files removed");
}
if guest {
purge(fs, UserFolder::GUEST)?;
@@ -107,31 +107,20 @@ pub(crate) fn sign_in(l: &mut Launcher) -> Result<(), &'static str> {
}
crate::factory::prepare(fs, folder, scratch)?;
let name = core::str::from_utf8(&h.name[..h.name_len]).unwrap_or("someone");
libkos::println!("init: {} is in", name);
crate::outln!("init: {} is in", name);
l.user = Some(User { folder, guest });
start_session(l);
Ok(())
}
/// Starts what runs for a signed-in user, keeping each process to stop
/// at sign-out.
/// Starts what runs for a signed-in user; it is stopped at sign-out.
fn start_session(l: &mut Launcher) {
let desktop = l.desktop;
for p in SESSION.iter().chain(desktop) {
libkos::print!("init: loading {}... ", p.name);
match l.launch(p) {
Ok(started) => {
libkos::println!("ok{}", started.note);
match l.running.iter_mut().find(|r| r.is_none()) {
Some(free) => *free = Some(started.process),
None => {
// Untracked, it could not be stopped at sign-out.
let _ = syscall::kill(started.process);
syscall::drop_cap(started.process);
}
}
}
Err(why) => libkos::println!("SKIP ({})", why),
crate::out!("init: loading {}... ", p.name);
match l.run(p, true) {
Ok(note) => crate::outln!("ok{}", note),
Err(why) => crate::outln!("SKIP ({})", why),
}
}
}
@@ -139,25 +128,19 @@ fn start_session(l: &mut Launcher) {
/// Stops the session, locks storage, and lets the next one in.
pub(crate) fn sign_out(l: &mut Launcher) {
l.spawner.clear();
for process in l.running.iter_mut().filter_map(Option::take) {
let _ = syscall::kill(process);
syscall::drop_cap(process);
}
if let Some(terminal) = l.served("terminal") {
let _ = syscall::request(terminal, [types::terminal::SIGNED_OUT, 0, 0, 0]);
}
l.stop_session();
let user = l.user.take();
let (fs, _) = l.storage();
let locked = fs.lock().is_ok();
// A guest leaves nothing behind.
let cleared = !user.is_some_and(|u| u.guest) || purge(fs, UserFolder::GUEST).is_ok();
libkos::println!("init: signed out");
crate::outln!("init: signed out");
let next = match locked && cleared {
true => sign_in(l),
false => Err("storage would not lock"),
};
if let Err(why) = next {
libkos::println!("init: STOP ({})", why);
crate::outln!("init: STOP ({})", why);
crate::idle();
}
}