54 lines
1.8 KiB
Rust
54 lines
1.8 KiB
Rust
//! 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<CapSlot>,
|
|
}
|
|
|
|
pub fn spawn(init: CapSlot, name: &[u8], limits: Limits) -> Result<Spawned, SpawnError> {
|
|
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
|
|
}
|
|
}
|