feat: Update the redox-scheme version to 0.6 in ipcd.

This commit is contained in:
Ibuki Omatsu
2025-07-11 03:01:40 +00:00
committed by Jeremy Soller
parent e614d267bb
commit 8a3bb40a1f
5 changed files with 288 additions and 215 deletions
Generated
+14 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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