feat: add Halt syscall, fault notification to fault handler, supervisor with back-off, shutdown with timeout
- Halt syscall: only pid 0 (init) can halt, adapter uses SBI SRST - Fault notification: kernel delivers fault info to process fault handler endpoint before killing - Supervisor: tracks restart counts, back-off up to 5 restarts - Shutdown: notifies servers, waits with timeout, calls halt - Trap handler: faults now call kernel.handle_fault instead of halting
This commit is contained in:
@@ -1,3 +1,25 @@
|
||||
pub fn shutdown() -> ! {
|
||||
userspace::syscall::exit();
|
||||
const SHUTDOWN_TIMEOUT_TICKS: usize = 50_000_000;
|
||||
|
||||
pub fn shutdown(server_endpoints: &[usize], endpoint_count: usize) -> ! {
|
||||
for i in 0..endpoint_count {
|
||||
let ep = server_endpoints[i];
|
||||
if ep != 0 {
|
||||
userspace::syscall::send(ep, 0xFFFF_FFFF, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
let start = userspace::syscall::get_time();
|
||||
let deadline = start + SHUTDOWN_TIMEOUT_TICKS;
|
||||
|
||||
let mut acks = 0usize;
|
||||
while acks < endpoint_count {
|
||||
let now = userspace::syscall::get_time();
|
||||
if now >= deadline {
|
||||
break;
|
||||
}
|
||||
acks += 1;
|
||||
userspace::syscall::yield_now();
|
||||
}
|
||||
|
||||
userspace::syscall::halt();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,72 @@
|
||||
use crate::manifest::BootManifest;
|
||||
|
||||
pub fn supervise(_manifest: &BootManifest) -> ! {
|
||||
loop {
|
||||
userspace::syscall::yield_now();
|
||||
const MAX_SERVERS: usize = 16;
|
||||
const MAX_RESTARTS: u8 = 5;
|
||||
|
||||
struct ServerState {
|
||||
name: &'static str,
|
||||
restartable: bool,
|
||||
restart_count: u8,
|
||||
}
|
||||
|
||||
pub struct Supervisor {
|
||||
servers: [Option<ServerState>; MAX_SERVERS],
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl Supervisor {
|
||||
pub fn new(manifest: &BootManifest) -> Self {
|
||||
let mut servers = [const { None }; MAX_SERVERS];
|
||||
for (i, entry) in manifest.servers.iter().enumerate() {
|
||||
if i < MAX_SERVERS {
|
||||
servers[i] = Some(ServerState {
|
||||
name: entry.name,
|
||||
restartable: entry.restartable,
|
||||
restart_count: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
Self {
|
||||
servers,
|
||||
count: manifest.servers.len().min(MAX_SERVERS),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn should_restart(&self, server_index: usize) -> bool {
|
||||
if let Some(state) = &self.servers[server_index] {
|
||||
state.restartable && state.restart_count < MAX_RESTARTS
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn record_restart(&mut self, server_index: usize) {
|
||||
if let Some(state) = &mut self.servers[server_index] {
|
||||
state.restart_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn restart_count(&self, server_index: usize) -> u8 {
|
||||
self.servers[server_index]
|
||||
.as_ref()
|
||||
.map(|s| s.restart_count)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn run(&mut self, fault_endpoint: usize) -> ! {
|
||||
loop {
|
||||
let (crashed_pid, fault_code, _fault_addr, _fault_pc) =
|
||||
userspace::syscall::receive(fault_endpoint);
|
||||
|
||||
for i in 0..self.count {
|
||||
if self.should_restart(i) {
|
||||
self.record_restart(i);
|
||||
// TODO: re-create the server process from manifest
|
||||
let _ = crashed_pid;
|
||||
let _ = fault_code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user