From 7a5d9d440cc7fc986ffda4d6852574d9ef3cbad2 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Tue, 20 Sep 2016 08:47:16 -0600
Subject: [PATCH] Implement user schemes. Example in pcid. Currently deadlocks
 in UserInner

---
 scheme/mod.rs  |  13 +++--
 scheme/root.rs |  84 +++++++++++++++++++++++++++
 scheme/user.rs | 153 +++++++++++++++++++++++++++----------------------
 3 files changed, 178 insertions(+), 72 deletions(-)
 create mode 100644 scheme/root.rs

diff --git a/scheme/mod.rs b/scheme/mod.rs
index f4340a06..d53688bc 100644
--- a/scheme/mod.rs
+++ b/scheme/mod.rs
@@ -19,6 +19,7 @@ use self::debug::DebugScheme;
 use self::env::EnvScheme;
 use self::initfs::InitFsScheme;
 use self::irq::IrqScheme;
+use self::root::RootScheme;
 
 /// Debug scheme
 pub mod debug;
@@ -32,6 +33,9 @@ pub mod initfs;
 /// IRQ handling
 pub mod irq;
 
+/// Root scheme
+pub mod root;
+
 /// Userspace schemes
 pub mod user;
 
@@ -102,10 +106,11 @@ static SCHEMES: Once<RwLock<SchemeList>> = Once::new();
 /// Initialize schemes, called if needed
 fn init_schemes() -> RwLock<SchemeList> {
     let mut list: SchemeList = SchemeList::new();
-    list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug: scheme");
-    list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env: scheme");
-    list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs: scheme");
-    list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq: scheme");
+    list.insert(Box::new(*b""), Arc::new(Box::new(RootScheme::new()))).expect("failed to insert root scheme");
+    list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug scheme");
+    list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env scheme");
+    list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs scheme");
+    list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq scheme");
     RwLock::new(list)
 }
 
diff --git a/scheme/root.rs b/scheme/root.rs
new file mode 100644
index 00000000..14cf55ea
--- /dev/null
+++ b/scheme/root.rs
@@ -0,0 +1,84 @@
+use alloc::arc::Arc;
+use alloc::boxed::Box;
+use collections::BTreeMap;
+use core::sync::atomic::{AtomicUsize, Ordering};
+use core::str;
+use spin::RwLock;
+
+use syscall::{Error, Result};
+use scheme::{self, Scheme};
+use scheme::user::{UserInner, UserScheme};
+
+pub struct RootScheme {
+    next_id: AtomicUsize,
+    handles: RwLock<BTreeMap<usize, Arc<UserInner>>>
+}
+
+impl RootScheme {
+    pub fn new() -> RootScheme {
+        RootScheme {
+            next_id: AtomicUsize::new(0),
+            handles: RwLock::new(BTreeMap::new())
+        }
+    }
+}
+
+impl Scheme for RootScheme {
+    fn open(&self, path: &[u8], flags: usize) -> Result<usize> {
+        let inner = {
+            let mut schemes = scheme::schemes_mut();
+            if schemes.get_name(path).is_some() {
+                return Err(Error::FileExists);
+            }
+            let inner = Arc::new(UserInner::new());
+            schemes.insert(path.to_vec().into_boxed_slice(), Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))).expect("failed to insert user scheme");
+            inner
+        };
+
+        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
+        self.handles.write().insert(id, inner);
+
+        Ok(id)
+    }
+
+    fn dup(&self, file: usize) -> Result<usize> {
+        let inner = {
+            let handles = self.handles.read();
+            let inner = handles.get(&file).ok_or(Error::BadFile)?;
+            inner.clone()
+        };
+
+        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
+        self.handles.write().insert(id, inner);
+
+        Ok(id)
+    }
+
+    fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> {
+        let inner = {
+            let handles = self.handles.read();
+            let inner = handles.get(&file).ok_or(Error::BadFile)?;
+            inner.clone()
+        };
+
+        inner.read(buf)
+    }
+
+    fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
+        let inner = {
+            let handles = self.handles.read();
+            let inner = handles.get(&file).ok_or(Error::BadFile)?;
+            inner.clone()
+        };
+
+        inner.write(buf)
+    }
+
+    fn fsync(&self, _file: usize) -> Result<()> {
+        Ok(())
+    }
+
+    fn close(&self, file: usize) -> Result<()> {
+        self.handles.write().remove(&file).ok_or(Error::BadFile).and(Ok(()))
+    }
+}
diff --git a/scheme/user.rs b/scheme/user.rs
index 6ff446ac..691ae024 100644
--- a/scheme/user.rs
+++ b/scheme/user.rs
@@ -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(()))
     }
 }
-- 
GitLab