feat(kernel): per-process budgets (pages, endpoints, notifs, regions) carved from creator, returned on death; init owns pool
This commit is contained in:
80
crates/domain/src/budget.rs
Normal file
80
crates/domain/src/budget.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
//! What a process may hold: frames and kernel objects. A child's limits
|
||||
//! are carved from its creator's unused budget and go back when it dies,
|
||||
//! so the limits of all live processes never add up to more than init got.
|
||||
|
||||
use crate::memory::quota::Quota;
|
||||
pub use types::budget::Limits;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "budget_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Budget {
|
||||
pub pages: Quota,
|
||||
pub endpoints: Quota,
|
||||
pub notifications: Quota,
|
||||
pub regions: Quota,
|
||||
}
|
||||
|
||||
impl Budget {
|
||||
pub const EMPTY: Self = Self::new(Limits {
|
||||
pages: 0,
|
||||
endpoints: 0,
|
||||
notifications: 0,
|
||||
regions: 0,
|
||||
});
|
||||
|
||||
pub const fn new(limits: Limits) -> Self {
|
||||
Self {
|
||||
pages: Quota::new(limits.pages),
|
||||
endpoints: Quota::new(limits.endpoints),
|
||||
notifications: Quota::new(limits.notifications),
|
||||
regions: Quota::new(limits.regions),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn limits(&self) -> Limits {
|
||||
Limits {
|
||||
pages: self.pages.limit(),
|
||||
endpoints: self.endpoints.limit(),
|
||||
notifications: self.notifications.limit(),
|
||||
regions: self.regions.limit(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parts(&mut self) -> [&mut Quota; 4] {
|
||||
[
|
||||
&mut self.pages,
|
||||
&mut self.endpoints,
|
||||
&mut self.notifications,
|
||||
&mut self.regions,
|
||||
]
|
||||
}
|
||||
|
||||
/// Carves `child` out of the unused budget: all of it or nothing.
|
||||
pub fn carve(&mut self, child: Limits) -> bool {
|
||||
let amounts = amounts(child);
|
||||
let fits = self.parts().iter().zip(amounts).all(|(q, n)| {
|
||||
q.limit()
|
||||
.checked_sub(n)
|
||||
.is_some_and(|rest| rest >= q.used())
|
||||
});
|
||||
if fits {
|
||||
for (q, n) in self.parts().into_iter().zip(amounts) {
|
||||
q.carve(n);
|
||||
}
|
||||
}
|
||||
fits
|
||||
}
|
||||
|
||||
pub fn refund(&mut self, child: Limits) {
|
||||
for (q, n) in self.parts().into_iter().zip(amounts(child)) {
|
||||
q.refund(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn amounts(l: Limits) -> [usize; 4] {
|
||||
[l.pages, l.endpoints, l.notifications, l.regions]
|
||||
}
|
||||
Reference in New Issue
Block a user