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:
@@ -1,3 +1,4 @@
|
||||
use crate::generations::SlotGenerations;
|
||||
use types::{
|
||||
address::{PhysicalAddress, VirtualAddress},
|
||||
bounded::PageCount,
|
||||
@@ -43,7 +44,6 @@ pub struct Region {
|
||||
backing: RegionBacking,
|
||||
base: PhysicalAddress,
|
||||
pages: PageCount,
|
||||
generation: Generation,
|
||||
mappings: [Option<RegionMapping>; MAX_REGION_MAPPINGS],
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ impl Region {
|
||||
backing,
|
||||
base,
|
||||
pages,
|
||||
generation: Generation::initial(),
|
||||
mappings: [None; MAX_REGION_MAPPINGS],
|
||||
}
|
||||
}
|
||||
@@ -80,14 +79,6 @@ impl Region {
|
||||
self.pages
|
||||
}
|
||||
|
||||
pub fn generation(&self) -> &Generation {
|
||||
&self.generation
|
||||
}
|
||||
|
||||
pub fn revoke(&mut self) {
|
||||
self.generation = self.generation.next();
|
||||
}
|
||||
|
||||
pub fn mappings(&self) -> impl Iterator<Item = &RegionMapping> {
|
||||
self.mappings.iter().flatten()
|
||||
}
|
||||
@@ -124,23 +115,42 @@ impl Region {
|
||||
|
||||
pub struct RegionTable {
|
||||
regions: [Option<Region>; MAX_REGIONS],
|
||||
generations: SlotGenerations<MAX_REGIONS>,
|
||||
}
|
||||
|
||||
impl RegionTable {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
regions: [const { None }; MAX_REGIONS],
|
||||
generations: SlotGenerations::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generation capabilities to a live region must carry.
|
||||
pub fn generation(&self, id: RegionId) -> Option<Generation> {
|
||||
self.get(id)?;
|
||||
self.generations.current(id.raw() as usize)
|
||||
}
|
||||
|
||||
/// Invalidates every existing capability to `id`; the region lives on.
|
||||
pub fn revoke(&mut self, id: RegionId) {
|
||||
if self.get(id).is_some() {
|
||||
self.generations.advance(id.raw() as usize);
|
||||
}
|
||||
}
|
||||
|
||||
fn free_slot(&self) -> Option<usize> {
|
||||
(0..MAX_REGIONS).find(|&i| self.regions[i].is_none() && self.generations.is_usable(i))
|
||||
}
|
||||
|
||||
/// The id the next `insert` will return.
|
||||
pub fn next_free_id(&self) -> Option<RegionId> {
|
||||
let idx = self.regions.iter().position(|s| s.is_none())?;
|
||||
let idx = self.free_slot()?;
|
||||
Some(RegionId::from_raw(idx as u16))
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, region: Region) -> Option<RegionId> {
|
||||
let idx = self.regions.iter().position(|s| s.is_none())?;
|
||||
let idx = self.free_slot()?;
|
||||
self.regions[idx] = Some(region);
|
||||
Some(RegionId::from_raw(idx as u16))
|
||||
}
|
||||
@@ -153,8 +163,12 @@ impl RegionTable {
|
||||
self.regions.get_mut(id.raw() as usize)?.as_mut()
|
||||
}
|
||||
|
||||
/// Removes the region; capabilities to it become invalid even if the
|
||||
/// slot is later reused.
|
||||
pub fn remove(&mut self, id: RegionId) -> Option<Region> {
|
||||
self.regions.get_mut(id.raw() as usize)?.take()
|
||||
let region = self.regions.get_mut(id.raw() as usize)?.take()?;
|
||||
self.generations.advance(id.raw() as usize);
|
||||
Some(region)
|
||||
}
|
||||
|
||||
pub fn ids_owned_by(&self, owner: ProcessId) -> impl Iterator<Item = RegionId> + '_ {
|
||||
|
||||
Reference in New Issue
Block a user