Kernel API
Generally, userspace applications will not have the capability to message the kernel. Those that can, such as the app store, have full control over starting and stopping all userspace processes.
The kernel runtime task accepts one kind of Request
:
#![allow(unused)] fn main() { /// IPC format for requests sent to kernel runtime module #[derive(Debug, Serialize, Deserialize)] pub enum KernelCommand { /// RUNTIME ONLY: used to notify the kernel that booting is complete and /// all processes have been loaded in from their persisted or bootstrapped state. Booted, /// Tell the kernel to install and prepare a new process for execution. /// The process will not begin execution until the kernel receives a /// `RunProcess` command with the same `id`. /// /// The process that sends this command will be given messaging capabilities /// for the new process if `public` is false. /// /// All capabilities passed into initial_capabilities must be held by the source /// of this message, or the kernel will discard them (silently for now). InitializeProcess { id: ProcessId, wasm_bytes_handle: String, wit_version: Option<u32>, on_exit: OnExit, initial_capabilities: HashSet<Capability>, public: bool, }, /// Create an arbitrary capability and grant it to a process. GrantCapabilities { target: ProcessId, capabilities: Vec<Capability>, }, /// Drop capabilities. Does nothing if process doesn't have these caps DropCapabilities { target: ProcessId, capabilities: Vec<Capability>, }, /// Tell the kernel to run a process that has already been installed. /// TODO: in the future, this command could be extended to allow for /// resource provision. RunProcess(ProcessId), /// Kill a running process immediately. This may result in the dropping / mishandling of messages! KillProcess(ProcessId), /// RUNTIME ONLY: notify the kernel that the runtime is shutting down and it /// should gracefully stop and persist the running processes. Shutdown, /// Ask kernel to produce debugging information Debug(KernelPrint), } }
All KernelCommand
s are sent in the body field of a Request
, serialized to JSON.
Only InitializeProcess
, RunProcess
, and KillProcess
will give back a Response
, also serialized to JSON text bytes using serde_json
:
#![allow(unused)] fn main() { #[derive(Debug, Serialize, Deserialize)] pub enum KernelResponse { InitializedProcess, InitializeProcessError, StartedProcess, RunProcessError, KilledProcess(ProcessId), Debug(KernelPrintResponse), } #[derive(Debug, Serialize, Deserialize)] pub enum KernelPrintResponse { ProcessMap(UserspaceProcessMap), Process(Option<UserspacePersistedProcess>), HasCap(Option<bool>), } pub type UserspaceProcessMap = HashMap<ProcessId, UserspacePersistedProcess>; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct UserspacePersistedProcess { pub wasm_bytes_handle: String, pub wit_version: Option<u32>, pub on_exit: OnExit, pub capabilities: HashSet<Capability>, pub public: bool, } }
Booted
Purely for internal use within the kernel. Sent by the kernel, to the kernel, to indicate that all persisted processes have been initialized and are ready to run.
InitializeProcess
The first command used to start a new process.
Generally available to apps via the spawn()
function in the WIT interface.
The wasm_bytes_handle
is a pointer generated by the filesystem API — it should be a valid .wasm
file compiled using the Kinode tooling.
The on_panic
field is an enum that specifies what to do if the process panics.
The initial_capabilities
field is a set of capabilities that the process will have access to — note that the capabilities are signed by this kernel.
The public
field specifies whether the process should be visible to other processes without needing to grant a messaging capability.
InitializeProcess
must be sent with a lazy_load_blob
.
The blob must be the same .wasm file, in raw bytes, that the wasm_bytes_handle
points to.
This will not cause the process to begin running.
To do that, send a RunProcess
command after a successful InitializeProcess
command.
GrantCapabilities
This command directly inserts a list of capabilities into another process' state.
While you generally don't want to do this for security reasons, it helps you clean up the "handshake" process by which capabilities must be handed off between two processes before engaging in the business logic.
For instance, if you want a kernel module like http_server
to be able to message a process back, you do this by directly inserting that "messaging"
cap into http_server
's store.
Only the app_store
, terminal
, and tester
make use of this.
DropCapabilities
This command removes a list of capabilities from another process' state. Currently, no app makes use of this, as it is very powerful.
RunProcess
Takes a process ID and tells kernel to call the init
function.
The process must have first been initialized with a successful InitializeProcess
.
KillProcess
Takes a process ID and kills it. This is a dangerous operation as messages queued for the process will be lost. The process will be removed from the kernel's process table and will no longer be able to receive messages.
Shutdown
Send to the kernel in order to gracefully shut down the system. The runtime must perform this request before exiting in order to see that all processes are properly cleaned up.