Implement user schemes. Example in pcid. Currently deadlocks in UserInner
This commit is contained in:
parent
c512d04378
commit
791dbfa7ad
9 changed files with 231 additions and 79 deletions
|
@ -1,7 +1,8 @@
|
|||
use alloc::arc::Weak;
|
||||
use collections::{BTreeMap, VecDeque};
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use core::{mem, usize};
|
||||
use spin::RwLock;
|
||||
use spin::Mutex;
|
||||
|
||||
use context;
|
||||
use syscall::{convert_to_result, Call, Error, Result};
|
||||
|
@ -18,109 +19,125 @@ pub struct Packet {
|
|||
pub d: usize
|
||||
}
|
||||
|
||||
/// UserScheme has to be wrapped
|
||||
pub struct UserScheme {
|
||||
pub struct UserInner {
|
||||
next_id: AtomicUsize,
|
||||
todo: RwLock<VecDeque<Packet>>,
|
||||
done: RwLock<BTreeMap<usize, usize>>
|
||||
todo: Mutex<VecDeque<Packet>>,
|
||||
done: Mutex<BTreeMap<usize, usize>>
|
||||
}
|
||||
|
||||
impl UserScheme {
|
||||
fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result<usize> {
|
||||
impl UserInner {
|
||||
pub fn new() -> UserInner {
|
||||
UserInner {
|
||||
next_id: AtomicUsize::new(0),
|
||||
todo: Mutex::new(VecDeque::new()),
|
||||
done: Mutex::new(BTreeMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call(&self, a: Call, b: usize, c: usize, d: usize) -> Result<usize> {
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
self.todo.write().push_back(Packet {
|
||||
let packet = Packet {
|
||||
id: id,
|
||||
a: a as usize,
|
||||
b: b,
|
||||
c: c,
|
||||
d: d
|
||||
});
|
||||
};
|
||||
|
||||
self.todo.lock().push_back(packet);
|
||||
|
||||
loop {
|
||||
if let Some(a) = self.done.write().remove(&id) {
|
||||
if let Some(a) = self.done.lock().remove(&id) {
|
||||
return convert_to_result(a);
|
||||
}
|
||||
|
||||
unsafe { context::switch(); }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
let packet_size = mem::size_of::<Packet>();
|
||||
let len = buf.len()/packet_size;
|
||||
if len > 0 {
|
||||
loop {
|
||||
let mut i = 0;
|
||||
{
|
||||
let mut todo = self.todo.lock();
|
||||
while ! todo.is_empty() && i < len {
|
||||
let packet = todo.pop_front().unwrap();
|
||||
unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = packet; }
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
return Ok(i * packet_size);
|
||||
} else {
|
||||
unsafe { context::switch(); }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> Result<usize> {
|
||||
let packet_size = mem::size_of::<Packet>();
|
||||
let len = buf.len()/packet_size;
|
||||
let mut i = 0;
|
||||
while i < len {
|
||||
let packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) };
|
||||
self.done.lock().insert(packet.id, packet.a);
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Ok(i * packet_size)
|
||||
}
|
||||
}
|
||||
|
||||
/// UserInner has to be wrapped
|
||||
pub struct UserScheme {
|
||||
inner: Weak<UserInner>
|
||||
}
|
||||
|
||||
impl UserScheme {
|
||||
pub fn new(inner: Weak<UserInner>) -> UserScheme {
|
||||
UserScheme {
|
||||
inner: inner
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheme for UserScheme {
|
||||
fn open(&self, path: &[u8], flags: usize) -> Result<usize> {
|
||||
self.call(Call::Open, path.as_ptr() as usize, path.len(), flags)
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::Open, path.as_ptr() as usize, path.len(), flags)
|
||||
}
|
||||
|
||||
fn dup(&self, file: usize) -> Result<usize> {
|
||||
if file == usize::MAX {
|
||||
Ok(file)
|
||||
} else {
|
||||
self.call(Call::Dup, file, 0, 0)
|
||||
}
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::Dup, file, 0, 0)
|
||||
}
|
||||
|
||||
fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
if file == usize::MAX {
|
||||
let packet_size = mem::size_of::<Packet>();
|
||||
let len = buf.len()/packet_size;
|
||||
if len > 0 {
|
||||
loop {
|
||||
let mut i = 0;
|
||||
{
|
||||
let mut todo = self.todo.write();
|
||||
while ! todo.is_empty() && i < len {
|
||||
unsafe { *(buf.as_mut_ptr() as *mut Packet).offset(i as isize) = todo.pop_front().unwrap(); }
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
return Ok(i * packet_size);
|
||||
} else {
|
||||
unsafe { context::switch(); }
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(0)
|
||||
}
|
||||
} else {
|
||||
self.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len())
|
||||
}
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::Read, file, buf.as_mut_ptr() as usize, buf.len())
|
||||
}
|
||||
|
||||
fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
|
||||
if file == usize::MAX {
|
||||
let packet_size = mem::size_of::<Packet>();
|
||||
let len = buf.len()/packet_size;
|
||||
let mut i = 0;
|
||||
while i < len {
|
||||
let packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) };
|
||||
self.done.write().insert(packet.id, packet.a);
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Ok(i * packet_size)
|
||||
} else {
|
||||
self.call(Call::Write, file, buf.as_ptr() as usize, buf.len())
|
||||
}
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::Write, file, buf.as_ptr() as usize, buf.len())
|
||||
}
|
||||
|
||||
fn fsync(&self, file: usize) -> Result<()> {
|
||||
if file == usize::MAX {
|
||||
Ok(())
|
||||
} else {
|
||||
self.call(Call::FSync, file, 0, 0).and(Ok(()))
|
||||
}
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::FSync, file, 0, 0).and(Ok(()))
|
||||
}
|
||||
|
||||
fn close(&self, file: usize) -> Result<()> {
|
||||
if file == usize::MAX {
|
||||
println!("Close user scheme");
|
||||
Ok(())
|
||||
} else {
|
||||
self.call(Call::Close, file, 0, 0).and(Ok(()))
|
||||
}
|
||||
let inner = self.inner.upgrade().ok_or(Error::NoDevice)?;
|
||||
inner.call(Call::Close, file, 0, 0).and(Ok(()))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue