Add separate scheme for fmap
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
[package]
|
||||
name = "ipcd"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
redox_syscall = "0.1.40"
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
extern crate syscall;
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, prelude::*},
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
extern crate syscall;
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, prelude::*},
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
extern crate syscall;
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, prelude::*},
|
||||
@@ -0,0 +1,41 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
io,
|
||||
os::unix::io::AsRawFd,
|
||||
slice
|
||||
};
|
||||
|
||||
fn from_syscall_error(error: syscall::Error) -> io::Error {
|
||||
io::Error::from_raw_os_error(error.errno as i32)
|
||||
}
|
||||
fn main() -> Result<(), io::Error> {
|
||||
let file1 = File::open("shm:example")?;
|
||||
let file2 = File::open("shm:example")?;
|
||||
|
||||
let one = unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
syscall::fmap(file1.as_raw_fd(), 0, 128).map_err(from_syscall_error)? as *mut u8,
|
||||
128
|
||||
)
|
||||
};
|
||||
let two = unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
syscall::fmap(file2.as_raw_fd(), 64, 64).map_err(from_syscall_error)? as *mut u8,
|
||||
64
|
||||
)
|
||||
};
|
||||
|
||||
println!("Testing writing between");
|
||||
for i in 0..128 {
|
||||
one[i as usize] = i;
|
||||
}
|
||||
for i in 0..64 {
|
||||
assert_eq!(two[i as usize], 64 + i);
|
||||
}
|
||||
|
||||
println!("Testing fpath");
|
||||
let mut buf = [0; 128];
|
||||
let len = syscall::fpath(file1.as_raw_fd(), &mut buf).map_err(from_syscall_error)?;
|
||||
assert_eq!(&buf[..len], b"shm:example");
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
io,
|
||||
mem,
|
||||
os::unix::io::AsRawFd,
|
||||
thread,
|
||||
time::Duration
|
||||
};
|
||||
|
||||
fn from_syscall_error(error: syscall::Error) -> io::Error {
|
||||
io::Error::from_raw_os_error(error.errno as i32)
|
||||
}
|
||||
fn main() -> Result<(), io::Error> {
|
||||
let file = File::open("shm:counter")?;
|
||||
println!("Reading from map... ");
|
||||
let counter = unsafe {
|
||||
&mut *(syscall::fmap(file.as_raw_fd(), 0, mem::size_of::<usize>()).map_err(from_syscall_error)? as *mut usize)
|
||||
};
|
||||
println!("Read value {}", counter);
|
||||
*counter += 1;
|
||||
println!("Increased value to {}", counter);
|
||||
|
||||
loop {
|
||||
thread::sleep(Duration::from_secs(std::u64::MAX));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
extern crate syscall;
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, prelude::*},
|
||||
|
||||
+12
-11
@@ -1,6 +1,7 @@
|
||||
use post_fevent;
|
||||
use crate::post_fevent;
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
cmp,
|
||||
collections::HashMap,
|
||||
fs::File,
|
||||
io,
|
||||
mem
|
||||
@@ -69,12 +70,12 @@ impl Handle {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct IpcScheme {
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
listeners: BTreeMap<String, usize>,
|
||||
pub struct ChanScheme {
|
||||
handles: HashMap<usize, Handle>,
|
||||
listeners: HashMap<String, usize>,
|
||||
next_id: usize
|
||||
}
|
||||
impl IpcScheme {
|
||||
impl ChanScheme {
|
||||
pub fn post_fevents(&mut self, file: &mut File) -> io::Result<()> {
|
||||
for (id, handle) in &mut self.handles {
|
||||
match handle.extra {
|
||||
@@ -116,7 +117,7 @@ fn connect(target: &mut Handle, new_id: usize) -> Result<()> {
|
||||
target.remote = Connection::Open(new_id);
|
||||
Ok(())
|
||||
}
|
||||
impl SchemeBlockMut for IpcScheme {
|
||||
impl SchemeBlockMut for ChanScheme {
|
||||
fn open(&mut self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result<Option<usize>> {
|
||||
let path = ::std::str::from_utf8(path).or(Err(Error::new(EPERM)))?;
|
||||
|
||||
@@ -155,7 +156,7 @@ impl SchemeBlockMut for IpcScheme {
|
||||
if let Connection::Open(remote_id) = remote {
|
||||
let new_id = self.next_id;
|
||||
|
||||
let mut clone = self.handles.get_mut(&id).map(Handle::accept).unwrap();
|
||||
let clone = self.handles.get_mut(&id).map(Handle::accept).unwrap();
|
||||
|
||||
{
|
||||
// This might fail if the remote side closed early
|
||||
@@ -174,7 +175,7 @@ impl SchemeBlockMut for IpcScheme {
|
||||
}
|
||||
},
|
||||
b"connect" => {
|
||||
let mut new = Handle::default();
|
||||
let new = Handle::default();
|
||||
let new_id = self.next_id;
|
||||
|
||||
{
|
||||
@@ -217,7 +218,7 @@ impl SchemeBlockMut for IpcScheme {
|
||||
(handle.flags, handle.remote)
|
||||
};
|
||||
if let Connection::Open(remote_id) = remote {
|
||||
let mut remote = self.handles.get_mut(&remote_id).unwrap();
|
||||
let remote = self.handles.get_mut(&remote_id).unwrap();
|
||||
match remote.extra {
|
||||
Extra::Client(ref mut client) => {
|
||||
client.buffer.extend(buf);
|
||||
@@ -247,7 +248,7 @@ impl SchemeBlockMut for IpcScheme {
|
||||
};
|
||||
|
||||
if !client.buffer.is_empty() {
|
||||
let len = buf.len().min(client.buffer.len());
|
||||
let len = cmp::min(buf.len(), client.buffer.len());
|
||||
buf[..len].copy_from_slice(&client.buffer[..len]);
|
||||
client.buffer.drain(..len);
|
||||
Ok(Some(len))
|
||||
+68
-30
@@ -1,61 +1,99 @@
|
||||
extern crate syscall;
|
||||
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
fs::File,
|
||||
io::{self, prelude::*}
|
||||
io::{self, prelude::*},
|
||||
os::unix::io::AsRawFd
|
||||
};
|
||||
use syscall::SchemeBlockMut;
|
||||
use syscall::{flag::*, Event, Packet, SchemeBlockMut, SchemeMut};
|
||||
|
||||
mod scheme;
|
||||
mod chan;
|
||||
mod shm;
|
||||
|
||||
use scheme::IpcScheme;
|
||||
use self::chan::ChanScheme;
|
||||
use self::shm::ShmScheme;
|
||||
|
||||
fn from_syscall_error(error: syscall::Error) -> io::Error {
|
||||
io::Error::from_raw_os_error(error.errno as i32)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<::std::error::Error>> {
|
||||
const TOKEN_CHAN: usize = 0;
|
||||
const TOKEN_SHM: usize = 1;
|
||||
|
||||
fn main() -> Result<(), Box<dyn ::std::error::Error>> {
|
||||
if unsafe { syscall::clone(0) }.map_err(from_syscall_error)? != 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut scheme_file = File::create(":chan")?;
|
||||
let mut scheme = IpcScheme::default();
|
||||
// Create event listener for both files
|
||||
let mut event_file = File::open("event:")?;
|
||||
|
||||
let mut chan_file = File::create(":chan")?;
|
||||
event_file.write(&Event {
|
||||
id: chan_file.as_raw_fd() as usize,
|
||||
flags: EVENT_READ,
|
||||
data: TOKEN_CHAN
|
||||
})?;
|
||||
|
||||
let mut shm_file = File::create(":shm")?;
|
||||
event_file.write(&Event {
|
||||
id: shm_file.as_raw_fd() as usize,
|
||||
flags: EVENT_READ,
|
||||
data: TOKEN_SHM
|
||||
})?;
|
||||
|
||||
let mut chan = ChanScheme::default();
|
||||
let mut shm = ShmScheme::default();
|
||||
let mut todo = VecDeque::with_capacity(16);
|
||||
|
||||
syscall::setrens(0, 0).map_err(from_syscall_error)?;
|
||||
|
||||
loop {
|
||||
let mut event = syscall::Packet::default();
|
||||
scheme_file.read(&mut event)?;
|
||||
let mut event = Event::default();
|
||||
event_file.read(&mut event)?;
|
||||
|
||||
// New event has to be handled first so any previous event
|
||||
// that is now updated gets processed after.
|
||||
todo.push_front(event);
|
||||
match event.data {
|
||||
TOKEN_CHAN => {
|
||||
let mut packet = Packet::default();
|
||||
chan_file.read(&mut packet)?;
|
||||
|
||||
let mut error = None;
|
||||
// Put new packet first in the queue
|
||||
todo.push_front(packet);
|
||||
|
||||
todo.retain(|event| {
|
||||
if let Some(a) = scheme.handle(&event) {
|
||||
// Send event back with new ID
|
||||
let mut event = *event;
|
||||
event.a = a;
|
||||
if let Err(err) = scheme_file.write(&event) {
|
||||
error = Some(err);
|
||||
let mut error: Option<io::Error> = None;
|
||||
|
||||
// Process queue, delete finished items
|
||||
todo.retain(|packet| {
|
||||
if let Some(status) = chan.handle(&packet) {
|
||||
// Send packet back with new ID
|
||||
let mut packet = *packet;
|
||||
packet.a = status;
|
||||
if let Err(err) = chan_file.write(&packet) {
|
||||
error = Some(err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
|
||||
if let Some(err) = error {
|
||||
return Err(Box::new(err));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
// Handle fevents
|
||||
chan.post_fevents(&mut chan_file)?;
|
||||
},
|
||||
TOKEN_SHM => {
|
||||
let mut packet = Packet::default();
|
||||
shm_file.read(&mut packet)?;
|
||||
|
||||
if let Some(err) = error {
|
||||
return Err(Box::new(err));
|
||||
// Handle packet and update `a` to be status code
|
||||
shm.handle(&mut packet);
|
||||
|
||||
shm_file.write(&packet)?;
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
|
||||
scheme.post_fevents(&mut scheme_file)?;
|
||||
}
|
||||
}
|
||||
fn post_fevent(file: &mut File, id: usize, flag: usize) -> io::Result<()> {
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
use std::{
|
||||
cmp,
|
||||
collections::{HashMap, hash_map::Entry},
|
||||
rc::Rc
|
||||
};
|
||||
use syscall::{error::*, Error, SchemeMut, Result};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ShmHandle {
|
||||
buffer: Option<Box<[u8]>>,
|
||||
refs: usize
|
||||
}
|
||||
#[derive(Default)]
|
||||
pub struct ShmScheme {
|
||||
maps: HashMap<Rc<str>, ShmHandle>,
|
||||
handles: HashMap<usize, Rc<str>>,
|
||||
next_id: usize
|
||||
}
|
||||
|
||||
impl SchemeMut for ShmScheme {
|
||||
fn open(&mut self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
|
||||
let path = std::str::from_utf8(path).or(Err(Error::new(EPERM)))?.into();
|
||||
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)
|
||||
}
|
||||
fn fmap(&mut self, id: usize, offset: usize, len: usize) -> Result<usize> {
|
||||
let path = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
match self.maps.get_mut(path).expect("handle pointing to nothing").buffer {
|
||||
Some(ref mut buf) => {
|
||||
if offset + len != buf.len() {
|
||||
return Err(Error::new(ERANGE));
|
||||
}
|
||||
Ok(buf[offset..].as_mut_ptr() as usize)
|
||||
},
|
||||
ref mut buf @ None => {
|
||||
*buf = Some(vec![0; offset+len].into_boxed_slice());
|
||||
Ok(buf.as_mut().unwrap()[offset..].as_mut_ptr() as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
// Write scheme name
|
||||
const PREFIX: &[u8] = b"shm:";
|
||||
let len = cmp::min(PREFIX.len(), buf.len());
|
||||
buf[..len].copy_from_slice(&PREFIX[..len]);
|
||||
if len < PREFIX.len() {
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
// Write path
|
||||
let path = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
let len = cmp::min(path.len(), buf.len() - PREFIX.len());
|
||||
buf[PREFIX.len()..][..len].copy_from_slice(&path.as_bytes()[..len]);
|
||||
|
||||
Ok(PREFIX.len() + len)
|
||||
}
|
||||
fn close(&mut self, id: usize) -> Result<usize> {
|
||||
let path = self.handles.remove(&id).ok_or(Error::new(EBADF))?;
|
||||
let mut entry = match self.maps.entry(path) {
|
||||
Entry::Occupied(entry) => entry,
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user