//! Per-process budgets (see `domain::budget`): carved from the creator, //! charged as a process takes frames and kernel objects, returned on death. use domain::{ budget::{Budget, Limits}, capability::CapabilityTable, error::KernelError, memory::quota::Quota, }; use platform::Platform; use types::id::ProcessId; use crate::Kernel; /// Picks the part of a budget an object counts against. pub(crate) type Part = fn(&mut Budget) -> &mut Quota; pub(crate) const ENDPOINTS: Part = |b| &mut b.endpoints; pub(crate) const NOTIFICATIONS: Part = |b| &mut b.notifications; pub(crate) const REGIONS: Part = |b| &mut b.regions; impl Kernel

{ pub(crate) fn budget_mut(&mut self, pid: ProcessId) -> Result<&mut Budget, KernelError> { self.budgets .get_mut(pid.raw() as usize) .ok_or(KernelError::InvalidProcess(pid)) } pub fn limits_of(&self, pid: ProcessId) -> Option { self.processes.get(pid).ok()?; self.budgets.get(pid.raw() as usize).map(Budget::limits) } /// A new process holding `limits`, carved from `parent`'s unused budget; /// only boot makes one without a parent. pub(crate) fn new_process( &mut self, parent: Option, limits: Limits, ) -> Result { if let Some(p) = parent { self.processes.get(p)?; if !self.budget_mut(p)?.carve(limits) { return Err(KernelError::OutOfMemory); } } let pid = match self.processes.create(CapabilityTable::new(), None) { Ok(pid) => pid, Err(e) => { if let Some(p) = parent { self.budget_mut(p)?.refund(limits); } return Err(e); } }; *self.budget_mut(pid)? = Budget::new(limits); if let Some(slot) = self.parents.get_mut(pid.raw() as usize) { *slot = parent; } if let Err(e) = self.create_address_space(pid) { self.release_budget(pid); let _ = self.processes.destroy(pid); return Err(e); } Ok(pid) } /// Gives a dead process's limits back to its parent; its children are /// carved from what it held, so they pass to that parent too. pub(crate) fn release_budget(&mut self, pid: ProcessId) { let i = pid.raw() as usize; let parent = self.parents.get_mut(i).and_then(Option::take); let limits = self .budgets .get_mut(i) .map(|b| core::mem::replace(b, Budget::EMPTY).limits()); if let (Some(p), Some(limits)) = (parent, limits) && let Ok(b) = self.budget_mut(p) { b.refund(limits); } for slot in self.parents.iter_mut().filter(|s| **s == Some(pid)) { *slot = parent; } } pub(crate) fn charge_object(&mut self, pid: ProcessId, part: Part) -> Result<(), KernelError> { if part(self.budget_mut(pid)?).charge(1) { Ok(()) } else { Err(KernelError::NoFreeSlot) } } pub(crate) fn uncharge_object(&mut self, pid: ProcessId, part: Part) { if let Ok(b) = self.budget_mut(pid) { part(b).uncharge(1); } } }