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:
@@ -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) {
|
||||
}
|
||||
@@ -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};
|
||||
|
||||
@@ -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
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user