feat: Update the redox-scheme version to 0.6 in ipcd.
This commit is contained in:
committed by
Jeremy Soller
parent
e614d267bb
commit
8a3bb40a1f
Generated
+14
-3
@@ -475,9 +475,10 @@ dependencies = [
|
||||
name = "ipcd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"libredox",
|
||||
"redox-daemon",
|
||||
"redox-scheme 0.2.4",
|
||||
"redox-scheme 0.7.0",
|
||||
"redox_event",
|
||||
"redox_syscall",
|
||||
]
|
||||
@@ -874,6 +875,16 @@ dependencies = [
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-scheme"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4da6a0251965958189cdfd5ebb66f99754db4aa165394300aa2b958525d94b64"
|
||||
dependencies = [
|
||||
"libredox",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_event"
|
||||
version = "0.4.1"
|
||||
@@ -902,9 +913,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.11"
|
||||
version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
||||
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
]
|
||||
|
||||
+2
-1
@@ -7,5 +7,6 @@ version = "0.1.0"
|
||||
libredox = "0.1.3"
|
||||
redox-daemon = "0.1.2"
|
||||
redox_syscall = "0.5"
|
||||
redox-scheme = "0.2.1"
|
||||
redox-scheme = "0.7.0"
|
||||
redox_event = "0.4.0"
|
||||
anyhow = "1.0.97"
|
||||
|
||||
+130
-80
@@ -1,24 +1,24 @@
|
||||
use redox_scheme::{scheme::SchemeSync, CallerCtx, OpenResult, Response, SignalBehavior, Socket};
|
||||
use std::{
|
||||
cmp,
|
||||
collections::{HashMap, VecDeque},
|
||||
};
|
||||
use syscall::{flag::*, error::*, Error};
|
||||
use redox_scheme::{SchemeBlockMut, V2};
|
||||
use syscall::{error::*, flag::*, schemev2::NewFdFlags, Error};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Client {
|
||||
buffer: Vec<u8>,
|
||||
remote: Connection
|
||||
remote: Connection,
|
||||
}
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Listener {
|
||||
path: Option<String>,
|
||||
awaiting: VecDeque<usize>
|
||||
awaiting: VecDeque<usize>,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum Extra {
|
||||
Client(Client),
|
||||
Listener(Listener)
|
||||
Listener(Listener),
|
||||
}
|
||||
impl Default for Extra {
|
||||
fn default() -> Self {
|
||||
@@ -29,7 +29,7 @@ impl Default for Extra {
|
||||
pub enum Connection {
|
||||
Waiting,
|
||||
Open(usize),
|
||||
Closed
|
||||
Closed,
|
||||
}
|
||||
impl Default for Connection {
|
||||
fn default() -> Self {
|
||||
@@ -66,8 +66,8 @@ impl Handle {
|
||||
Extra::Listener(ref mut listener) => {
|
||||
listener.awaiting.push_back(other);
|
||||
Ok(())
|
||||
},
|
||||
_ => Err(Error::new(EBADF))
|
||||
}
|
||||
_ => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ impl Handle {
|
||||
pub fn require_listener(&mut self) -> Result<&mut Listener> {
|
||||
match self.extra {
|
||||
Extra::Listener(ref mut listener) => Ok(listener),
|
||||
_ => Err(Error::new(EBADF))
|
||||
_ => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,36 +83,48 @@ impl Handle {
|
||||
pub fn require_client(&mut self) -> Result<&mut Client> {
|
||||
match self.extra {
|
||||
Extra::Client(ref mut client) => Ok(client),
|
||||
_ => Err(Error::new(EBADF))
|
||||
_ => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ChanScheme {
|
||||
pub struct ChanScheme<'sock> {
|
||||
handles: HashMap<usize, Handle>,
|
||||
listeners: HashMap<String, usize>,
|
||||
next_id: usize,
|
||||
pub socket: redox_scheme::Socket,
|
||||
socket: &'sock Socket,
|
||||
}
|
||||
impl ChanScheme {
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {
|
||||
impl<'sock> ChanScheme<'sock> {
|
||||
pub fn new(socket: &'sock Socket) -> Self {
|
||||
Self {
|
||||
handles: HashMap::new(),
|
||||
listeners: HashMap::new(),
|
||||
next_id: 0,
|
||||
socket: redox_scheme::Socket::<V2>::nonblock("chan")?,
|
||||
})
|
||||
socket,
|
||||
}
|
||||
}
|
||||
|
||||
fn post_fevent(&self, id: usize, flags: usize) -> Result<()> {
|
||||
let fevent_response = Response::post_fevent(id, flags);
|
||||
match self
|
||||
.socket
|
||||
.write_response(fevent_response, SignalBehavior::Restart)
|
||||
{
|
||||
Ok(true) => Ok(()), // Write response success
|
||||
Ok(false) => Err(Error::new(EAGAIN)), // Write response failed, retry.
|
||||
Err(err) => Err(err), // Error writing response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SchemeBlockMut for ChanScheme {
|
||||
impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
// ___ ____ _____ _ _
|
||||
// / _ \| _ \| ____| \ | |
|
||||
// | | | | |_) | _| | \| |
|
||||
// | |_| | __/| |___| |\ |
|
||||
// \___/|_| |_____|_| \_|
|
||||
|
||||
fn open(&mut self, path: &str, flags: usize, _uid: u32, _gid: u32) -> Result<Option<usize>> {
|
||||
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
let new_id = self.next_id;
|
||||
let mut new = Handle::default();
|
||||
new.flags = flags;
|
||||
@@ -132,20 +144,27 @@ impl SchemeBlockMut for ChanScheme {
|
||||
// Connect to existing if: O_CREAT isn't set or it already exists
|
||||
// and O_EXCL isn't set
|
||||
let listener_id = *self.listeners.get(path).ok_or(Error::new(ENOENT))?;
|
||||
let listener = self.handles.get_mut(&listener_id).expect("orphan listener left over");
|
||||
let listener = self
|
||||
.handles
|
||||
.get_mut(&listener_id)
|
||||
.expect("orphan listener left over");
|
||||
listener.connect(new_id)?;
|
||||
|
||||
// smoltcp sends writeable whenever a listener gets a
|
||||
// client, we'll do the same too (but also readable, why
|
||||
// not)
|
||||
self.socket.post_fevent(listener_id, (EVENT_READ | EVENT_WRITE).bits())?;
|
||||
self.post_fevent(listener_id, (EVENT_READ | EVENT_WRITE).bits())?;
|
||||
}
|
||||
|
||||
self.handles.insert(new_id, new);
|
||||
self.next_id += 1;
|
||||
Ok(Some(new_id))
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: new_id,
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
}
|
||||
fn dup(&mut self, id: usize, buf: &[u8]) -> Result<Option<usize>> {
|
||||
fn dup(&mut self, id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
match buf {
|
||||
b"listen" => {
|
||||
loop {
|
||||
@@ -162,28 +181,34 @@ impl SchemeBlockMut for ChanScheme {
|
||||
// mutal.
|
||||
let remote = match self.handles.get_mut(&remote_id) {
|
||||
Some(client) => client,
|
||||
None => continue // Check next client
|
||||
None => continue, // Check next client
|
||||
};
|
||||
match remote.extra {
|
||||
Extra::Client(ref mut client) => {
|
||||
client.remote = Connection::Open(new_id);
|
||||
},
|
||||
Extra::Listener(_) => panic!("newly created handle can't possibly be a listener")
|
||||
}
|
||||
Extra::Listener(_) => {
|
||||
panic!("newly created handle can't possibly be a listener")
|
||||
}
|
||||
}
|
||||
self.socket.post_fevent(remote_id, EVENT_WRITE.bits())?;
|
||||
self.post_fevent(remote_id, EVENT_WRITE.bits())?;
|
||||
|
||||
new.path = listener_path;
|
||||
|
||||
self.handles.insert(new_id, new);
|
||||
self.next_id += 1;
|
||||
Ok(Some(new_id))
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: new_id,
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
} else if handle.flags & O_NONBLOCK == O_NONBLOCK {
|
||||
Err(Error::new(EAGAIN))
|
||||
Ok(OpenResult::WouldBlock)
|
||||
} else {
|
||||
Ok(None)
|
||||
Err(Error::new(EWOULDBLOCK))
|
||||
};
|
||||
}
|
||||
},
|
||||
}
|
||||
b"connect" => {
|
||||
let new_id = self.next_id;
|
||||
let new = Handle::default();
|
||||
@@ -195,12 +220,16 @@ impl SchemeBlockMut for ChanScheme {
|
||||
// smoltcp sends writeable whenever a listener gets a
|
||||
// client, we'll do the same too (but also readable,
|
||||
// why not)
|
||||
self.socket.post_fevent(id, (EVENT_READ | EVENT_WRITE).bits())?;
|
||||
self.post_fevent(id, (EVENT_READ | EVENT_WRITE).bits())?;
|
||||
|
||||
self.handles.insert(new_id, new);
|
||||
self.next_id += 1;
|
||||
Ok(Some(new_id))
|
||||
},
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: new_id,
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
// If a buf is provided, different than "connect" / "listen",
|
||||
// turn the socket into a named socket.
|
||||
@@ -217,7 +246,7 @@ impl SchemeBlockMut for ChanScheme {
|
||||
}
|
||||
|
||||
let flags = handle.flags;
|
||||
return self.open(path, flags, 0, 0);
|
||||
return self.open(path, flags, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,7 +257,14 @@ impl SchemeBlockMut for ChanScheme {
|
||||
// | | |_| | | (_> < | |___| |__| |_| |___) | |___
|
||||
// |___\___/ \___/\/ \____|_____\___/|____/|_____|
|
||||
|
||||
fn write(&mut self, id: usize, buf: &[u8], _offset: u64, flags: u32) -> Result<Option<usize>> {
|
||||
fn write(
|
||||
&mut self,
|
||||
id: usize,
|
||||
buf: &[u8],
|
||||
_offset: u64,
|
||||
flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let client = handle.require_client()?;
|
||||
|
||||
@@ -240,27 +276,29 @@ impl SchemeBlockMut for ChanScheme {
|
||||
if client.buffer.len() == buf.len() {
|
||||
// Send readable only if it wasn't readable
|
||||
// before
|
||||
self.socket.post_fevent(remote_id, EVENT_READ.bits())?;
|
||||
self.post_fevent(remote_id, EVENT_READ.bits())?;
|
||||
}
|
||||
Ok(Some(buf.len()))
|
||||
},
|
||||
Extra::Listener(_) => panic!("somehow, a client was connected to a listener directly")
|
||||
Ok(buf.len())
|
||||
}
|
||||
Extra::Listener(_) => {
|
||||
panic!("somehow, a client was connected to a listener directly")
|
||||
}
|
||||
}
|
||||
} else if client.remote == Connection::Closed {
|
||||
Err(Error::new(EPIPE))
|
||||
} else if (flags as usize) & O_NONBLOCK == O_NONBLOCK {
|
||||
Err(Error::new(EAGAIN))
|
||||
} else {
|
||||
Ok(None)
|
||||
Err(Error::new(EWOULDBLOCK))
|
||||
}
|
||||
}
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
// Write scheme name
|
||||
const PREFIX: &[u8] = b"chan:";
|
||||
let len = cmp::min(PREFIX.len(), buf.len());
|
||||
buf[..len].copy_from_slice(&PREFIX[..len]);
|
||||
if len < PREFIX.len() {
|
||||
return Ok(Some(len));
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
// Write path
|
||||
@@ -269,14 +307,19 @@ impl SchemeBlockMut for ChanScheme {
|
||||
let len = cmp::min(path.len(), buf.len() - PREFIX.len());
|
||||
buf[PREFIX.len()..][..len].copy_from_slice(&path.as_bytes()[..len]);
|
||||
|
||||
Ok(Some(PREFIX.len() + len))
|
||||
Ok(PREFIX.len() + len)
|
||||
}
|
||||
fn fsync(&mut self, id: usize) -> Result<Option<usize>> {
|
||||
self.handles.get(&id)
|
||||
.ok_or(Error::new(EBADF))
|
||||
.and(Ok(Some(id)))
|
||||
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
|
||||
self.handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(()))
|
||||
}
|
||||
fn read(&mut self, id: usize, buf: &mut [u8], _offset: u64, flags: u32) -> Result<Option<usize>> {
|
||||
fn read(
|
||||
&mut self,
|
||||
id: usize,
|
||||
buf: &mut [u8],
|
||||
_offset: u64,
|
||||
flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let client = handle.require_client()?;
|
||||
|
||||
@@ -284,61 +327,66 @@ impl SchemeBlockMut for ChanScheme {
|
||||
let len = cmp::min(buf.len(), client.buffer.len());
|
||||
buf[..len].copy_from_slice(&client.buffer[..len]);
|
||||
client.buffer.drain(..len);
|
||||
Ok(Some(len))
|
||||
Ok(len)
|
||||
} else if client.remote == Connection::Closed {
|
||||
// Remote dropped, send EOF
|
||||
Ok(Some(0))
|
||||
Ok(0)
|
||||
} else if (flags as usize) & O_NONBLOCK == O_NONBLOCK {
|
||||
Err(Error::new(EAGAIN))
|
||||
} else {
|
||||
Ok(None)
|
||||
Err(Error::new(EWOULDBLOCK))
|
||||
}
|
||||
}
|
||||
fn close(&mut self, id: usize) -> Result<Option<usize>> {
|
||||
let handle = self.handles.remove(&id).ok_or(Error::new(EBADF))?;
|
||||
fn on_close(&mut self, id: usize) {
|
||||
let handle = self
|
||||
.handles
|
||||
.remove(&id)
|
||||
.expect("handle pointing to nothing");
|
||||
|
||||
match handle.extra {
|
||||
Extra::Client(client) => if let Connection::Open(remote_id) = client.remote {
|
||||
let remote = self.handles.get_mut(&remote_id).unwrap();
|
||||
Extra::Client(client) => {
|
||||
if let Connection::Open(remote_id) = client.remote {
|
||||
let remote = self.handles.get_mut(&remote_id).unwrap();
|
||||
|
||||
match remote.extra {
|
||||
Extra::Client(ref mut client) => {
|
||||
client.remote = Connection::Closed;
|
||||
if client.buffer.is_empty() {
|
||||
// Post readable on EOF only if it wasn't
|
||||
// readable before
|
||||
self.socket.post_fevent(remote_id, EVENT_READ.bits())?;
|
||||
match remote.extra {
|
||||
Extra::Client(ref mut client) => {
|
||||
client.remote = Connection::Closed;
|
||||
if client.buffer.is_empty() {
|
||||
// Post readable on EOF only if it wasn't
|
||||
// readable before
|
||||
self.post_fevent(remote_id, EVENT_READ.bits()).unwrap();
|
||||
}
|
||||
}
|
||||
},
|
||||
Extra::Listener(_) => panic!("a client can't be connected to a listener!")
|
||||
Extra::Listener(_) => panic!("a client can't be connected to a listener!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Extra::Listener(listener) => {
|
||||
if let Some(path) = listener.path {
|
||||
self.listeners.remove(&path);
|
||||
}
|
||||
},
|
||||
Extra::Listener(listener) => if let Some(path) = listener.path {
|
||||
self.listeners.remove(&path);
|
||||
}
|
||||
}
|
||||
Ok(Some(0))
|
||||
}
|
||||
|
||||
|
||||
// ____ _ ____ _ __ __ _____ _____ _____ ____ ____
|
||||
// | _ \ / \ | _ \ / \ | \/ | ____|_ _| ____| _ \/ ___|
|
||||
// | |_) / _ \ | |_) | / _ \ | |\/| | _| | | | _| | |_) \___ \
|
||||
// | __/ ___ \| _ < / ___ \| | | | |___ | | | |___| _ < ___) |
|
||||
// |_| /_/ \_\_| \_\/_/ \_\_| |_|_____| |_| |_____|_| \_\____/
|
||||
|
||||
fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> Result<Option<usize>> {
|
||||
fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, _ctx: &CallerCtx) -> Result<usize> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
match cmd {
|
||||
F_GETFL => Ok(Some(handle.flags)),
|
||||
F_GETFL => Ok(handle.flags),
|
||||
F_SETFL => {
|
||||
handle.flags = arg;
|
||||
Ok(Some(0))
|
||||
},
|
||||
_ => Err(Error::new(EINVAL))
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(Error::new(EINVAL)),
|
||||
}
|
||||
}
|
||||
fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result<Option<EventFlags>> {
|
||||
fn fevent(&mut self, id: usize, _flags: EventFlags, _ctx: &CallerCtx) -> Result<EventFlags> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let mut events = EventFlags::empty();
|
||||
match handle.extra {
|
||||
@@ -349,11 +397,13 @@ impl SchemeBlockMut for ChanScheme {
|
||||
if !client.buffer.is_empty() || client.remote == Connection::Closed {
|
||||
events |= EVENT_READ;
|
||||
}
|
||||
},
|
||||
Extra::Listener(ref listener) => if !listener.awaiting.is_empty() {
|
||||
events |= EVENT_READ | EVENT_WRITE;
|
||||
}
|
||||
Extra::Listener(ref listener) => {
|
||||
if !listener.awaiting.is_empty() {
|
||||
events |= EVENT_READ | EVENT_WRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Some(events))
|
||||
Ok(events)
|
||||
}
|
||||
}
|
||||
|
||||
+92
-105
@@ -1,9 +1,8 @@
|
||||
#![feature(int_roundings, let_chains)]
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use event::{EventQueue, EventFlags};
|
||||
use redox_scheme::{CallRequest, RequestKind, Response, SignalBehavior};
|
||||
use syscall::{Error, Result, EAGAIN, EWOULDBLOCK, ENODEV, EINTR};
|
||||
use event::{EventFlags, EventQueue};
|
||||
use redox_scheme::{wrappers::ReadinessBased, Socket};
|
||||
use std::sync::Mutex;
|
||||
|
||||
mod chan;
|
||||
mod shm;
|
||||
@@ -21,138 +20,126 @@ fn main() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}).expect("ipcd: failed to daemonize");
|
||||
})
|
||||
.expect("ipcd: failed to daemonize");
|
||||
}
|
||||
|
||||
fn inner(daemon: redox_daemon::Daemon) -> Result<()> {
|
||||
fn inner(daemon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
event::user_data! {
|
||||
enum EventSource {
|
||||
ChanSocket,
|
||||
ShmSocket,
|
||||
}
|
||||
}
|
||||
let chan = ChanScheme::new()?;
|
||||
let shm = ShmScheme::new()?;
|
||||
|
||||
// Prepare chan scheme
|
||||
let chan_socket = Socket::nonblock("chan")
|
||||
.map_err(|e| anyhow::anyhow!("failed to create chan scheme: {e}"))?;
|
||||
let chan = Mutex::new(ChanScheme::new(&chan_socket));
|
||||
let mut chan_handler = ReadinessBased::new(&chan_socket, 16);
|
||||
|
||||
// Prepare shm scheme
|
||||
let shm_socket =
|
||||
Socket::nonblock("shm").map_err(|e| anyhow::anyhow!("failed to create shm socket: {e}"))?;
|
||||
let shm = Mutex::new(ShmScheme::new());
|
||||
let mut shm_handler = ReadinessBased::new(&shm_socket, 16);
|
||||
|
||||
daemon.ready().unwrap();
|
||||
|
||||
// Create event listener for both files
|
||||
let mut event_queue = EventQueue::<EventSource>::new()?;
|
||||
|
||||
event_queue.subscribe(chan.socket.inner().raw(), EventSource::ChanSocket, EventFlags::READ)?;
|
||||
event_queue.subscribe(shm.socket.inner().raw(), EventSource::ShmSocket, EventFlags::READ)?;
|
||||
|
||||
struct Todo {
|
||||
req: Option<CallRequest>,
|
||||
canceling: bool,
|
||||
}
|
||||
let mut todo = VecDeque::<Todo>::with_capacity(16);
|
||||
let mut event_queue = EventQueue::<EventSource>::new()
|
||||
.map_err(|e| anyhow::anyhow!("failed to create event queue: {e}"))?;
|
||||
event_queue
|
||||
.subscribe(
|
||||
chan_socket.inner().raw(),
|
||||
EventSource::ChanSocket,
|
||||
EventFlags::READ,
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("failed to subscribe chan socket: {e}"))?;
|
||||
event_queue
|
||||
.subscribe(
|
||||
shm_socket.inner().raw(),
|
||||
EventSource::ShmSocket,
|
||||
EventFlags::READ,
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("failed to subscribe shm socket: {e}"))?;
|
||||
|
||||
libredox::call::setrens(0, 0)?;
|
||||
|
||||
let mut chan_opt = Some(chan);
|
||||
let mut shm_opt = Some(shm);
|
||||
while chan_opt.is_some() || shm_opt.is_some() {
|
||||
// EOF flags
|
||||
let mut chan_eof = false;
|
||||
let mut shm_eof = false;
|
||||
while !(chan_eof && shm_eof) {
|
||||
let Some(event_res) = event_queue.next() else {
|
||||
break;
|
||||
};
|
||||
let event = event_res?;
|
||||
let event = event_res.map_err(|e| anyhow::anyhow!("error occured in event queue: {e}"))?;
|
||||
|
||||
match event.user_data {
|
||||
EventSource::ChanSocket => {
|
||||
let mut error: Option<Error> = None;
|
||||
|
||||
let unmount = if let Some(ref mut chan) = chan_opt {
|
||||
let eof = loop {
|
||||
match chan.socket.next_request(SignalBehavior::Restart) {
|
||||
Ok(None) => break true,
|
||||
Ok(Some(request)) => match request.kind() {
|
||||
RequestKind::Call(request) => todo.push_front(Todo { req: Some(request), canceling: false }),
|
||||
RequestKind::Cancellation(request) => {
|
||||
if let Some(affected_packet) = todo.iter_mut().find(|t| t.req.as_ref().map_or(false, |r| r.request().request_id() == request.id)) {
|
||||
affected_packet.canceling = true;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Err(Error { errno: EAGAIN | EWOULDBLOCK }) => break false,
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
};
|
||||
|
||||
// Process queue, delete finished items
|
||||
todo.retain_mut(|slot| {
|
||||
let req = slot.req.take().unwrap();
|
||||
|
||||
match req.handle_scheme_block_mut(chan) {
|
||||
Some(res) => {
|
||||
if let Err(err) = chan.socket.write_response(res, SignalBehavior::Restart) {
|
||||
error = Some(err);
|
||||
}
|
||||
false
|
||||
}
|
||||
None if slot.canceling => {
|
||||
if let Err(err) = chan.socket.write_response(Response::new(&req, Err(Error::new(EINTR))), SignalBehavior::Restart) {
|
||||
error = Some(err);
|
||||
}
|
||||
false
|
||||
}
|
||||
None => {
|
||||
slot.req = Some(req);
|
||||
true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
eof
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if unmount && let Some(chan) = chan_opt.take() {
|
||||
for slot in todo.drain(..) {
|
||||
let res = if slot.canceling {
|
||||
Err(Error::new(EINTR))
|
||||
} else {
|
||||
Err(Error::new(ENODEV))
|
||||
};
|
||||
if let Err(err) = chan.socket.write_response(Response::new(&slot.req.unwrap(), res), SignalBehavior::Restart) {
|
||||
error = Some(err);
|
||||
// Channel scheme
|
||||
if !chan_eof {
|
||||
// 1. Read requests
|
||||
match chan_handler.read_requests() {
|
||||
Ok(true) => {} // Read requests success
|
||||
Ok(false) => {
|
||||
// EOF
|
||||
chan_eof = true;
|
||||
}
|
||||
Err(err) => return Err(anyhow::anyhow!("{err}")),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(err) = error {
|
||||
return Err(err);
|
||||
// 2. Process requests
|
||||
chan_handler.process_requests(|| chan.lock().unwrap());
|
||||
|
||||
// 3.Poll all blocking requests
|
||||
chan_handler
|
||||
.poll_all_requests(|| chan.lock().unwrap())
|
||||
.map_err(|e| anyhow::anyhow!("error occured in poll_all_requests: {e}"))?;
|
||||
|
||||
// 3. Write responses
|
||||
// write_responses returns a Result<bool>, but currently only returns true.
|
||||
match chan_handler.write_responses() {
|
||||
Ok(true) => {} // Read requests success
|
||||
Ok(false) => {
|
||||
// EOF
|
||||
chan_eof = true;
|
||||
}
|
||||
Err(err) => return Err(anyhow::anyhow!("{err}")),
|
||||
}
|
||||
},
|
||||
}
|
||||
EventSource::ShmSocket => {
|
||||
let unmount = if let Some(ref mut shm) = shm_opt {
|
||||
let eof = loop {
|
||||
match shm.socket.next_request(SignalBehavior::Restart) {
|
||||
Ok(None) => break true,
|
||||
Ok(Some(request)) => match request.kind() {
|
||||
RequestKind::Call(request) => {
|
||||
let response = request.handle_scheme_mut(shm);
|
||||
shm.socket.write_response(response, SignalBehavior::Restart)?;
|
||||
}
|
||||
_ => (),
|
||||
},
|
||||
Err(Error { errno: EAGAIN | EWOULDBLOCK }) => break false,
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
};
|
||||
// Shared memory scheme
|
||||
if !shm_eof {
|
||||
// 1. Read requests
|
||||
match shm_handler.read_requests() {
|
||||
Ok(true) => {} // Read requests success
|
||||
Ok(false) => {
|
||||
// EOF
|
||||
shm_eof = true;
|
||||
}
|
||||
Err(err) => return Err(anyhow::anyhow!("{err}")),
|
||||
}
|
||||
}
|
||||
|
||||
eof
|
||||
} else {
|
||||
false
|
||||
};
|
||||
// 2. Process requests
|
||||
shm_handler.process_requests(|| shm.lock().unwrap());
|
||||
|
||||
if unmount {
|
||||
shm_opt.take();
|
||||
// shm is not a blocking scheme
|
||||
|
||||
// 3. Write responses
|
||||
// write_responses returns a Result<bool>, but currently only returns true.
|
||||
match shm_handler.write_responses() {
|
||||
Ok(true) => {} // Read requests success
|
||||
Ok(false) => {
|
||||
// EOF
|
||||
shm_eof = true;
|
||||
}
|
||||
Err(err) => return Err(anyhow::anyhow!("{err}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+50
-26
@@ -1,45 +1,51 @@
|
||||
use redox_scheme::{scheme::SchemeSync, CallerCtx, OpenResult};
|
||||
use std::{
|
||||
cmp,
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
collections::{hash_map::Entry, HashMap},
|
||||
rc::Rc,
|
||||
};
|
||||
use syscall::{error::*, Error, Map, Result, MapFlags, PAGE_SIZE, MAP_PRIVATE};
|
||||
use redox_scheme::{SchemeMut, V2};
|
||||
use syscall::{
|
||||
error::*, schemev2::NewFdFlags, Error, Map, MapFlags, Result, MAP_PRIVATE, PAGE_SIZE,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ShmHandle {
|
||||
buffer: Option<MmapGuard>,
|
||||
refs: usize
|
||||
refs: usize,
|
||||
}
|
||||
pub struct ShmScheme {
|
||||
maps: HashMap<Rc<str>, ShmHandle>,
|
||||
handles: HashMap<usize, Rc<str>>,
|
||||
next_id: usize,
|
||||
pub socket: redox_scheme::Socket,
|
||||
}
|
||||
impl ShmScheme {
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
maps: HashMap::new(),
|
||||
handles: HashMap::new(),
|
||||
next_id: 0,
|
||||
socket: redox_scheme::Socket::<V2>::nonblock("shm")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SchemeMut for ShmScheme {
|
||||
fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
|
||||
impl SchemeSync for ShmScheme {
|
||||
fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
let path = Rc::from(path);
|
||||
let entry = self.maps.entry(Rc::clone(&path)).or_insert(ShmHandle::default());
|
||||
let entry = self
|
||||
.maps
|
||||
.entry(Rc::clone(&path))
|
||||
.or_insert(ShmHandle::default());
|
||||
entry.refs += 1;
|
||||
self.handles.insert(self.next_id, path);
|
||||
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
Ok(id)
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
}
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
// Write scheme name
|
||||
const PREFIX: &[u8] = b"shm:";
|
||||
let len = cmp::min(PREFIX.len(), buf.len());
|
||||
@@ -55,29 +61,40 @@ impl SchemeMut for ShmScheme {
|
||||
|
||||
Ok(PREFIX.len() + len)
|
||||
}
|
||||
fn close(&mut self, id: usize) -> Result<usize> {
|
||||
let path = self.handles.remove(&id).ok_or(Error::new(EBADF))?;
|
||||
fn on_close(&mut self, id: usize) {
|
||||
let path = self.handles.remove(&id).unwrap();
|
||||
let mut entry = match self.maps.entry(path) {
|
||||
Entry::Occupied(entry) => entry,
|
||||
Entry::Vacant(_) => panic!("handle pointing to nothing")
|
||||
Entry::Vacant(_) => panic!("handle pointing to nothing"),
|
||||
};
|
||||
entry.get_mut().refs -= 1;
|
||||
if entry.get().refs == 0 {
|
||||
// There is no other reference to this entry, drop
|
||||
entry.remove_entry();
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, _: MapFlags) -> Result<usize> {
|
||||
fn mmap_prep(
|
||||
&mut self,
|
||||
id: usize,
|
||||
offset: u64,
|
||||
size: usize,
|
||||
_flags: MapFlags,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
let path = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
let total_size = offset as usize + size;
|
||||
match self.maps.get_mut(path).expect("handle pointing to nothing").buffer {
|
||||
match self
|
||||
.maps
|
||||
.get_mut(path)
|
||||
.expect("handle pointing to nothing")
|
||||
.buffer
|
||||
{
|
||||
Some(ref mut buf) => {
|
||||
if total_size > buf.len() {
|
||||
return Err(Error::new(ERANGE));
|
||||
}
|
||||
Ok(buf.as_ptr() + offset as usize)
|
||||
},
|
||||
}
|
||||
ref mut buf @ None => {
|
||||
*buf = Some(MmapGuard::alloc(size.div_ceil(PAGE_SIZE))?);
|
||||
Ok(buf.as_mut().unwrap().as_ptr() + offset as usize)
|
||||
@@ -93,12 +110,19 @@ pub struct MmapGuard {
|
||||
impl MmapGuard {
|
||||
pub fn alloc(page_count: usize) -> Result<Self> {
|
||||
let size = page_count * PAGE_SIZE;
|
||||
let base = unsafe { syscall::fmap(!0, &Map { offset: 0, size, flags: MAP_PRIVATE, address: 0 }) }?;
|
||||
let base = unsafe {
|
||||
syscall::fmap(
|
||||
!0,
|
||||
&Map {
|
||||
offset: 0,
|
||||
size,
|
||||
flags: MAP_PRIVATE,
|
||||
address: 0,
|
||||
},
|
||||
)
|
||||
}?;
|
||||
|
||||
Ok(Self {
|
||||
base,
|
||||
size,
|
||||
})
|
||||
Ok(Self { base, size })
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.size
|
||||
|
||||
Reference in New Issue
Block a user