跳转到内容

添加 IPC 服务

本指南介绍如何为 OpenOS 添加新的 IPC 服务。

kernel/src/services/my_service/mod.rs
#[derive(Debug, Clone)]
pub enum Request {
Read { offset: u64, length: u64 },
Write { offset: u64, data: Vec<u8> },
GetStatus,
}
#[derive(Debug, Clone)]
pub enum Response {
ReadResult { data: Vec<u8> },
WriteResult { bytes_written: u64 },
Status { ready: bool, error: Option<String> },
Error { code: i64, message: String },
}
use alloc::collections::VecDeque;
use spin::Mutex;
pub struct MyService {
port_id: u64,
buffer: Vec<u8>,
}
impl MyService {
pub fn new(port_id: u64) -> Self {
MyService {
port_id,
buffer: Vec::new(),
}
}
pub fn handle_request(&mut self, request: Request) -> Response {
match request {
Request::Read { offset, length } => self.handle_read(offset, length),
Request::Write { offset, data } => self.handle_write(offset, &data),
Request::GetStatus => self.handle_get_status(),
}
}
fn handle_read(&self, offset: u64, length: u64) -> Response {
let offset = offset as usize;
let length = length as usize;
if offset >= self.buffer.len() {
return Response::Error {
code: -1,
message: "Offset out of bounds".to_string(),
};
}
let end = core::cmp::min(offset + length, self.buffer.len());
let data = self.buffer[offset..end].to_vec();
Response::ReadResult { data }
}
fn handle_write(&mut self, offset: u64, data: &[u8]) -> Response {
let offset = offset as usize;
if offset + data.len() > self.buffer.len() {
self.buffer.resize(offset + data.len(), 0);
}
self.buffer[offset..offset + data.len()].copy_from_slice(data);
Response::WriteResult { bytes_written: data.len() as u64 }
}
fn handle_get_status(&self) -> Response {
Response::Status { ready: true, error: None }
}
}
pub fn service_main(port_id: u64) -> ! {
let mut service = MyService::new(port_id);
loop {
let mut buffer = [0u8; 4096];
let received = sys_receive(port_id, &mut buffer).unwrap();
let request = match Request::from_bytes(&buffer[..received]) {
Ok(req) => req,
Err(e) => {
serial_println!("[MY_SERVICE] Failed to parse request: {:?}", e);
continue;
}
};
let response = service.handle_request(request);
let response_bytes = response.to_bytes();
if let Err(e) = sys_send(port_id, &response_bytes) {
serial_println!("[MY_SERVICE] Failed to send response: {:?}", e);
}
}
}
kernel/src/services/mod.rs
pub mod my_service;
pub fn init_all() {
let port_id = sys_port_create().unwrap();
register_service("my_service", port_id);
spawn_service_thread(port_id, my_service::service_main);
}
sdk/src/services/my_service.rs
pub struct MyServiceClient {
port_id: u64,
}
impl MyServiceClient {
pub fn new(port_id: u64) -> Self {
MyServiceClient { port_id }
}
pub fn read(&self, offset: u64, length: u64) -> Result<Vec<u8>, Error> {
let request = Request::Read { offset, length };
let response = self.send_request(request)?;
match response {
Response::ReadResult { data } => Ok(data),
Response::Error { code, message } => Err(Error::ServiceError(code, message)),
_ => Err(Error::InvalidResponse),
}
}
pub fn write(&self, offset: u64, data: &[u8]) -> Result<u64, Error> {
let request = Request::Write {
offset,
data: data.to_vec(),
};
let response = self.send_request(request)?;
match response {
Response::WriteResult { bytes_written } => Ok(bytes_written),
Response::Error { code, message } => Err(Error::ServiceError(code, message)),
_ => Err(Error::InvalidResponse),
}
}
fn send_request(&self, request: Request) -> Result<Response, Error> {
let request_bytes = request.to_bytes();
let mut response_bytes = [0u8; 4096];
let received = sys::channel_call(
self.port_id,
&request_bytes,
&mut response_bytes,
)?;
Response::from_bytes(&response_bytes[..received])
.map_err(|_| Error::InvalidResponse)
}
}

最常见的模式,客户端发送请求,服务器返回响应。

服务发布事件,客户端订阅感兴趣的消息。

服务发送流式数据,客户端逐步接收。

#[derive(Debug, Clone)]
pub enum ServiceError {
InvalidRequest(String),
ResourceExhausted,
PermissionDenied,
ServiceUnavailable,
Timeout,
InternalError(String),
}
// 推荐:批量处理
client.process_batch(items)?;
let shared_mem = sys_memory_create(data.len(), MEMORY_SHARED)?;
unsafe {
core::ptr::copy_nonoverlapping(
data.as_ptr(),
shared_mem.as_mut_ptr(),
data.len(),
);
}