feat(kernel): add Exit and ExitThread syscalls with process cleanup

This commit is contained in:
2026-10-18 00:16:38 +02:00
parent d0a0ba788f
commit 74b296a2bf
4 changed files with 80 additions and 0 deletions

View File

@@ -125,6 +125,10 @@ impl<P: Platform> Kernel<P> {
} }
} }
pub fn process_exists(&self, pid: ProcessId) -> bool {
self.processes.get(pid).is_ok()
}
fn check_cap( fn check_cap(
&self, &self,
owner: ProcessId, owner: ProcessId,

View File

@@ -14,6 +14,8 @@ impl<P: Platform> Kernel<P> {
Syscall::GetTime => self.handle_get_time(), Syscall::GetTime => self.handle_get_time(),
Syscall::GetProcessId => self.handle_get_process_id(pid), Syscall::GetProcessId => self.handle_get_process_id(pid),
Syscall::Yield => self.handle_yield(tid), Syscall::Yield => self.handle_yield(tid),
Syscall::Exit => self.handle_exit(tid, pid),
Syscall::ExitThread => self.handle_exit_thread(tid, pid),
_ => SyscallOutcome::Complete(SyscallResult::Error( _ => SyscallOutcome::Complete(SyscallResult::Error(
domain::error::KernelError::WouldBlock, domain::error::KernelError::WouldBlock,
)), )),
@@ -29,6 +31,54 @@ impl<P: Platform> Kernel<P> {
SyscallOutcome::Complete(SyscallResult::Value(pid.raw() as usize)) SyscallOutcome::Complete(SyscallResult::Value(pid.raw() as usize))
} }
fn handle_exit(&mut self, caller_tid: types::id::ThreadId, pid: types::id::ProcessId) -> SyscallOutcome {
use domain::scheduler::Scheduler;
// Kill all threads of this process
let thread_ids: [Option<types::id::ThreadId>; 4] = {
match self.processes.get(pid) {
Ok(p) => {
let mut ids = [None; 4];
for (i, tid) in p.thread_ids().enumerate() {
if i < 4 {
ids[i] = Some(tid);
}
}
ids
}
Err(_) => return SyscallOutcome::TerminateCaller,
}
};
for slot in &thread_ids {
if let Some(tid) = slot {
self.scheduler.remove(*tid);
let _ = self.threads.destroy(*tid);
}
}
let _ = self.processes.destroy(pid);
self.process_memory[pid.raw() as usize] = None;
SyscallOutcome::TerminateCaller
}
fn handle_exit_thread(&mut self, caller_tid: types::id::ThreadId, pid: types::id::ProcessId) -> SyscallOutcome {
use domain::scheduler::Scheduler;
self.scheduler.remove(caller_tid);
let _ = self.threads.destroy(caller_tid);
if let Ok(process) = self.processes.get_mut(pid) {
process.remove_thread(caller_tid);
if process.thread_ids().count() == 0 {
let _ = self.processes.destroy(pid);
self.process_memory[pid.raw() as usize] = None;
}
}
SyscallOutcome::TerminateCaller
}
fn handle_yield(&mut self, caller_tid: types::id::ThreadId) -> SyscallOutcome { fn handle_yield(&mut self, caller_tid: types::id::ThreadId) -> SyscallOutcome {
use domain::scheduler::Scheduler; use domain::scheduler::Scheduler;

View File

@@ -0,0 +1,25 @@
use super::*;
use crate::{SyscallOutcome, SyscallResult};
use domain::syscall::Syscall;
#[test]
fn exit_thread_terminates_caller() {
let (mut k, _) = kernel_with_process();
let outcome = k.handle_syscall(Syscall::ExitThread);
assert!(matches!(outcome, SyscallOutcome::TerminateCaller));
}
#[test]
fn exit_terminates_process_and_all_threads() {
let (mut k, _) = kernel_with_process();
let outcome = k.handle_syscall(Syscall::Exit);
assert!(matches!(outcome, SyscallOutcome::TerminateCaller));
}
#[test]
fn exit_thread_last_thread_destroys_process() {
let (mut k, pid) = kernel_with_process();
k.handle_syscall(Syscall::ExitThread);
// Process should be gone since it had only one thread
assert!(k.process_exists(pid) == false);
}

View File

@@ -1,3 +1,4 @@
mod exit;
mod simple; mod simple;
use domain::memory::page_pool::PagePool; use domain::memory::page_pool::PagePool;