feat(userspace): Call/ReplyRecv IPC, malformed-request replies, servers exit on dead endpoint; drop send/receive compat, select!, async_syscall

This commit is contained in:
2026-10-27 12:06:10 +01:00
parent 2a8a5b0c27
commit e8a2963b24
18 changed files with 96 additions and 101 deletions

View File

@@ -1,16 +0,0 @@
use types::bounded::CapSlot;
pub async fn send(endpoint: CapSlot, w0: usize, w1: usize, w2: usize, w3: usize) -> usize {
libkos::syscall::send(endpoint, w0, w1, w2, w3)
}
pub async fn receive(endpoint: CapSlot) -> (usize, usize, usize, usize) {
libkos::syscall::receive(endpoint)
}
pub async fn wait_for_interrupt(_irq: CapSlot) {
libkos::syscall::yield_now();
}
pub async fn acknowledge_interrupt(_irq: CapSlot) {
}

View File

@@ -1,9 +1,7 @@
#![no_std]
pub mod async_syscall;
pub mod codec;
pub mod executor;
pub mod select;
pub mod server;
pub use codec::{Decode, Encode};

View File

@@ -1,14 +0,0 @@
#[macro_export]
macro_rules! select {
(
$msg:ident = receive($ep:expr) => $ipc_body:block
$irq:ident = wait_interrupt($irq_cap:expr) => $irq_body:block
) => {
{
let sources = types::syscall_abi::SYS_WAIT_ANY;
let wake = libkos::syscall::receive($ep as usize);
let $msg = wake;
$ipc_body
}
};
}

View File

@@ -4,24 +4,52 @@ mod tests;
use crate::codec::{Decode, Encode};
use types::bounded::CapSlot;
/// The reply to a request that does not decode. No protocol uses this
/// tag, so every client decodes it as an error.
pub const MALFORMED: usize = usize::MAX;
pub trait Server {
type Request: Decode;
type Response: Encode;
fn handle(&mut self, request: Self::Request) -> Self::Response;
fn run(&mut self, endpoint: CapSlot) {
/// Serves `endpoint` until receiving on it fails (it was destroyed or
/// the capability revoked), then returns why. Every `Call` gets a
/// reply, `[MALFORMED, ..]` if it does not decode; a one-way `Send` is
/// handled without one; notification signals are ignored.
fn run(&mut self, endpoint: CapSlot) -> libkos::syscall::Error {
use libkos::syscall::{Received, receive_msg, reply_recv};
let mut next = receive_msg(endpoint);
loop {
let words = libkos::syscall::receive(endpoint);
if let Some(request) = Self::Request::decode([words.0, words.1, words.2, words.3]) {
let response = self.handle(request);
let encoded = response.encode();
libkos::syscall::send(endpoint, encoded[0], encoded[1], encoded[2], encoded[3]);
}
let message = match next {
Ok(m) => m,
Err(e) => return e,
};
next = match message {
Received::Call { words, .. } => {
let reply = match Self::Request::decode(words) {
Some(request) => self.handle(request).encode(),
None => [MALFORMED, 0, 0, 0],
};
reply_recv(endpoint, reply, None)
}
Received::Message { words, .. } => {
if let Some(request) = Self::Request::decode(words) {
let _ = self.handle(request);
}
receive_msg(endpoint)
}
Received::Signal { .. } => receive_msg(endpoint),
};
}
}
}
pub fn serve<S: Server>(server: &mut S, endpoint: CapSlot) {
server.run(endpoint);
/// Runs `server` on `endpoint` for good. A server whose endpoint is gone
/// has nobody left to serve, so it says why and exits.
pub fn serve<S: Server>(server: &mut S, endpoint: CapSlot) -> ! {
let error = server.run(endpoint);
libkos::println!("server: endpoint {} unusable ({:?}), exiting", endpoint.value(), error);
libkos::syscall::exit()
}