Files
k-os/crates/domain/src/budget.rs

81 lines
2.1 KiB
Rust

//! 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]
}