From b18e322c3f51d636847464a81d0f5a2c84d350ac Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jeremy@system76.com>
Date: Fri, 28 Dec 2018 21:53:40 -0700
Subject: [PATCH] WIP: itimer and sigprocmask

---
 Cargo.lock             |   4 +-
 src/scheme/itimer.rs   | 110 +++++++++++++++++++++++++++++++++++++++++
 src/scheme/mod.rs      |   5 ++
 src/syscall/debug.rs   |   6 +++
 src/syscall/mod.rs     |  13 +++++
 src/syscall/process.rs |   5 ++
 syscall                |   2 +-
 7 files changed, 142 insertions(+), 3 deletions(-)
 create mode 100644 src/scheme/itimer.rs

diff --git a/Cargo.lock b/Cargo.lock
index 8eafacfd..a243fc86 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -178,7 +178,7 @@ dependencies = [
  "goblin 0.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "raw-cpuid 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "redox_syscall 0.1.45",
+ "redox_syscall 0.1.49",
  "slab_allocator 0.3.1",
  "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "x86 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -279,7 +279,7 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.1.45"
+version = "0.1.49"
 
 [[package]]
 name = "regex"
diff --git a/src/scheme/itimer.rs b/src/scheme/itimer.rs
new file mode 100644
index 00000000..2eaae089
--- /dev/null
+++ b/src/scheme/itimer.rs
@@ -0,0 +1,110 @@
+use alloc::collections::BTreeMap;
+use core::{mem, slice, str};
+use core::sync::atomic::{AtomicUsize, Ordering};
+use spin::RwLock;
+
+use syscall::data::ITimerSpec;
+use syscall::error::*;
+use syscall::flag::{CLOCK_REALTIME, CLOCK_MONOTONIC};
+use syscall::scheme::Scheme;
+
+pub struct ITimerScheme {
+    next_id: AtomicUsize,
+    handles: RwLock<BTreeMap<usize, usize>>
+}
+
+impl ITimerScheme {
+    pub fn new() -> ITimerScheme {
+        ITimerScheme {
+            next_id: AtomicUsize::new(0),
+            handles: RwLock::new(BTreeMap::new())
+        }
+    }
+}
+
+impl Scheme for ITimerScheme {
+    fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
+        let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?;
+
+        let clock = path_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
+
+        match clock {
+            CLOCK_REALTIME => (),
+            CLOCK_MONOTONIC => (),
+            _ => return Err(Error::new(ENOENT))
+        }
+
+        let id = self.next_id.fetch_add(1, Ordering::SeqCst);
+        self.handles.write().insert(id, clock);
+
+        Ok(id)
+    }
+
+    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
+        let clock = {
+            let handles = self.handles.read();
+            *handles.get(&id).ok_or(Error::new(EBADF))?
+        };
+
+        let time_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut ITimerSpec, buf.len()/mem::size_of::<ITimerSpec>()) };
+
+        let mut i = 0;
+        while i < time_buf.len() {
+            time_buf[i] = ITimerSpec::default();
+            i += 1;
+        }
+
+        Ok(i * mem::size_of::<ITimerSpec>())
+    }
+
+    fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
+        let clock = {
+            let handles = self.handles.read();
+            *handles.get(&id).ok_or(Error::new(EBADF))?
+        };
+
+        let time_buf = unsafe { slice::from_raw_parts(buf.as_ptr() as *const ITimerSpec, buf.len()/mem::size_of::<ITimerSpec>()) };
+
+        let mut i = 0;
+        while i < time_buf.len() {
+            let time = time_buf[i];
+            println!("{}: {:?}", i, time);
+            i += 1;
+        }
+
+        Ok(i * mem::size_of::<ITimerSpec>())
+    }
+
+    fn fcntl(&self, _id: usize, _cmd: usize, _arg: usize) -> Result<usize> {
+        Ok(0)
+    }
+
+    fn fevent(&self, id: usize, _flags: usize) ->  Result<usize> {
+        let handles = self.handles.read();
+        handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(id))
+    }
+
+    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
+        let clock = {
+            let handles = self.handles.read();
+            *handles.get(&id).ok_or(Error::new(EBADF))?
+        };
+
+        let mut i = 0;
+        let scheme_path = format!("time:{}", clock).into_bytes();
+        while i < buf.len() && i < scheme_path.len() {
+            buf[i] = scheme_path[i];
+            i += 1;
+        }
+        Ok(i)
+    }
+
+    fn fsync(&self, id: usize) -> Result<usize> {
+        let handles = self.handles.read();
+        handles.get(&id).ok_or(Error::new(EBADF)).and(Ok(0))
+    }
+
+    fn close(&self, id: usize) -> Result<usize> {
+        self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0))
+    }
+}
diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs
index 882ea78c..1abacd75 100644
--- a/src/scheme/mod.rs
+++ b/src/scheme/mod.rs
@@ -19,6 +19,7 @@ use self::debug::DebugScheme;
 use self::event::EventScheme;
 use self::initfs::InitFsScheme;
 use self::irq::IrqScheme;
