//! Running a program through init (protocol: `types::spawn`). Init loads it //! and gives it a log endpoint; the caller hands it any other capabilities //! (`delegate` to the process) and starts it. use crate::syscall; use types::address::{EntryPoint, StackPointer}; use types::bounded::CapSlot; use types::budget::Limits; use types::spawn::{STACK_TOP, reply, request}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SpawnError { NotFound, /// More than what is left of this process's spawn allowance. OverAllowance, Failed, } /// A loaded program, not yet running. pub struct Spawned { pub process: CapSlot, entry: EntryPoint, log: Option, } pub fn spawn(init: CapSlot, name: &[u8], limits: Limits) -> Result { let words = request(name, limits).ok_or(SpawnError::Failed)?; let reply = syscall::call(init, words, None).map_err(|_| SpawnError::Failed)?; let [tag, entry, log, _] = reply.words(); let cap = match reply { syscall::Received::Message { cap, .. } | syscall::Received::Call { cap, .. } => cap, syscall::Received::Signal { .. } => None, }; match (tag, cap) { (reply::OK, Some(process)) => Ok(Spawned { process, entry: EntryPoint::from_raw(entry), log: u8::try_from(log).ok().and_then(CapSlot::new), }), (reply::NOT_FOUND, _) => Err(SpawnError::NotFound), (reply::OVER_ALLOWANCE, _) => Err(SpawnError::OverAllowance), _ => Err(SpawnError::Failed), } } impl Spawned { /// Runs the program, telling it where its log endpoint is. pub fn start(&self) -> bool { let arg = types::start_arg::encode(None, self.log); let stack = StackPointer::from_raw(STACK_TOP); syscall::spawn_thread_in(self.process, self.entry, stack, arg) != usize::MAX } }