feat(kernel): per-process budgets (pages, endpoints, notifs, regions) carved from creator, returned on death; init owns pool

This commit is contained in:
2026-10-27 15:08:58 +01:00
parent 7415bab7f5
commit 4049ba5007
46 changed files with 672 additions and 119 deletions

View File

@@ -1,5 +1,6 @@
/// Per-process page budget. Every frame charged to a process (user pages
/// and its page tables) counts against it.
/// A count against a limit: one of a process's budgets (see `budget`).
/// For pages, every frame charged to a process (user pages and its page
/// tables) counts against it.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Quota {
used: usize,
@@ -7,8 +8,6 @@ pub struct Quota {
}
impl Quota {
pub const DEFAULT_LIMIT: usize = 1024;
pub const fn new(limit: usize) -> Self {
Self { used: 0, limit }
}
@@ -41,17 +40,19 @@ impl Quota {
}
}
pub fn set_limit(&mut self, limit: usize) -> bool {
if limit < self.used {
return false;
/// Gives up `amount` of the unused limit, for a child to hold.
pub fn carve(&mut self, amount: usize) -> bool {
match self.limit.checked_sub(amount) {
Some(rest) if rest >= self.used => {
self.limit = rest;
true
}
_ => false,
}
self.limit = limit;
true
}
}
impl Default for Quota {
fn default() -> Self {
Self::new(Self::DEFAULT_LIMIT)
/// Takes back a limit carved out earlier.
pub fn refund(&mut self, amount: usize) {
self.limit = self.limit.saturating_add(amount);
}
}

View File

@@ -28,10 +28,13 @@ fn uncharge_cannot_underflow() {
}
#[test]
fn limit_can_be_raised_but_not_below_usage() {
fn only_the_unused_limit_can_be_carved() {
let mut q = Quota::new(4);
q.charge(3);
assert!(!q.set_limit(2));
assert!(q.set_limit(10));
assert!(q.charge(7));
assert!(!q.carve(2));
assert_eq!(q.limit(), 4);
assert!(q.carve(1));
assert!(!q.charge(1));
q.refund(1);
assert!(q.charge(1));
}