+use self::itimer::ITimerScheme;
 use self::memory::MemoryScheme;
 use self::pipe::PipeScheme;
 use self::root::RootScheme;
@@ -37,6 +38,9 @@ pub mod initfs;
 /// `irq:` - allows userspace handling of IRQs
 pub mod irq;
 
+/// `itimer:` - support for getitimer and setitimer
+pub mod itimer;
+
 /// When compiled with "live" feature - `disk:` - embedded filesystem for live disk
 #[cfg(feature="live")]
 pub mod live;
@@ -115,6 +119,7 @@ impl SchemeList {
 
         self.insert(ns, Box::new(*b""), |scheme_id| Arc::new(Box::new(RootScheme::new(ns, scheme_id)))).unwrap();
         self.insert(ns, Box::new(*b"event"), |_| Arc::new(Box::new(EventScheme))).unwrap();
+        self.insert(ns, Box::new(*b"itimer"), |_| Arc::new(Box::new(ITimerScheme::new()))).unwrap();
         self.insert(ns, Box::new(*b"memory"), |_| Arc::new(Box::new(MemoryScheme::new()))).unwrap();
         self.insert(ns, Box::new(*b"sys"), |_| Arc::new(Box::new(SysScheme::new()))).unwrap();
         self.insert(ns, Box::new(*b"time"), |scheme_id| Arc::new(Box::new(TimeScheme::new(scheme_id)))).unwrap();
diff --git a/src/syscall/debug.rs b/src/syscall/debug.rs
index 7f746c68..70cf9d5c 100644
--- a/src/syscall/debug.rs
+++ b/src/syscall/debug.rs
@@ -254,6 +254,12 @@ pub fn format_call(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -
             d,
             e
         ),
+        SYS_SIGPROCMASK => format!(
+            "sigprocmask({}, {:?}, {:?})",
+            b,
+            validate_slice(c as *const [u64; 2], 1),
+            validate_slice(d as *const [u64; 2], 1)
+        ),
         SYS_MKNS => format!(
             "mkns({:?})",
             validate_slice(b as *const [usize; 2], c)
diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs
index 5528e69b..3f97a4ef 100644
--- a/src/syscall/mod.rs
+++ b/src/syscall/mod.rs
@@ -125,6 +125,19 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u
                     },
                     e
                 ),
+                SYS_SIGPROCMASK => sigprocmask(
+                    b,
+                    if c == 0 {
+                        None
+                    } else {
+                        Some(validate_slice(c as *const [u64; 2], 1).map(|s| &s[0])?)
+                    },
+                    if d == 0 {
+                        None
+                    } else {
+                        Some(validate_slice_mut(d as *mut [u64; 2], 1).map(|s| &mut s[0])?)
+                    }
+                ),
                 SYS_SIGRETURN => sigreturn(),
                 SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                 SYS_PHYSALLOC => physalloc(b),
diff --git a/src/syscall/process.rs b/src/syscall/process.rs
index 65c6a7f9..403cb282 100644
--- a/src/syscall/process.rs
+++ b/src/syscall/process.rs
@@ -1176,6 +1176,11 @@ pub fn sigaction(sig: usize, act_opt: Option<&SigAction>, oldact_opt: Option<&mu
     }
 }
 
+pub fn sigprocmask(how: usize, mask_opt: Option<&[u64; 2]>, oldmask_opt: Option<&mut [u64; 2]>) -> Result<usize> {
+    println!("sigprocmask {}, {:?}, {:?}", how, mask_opt, oldmask_opt);
+    Ok(0)
+}
+
 pub fn sigreturn() -> Result<usize> {
     {
         let contexts = context::contexts();
diff --git a/syscall b/syscall
index 31b7ae8e..6909fb1c 160000
--- a/syscall
+++ b/syscall
@@ -1 +1 @@
-Subproject commit 31b7ae8eef2b108e453c2f9b154ca516be900c11
+Subproject commit 6909fb1c32d2c4dd75c0967ab06b894c8f7ed308
-- 
GitLab