feat(init): spawn service over IPC with per-client allowance refunded on child death; up to 4 death watchers; spawntest on test image
This commit is contained in:
@@ -5,12 +5,14 @@ use libkos::device::Device as BoardDevice;
|
||||
use libkos::fs::Storage;
|
||||
use libkos::syscall;
|
||||
use types::address::StackPointer;
|
||||
use types::badge::Badge;
|
||||
use types::bounded::CapSlot;
|
||||
use types::permission::{Permission, PermissionSet};
|
||||
|
||||
use crate::devices::Devices;
|
||||
use crate::load::{self, LoadedProcess};
|
||||
use crate::manifest::{Device, Program};
|
||||
use crate::spawn::Spawner;
|
||||
|
||||
const USER_STACK_TOP: StackPointer = StackPointer::from_raw(0x10000);
|
||||
const MAX_SERVED: usize = 8;
|
||||
@@ -25,11 +27,22 @@ pub(crate) struct Launcher<'a> {
|
||||
devices: Devices,
|
||||
/// The endpoint of every server started so far, by name.
|
||||
served: [Option<(&'static str, CapSlot)>; MAX_SERVED],
|
||||
/// Init's own endpoint, for the spawn service.
|
||||
pub(crate) spawn_ep: CapSlot,
|
||||
/// Bound to init's thread: spawned children's deaths, a bit each.
|
||||
pub(crate) deaths: CapSlot,
|
||||
pub(crate) spawner: Spawner,
|
||||
}
|
||||
|
||||
impl<'a> Launcher<'a> {
|
||||
pub(crate) fn new(storage: &'a mut Storage, scratch: &'a mut [u8], devices: Devices) -> Self {
|
||||
Self { storage, scratch, devices, served: [None; MAX_SERVED] }
|
||||
pub(crate) fn new(
|
||||
storage: &'a mut Storage,
|
||||
scratch: &'a mut [u8],
|
||||
devices: Devices,
|
||||
) -> Result<Self, &'static str> {
|
||||
let spawn_ep = syscall::create_endpoint().ok_or("no spawn endpoint")?;
|
||||
let deaths = syscall::create_notification().map_err(|_| "no death notification")?;
|
||||
Ok(Self { storage, scratch, devices, served: [None; MAX_SERVED], spawn_ep, deaths, spawner: Spawner::new() })
|
||||
}
|
||||
|
||||
pub(crate) fn storage(&mut self) -> (&mut Storage, &mut [u8]) {
|
||||
@@ -61,6 +74,13 @@ impl<'a> Launcher<'a> {
|
||||
let ep = self.endpoint(name).ok_or("needs a server that is not running")?;
|
||||
syscall::delegate(ep, child, perms(&[Permission::Execute])).ok_or("cannot give an endpoint")?;
|
||||
}
|
||||
if let Some(allowance) = p.spawns {
|
||||
self.give_spawn(child, allowance)?;
|
||||
}
|
||||
if p.system_control {
|
||||
let control = crate::devices::system_control().ok_or("no SystemControl to give")?;
|
||||
syscall::delegate(control, child, perms(&[Permission::Execute])).ok_or("cannot give SystemControl")?;
|
||||
}
|
||||
let console = libkos::start::console()
|
||||
.filter(|_| p.console)
|
||||
.and_then(|c| syscall::delegate(c, child, perms(&[Permission::Write])));
|
||||
@@ -82,6 +102,17 @@ impl<'a> Launcher<'a> {
|
||||
Ok(note)
|
||||
}
|
||||
|
||||
/// A badged copy of init's endpoint: the badge names the client and so
|
||||
/// its allowance.
|
||||
fn give_spawn(&mut self, child: CapSlot, allowance: types::budget::Limits) -> Result<(), &'static str> {
|
||||
let badge: Badge = self.spawner.add_client(allowance).ok_or("too many spawn clients")?;
|
||||
let minted = perms(&[Permission::Execute, Permission::Delegate]);
|
||||
let copy = syscall::mint(self.spawn_ep, badge, minted).map_err(|_| "cannot mint")?;
|
||||
let given = syscall::delegate(copy, child, perms(&[Permission::Execute]));
|
||||
syscall::drop_cap(copy);
|
||||
given.map(|_| ()).ok_or("cannot give the spawn endpoint")
|
||||
}
|
||||
|
||||
/// The driver waits for its device before serving, and runs without
|
||||
/// one (headless) if the board has none.
|
||||
fn give(&self, device: Device, ep: CapSlot) -> &'static str {
|
||||
|
||||
Reference in New Issue
Block a user