feat(kernel): object lifetimes via slot generations

- SlotGenerations per table, never wraps, retires exhausted slots
- caps to dead/reused process, endpoint, region rejected
- endpoints owned, die w/ owner, waiters woken w/ error
- DropCap syscall + libkos wrapper
- irq table bounds-checked, routes dropped w/ thread
- self-kill terminates caller, exit_thread full cleanup
- sched run_now: switch to named thread, not queue head
- lifetime tests, fuzz kills/recreates, kani gen proofs
This commit is contained in:
2026-10-26 19:54:23 +01:00
parent 8d2c40cb1e
commit d43421e33e
32 changed files with 790 additions and 207 deletions

View File

@@ -74,14 +74,16 @@ impl Kernel<MockPlatform> {
if let Ok(t) = self.threads.get(tid)
&& matches!(t.state(), ThreadState::Ready)
&& self.scheduler.run_now(core, tid)
{
self.scheduler.next(core);
let _ = self.threads.get_mut(tid).map(|t| t.set_running(core));
}
}
pub fn create_endpoint_for_test(&mut self) -> EndpointId {
self.endpoints.create().expect("create endpoint")
self.endpoints
.create(ProcessId::from_raw(0))
.expect("create endpoint")
}
pub fn grant_cap_for_test(
@@ -93,4 +95,40 @@ impl Kernel<MockPlatform> {
self.grant_cap(pid, resource, permissions)
.expect("grant cap")
}
pub fn endpoint_of_cap_for_test(&self, pid: ProcessId, slot: CapSlot) -> EndpointId {
match self
.processes
.get(pid)
.unwrap()
.capabilities()
.get(slot)
.unwrap()
.resource()
{
Resource::Endpoint(id) => *id,
_ => panic!("not an endpoint cap"),
}
}
/// The process a Process cap in init's table points at.
pub fn process_of_cap_for_test(&self, slot: CapSlot) -> ProcessId {
let init = ProcessId::from_raw(0);
match self
.processes
.get(init)
.unwrap()
.capabilities()
.get(slot)
.unwrap()
.resource()
{
Resource::Process(pid) => *pid,
_ => panic!("not a process cap"),
}
}
pub fn thread_state_for_test(&self, tid: ThreadId) -> Option<ThreadState> {
self.threads.get(tid).ok().map(|t| *t.state())
}
}