feat(kernel): add Exit and ExitThread syscalls with process cleanup
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
25
crates/kernel/src/tests/exit.rs
Normal file
25
crates/kernel/src/tests/exit.rs
Normal 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);
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
mod exit;
|
||||||
mod simple;
|
mod simple;
|
||||||
|
|
||||||
use domain::memory::page_pool::PagePool;
|
use domain::memory::page_pool::PagePool;
|
||||||
|
|||||||
Reference in New Issue
Block a user