From 869eb160bde8f77baaae9af90eca512ec3995f2c Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jeremy@system76.com>
Date: Sun, 25 Nov 2018 13:04:38 -0700
Subject: [PATCH] Add poll

---
 src/header/mod.rs             |   1 +
 src/header/poll/cbindgen.toml |   7 ++
 src/header/poll/mod.rs        |  22 ++++++
 src/header/pwd/mod.rs         |   6 +-
 src/lib.rs                    |   1 +
 src/platform/linux/mod.rs     |   5 ++
 src/platform/pal/mod.rs       |   4 +
 src/platform/redox/mod.rs     | 133 ++++++++++++++++++++++++++++++++--
 8 files changed, 169 insertions(+), 10 deletions(-)
 create mode 100644 src/header/poll/cbindgen.toml
 create mode 100644 src/header/poll/mod.rs

diff --git a/src/header/mod.rs b/src/header/mod.rs
index aed7c6580..e02ccd3ef 100644
--- a/src/header/mod.rs
+++ b/src/header/mod.rs
@@ -16,6 +16,7 @@ pub mod limits;
 pub mod locale;
 pub mod netdb;
 pub mod netinet_in;
+pub mod poll;
 //pub mod pthread;
 pub mod pwd;
 pub mod regex;
diff --git a/src/header/poll/cbindgen.toml b/src/header/poll/cbindgen.toml
new file mode 100644
index 000000000..4d3ce0250
--- /dev/null
+++ b/src/header/poll/cbindgen.toml
@@ -0,0 +1,7 @@
+sys_includes = []
+include_guard = "_POLL_H"
+language = "C"
+style = "Tag"
+
+[enum]
+prefix_with_name = true
diff --git a/src/header/poll/mod.rs b/src/header/poll/mod.rs
new file mode 100644
index 000000000..fab03b382
--- /dev/null
+++ b/src/header/poll/mod.rs
@@ -0,0 +1,22 @@
+//! poll implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/poll.h.html
+
+use platform::types::*;
+use platform::{Pal, Sys};
+
+pub const POLLIN: c_short = 0x001;
+pub const POLLPRI: c_short = 0x002;
+pub const POLLOUT: c_short = 0x004;
+
+pub type nfds_t = c_ulong;
+
+#[repr(C)]
+pub struct pollfd {
+    pub fd: c_int,
+    pub events: c_short,
+    pub revents: c_short,
+}
+
+#[no_mangle]
+pub extern "C" fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int {
+    Sys::poll(fds, nfds, timeout)
+}
diff --git a/src/header/pwd/mod.rs b/src/header/pwd/mod.rs
index 7157c0f29..efdcd1d15 100644
--- a/src/header/pwd/mod.rs
+++ b/src/header/pwd/mod.rs
@@ -2,7 +2,6 @@
 
 use core::ptr;
 
-use c_str::CStr;
 use fs::File;
 use header::{errno, fcntl};
 use io::{BufRead, BufReader};
@@ -56,10 +55,7 @@ where
     // TODO F: FnMut(impl Iterator<Item = &[u8]>) -> bool
     F: FnMut(&[&[u8]]) -> bool,
 {
-    let file = match File::open(
-        unsafe { CStr::from_bytes_with_nul_unchecked(b"/etc/passwd\0") },
-        fcntl::O_RDONLY,
-    ) {
+    let file = match File::open(c_str!("/etc/passwd"), fcntl::O_RDONLY) {
         Ok(file) => file,
         Err(_) => return OptionPasswd::Error,
     };
diff --git a/src/lib.rs b/src/lib.rs
index 33f107ace..95cfc0adb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,6 +10,7 @@
 #![feature(global_asm)]
 #![feature(lang_items)]
 #![feature(linkage)]
+#![feature(stmt_expr_attributes)]
 #![feature(str_internals)]
 #![feature(thread_local)]
 
diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs
index 98e3f310b..3c221b2c4 100644
--- a/src/platform/linux/mod.rs
+++ b/src/platform/linux/mod.rs
@@ -8,6 +8,7 @@ use fs::File;
 use header::dirent::dirent;
 use header::errno::EINVAL;
 use header::fcntl;
+use header::poll::{nfds_t, pollfd};
 use header::signal::SIGCHLD;
 use header::sys_ioctl::{winsize, TCGETS, TCSETS, TIOCGWINSZ};
 // use header::sys_resource::rusage;
@@ -296,6 +297,10 @@ impl Pal for Sys {
         e(unsafe { syscall!(PIPE2, fildes.as_mut_ptr(), 0) }) as c_int
     }
 
+    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int {
+        e(unsafe { syscall!(POLL, fds, nfds, timeout) }) as c_int
+    }
+
     fn read(fildes: c_int, buf: &mut [u8]) -> ssize_t {
         e(unsafe { syscall!(READ, fildes, buf.as_mut_ptr(), buf.len()) }) as ssize_t
     }
diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs
index 0866f1f4f..217ff46d5 100644
--- a/src/platform/pal/mod.rs
+++ b/src/platform/pal/mod.rs
@@ -1,6 +1,7 @@
 use super::types::*;
 use c_str::CStr;
 use header::dirent::dirent;
+use header::poll::{nfds_t, pollfd};
 use header::sys_select::fd_set;
 use header::sys_stat::stat;
 use header::sys_time::{timeval, timezone};
@@ -110,6 +111,8 @@ pub trait Pal {
 
     fn pipe(fildes: &mut [c_int]) -> c_int;
 
+    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int;
+
     fn read(fildes: c_int, buf: &mut [u8]) -> ssize_t;
 
     //fn readlink(pathname: &CStr, out: &mut [u8]) -> ssize_t;
@@ -120,6 +123,7 @@ pub trait Pal {
 
     fn rmdir(path: &CStr) -> c_int;
 
+    //TODO: Deprecate in favor of poll
     fn select(
         nfds: c_int,
         readfds: *mut fd_set,
diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs
index 320a73f5d..3750178c9 100644
--- a/src/platform/redox/mod.rs
+++ b/src/platform/redox/mod.rs
@@ -15,9 +15,7 @@ use fs::File;
 use header::dirent::dirent;
 use header::errno::{EINVAL, EIO, EPERM};
 use header::fcntl;
-use io::prelude::*;
-use io::{self, BufReader, SeekFrom};
-const MAP_ANON: c_int = 1;
+use header::poll::{self, nfds_t, pollfd};
 use header::sys_select::fd_set;
 use header::sys_stat::stat;
 use header::sys_time::{timeval, timezone};
@@ -25,6 +23,8 @@ use header::sys_utsname::{utsname, UTSLENGTH};
 use header::termios::termios;
 use header::time::timespec;
 use header::unistd::{F_OK, R_OK, SEEK_SET, W_OK, X_OK};
+use io::prelude::*;
+use io::{self, BufReader, SeekFrom};
 
 use super::types::*;
 use super::{errno, Pal, Read};
@@ -32,6 +32,8 @@ use super::{errno, Pal, Read};
 mod signal;
 mod socket;
 
+const MAP_ANON: c_int = 1;
+
 static ANONYMOUS_MAPS: Once<Mutex<BTreeMap<usize, usize>>> = Once::new();
 
 fn anonymous_maps() -> MutexGuard<'static, BTreeMap<usize, usize>> {
@@ -705,6 +707,127 @@ impl Pal for Sys {
         res as c_int
     }
 
+    fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int {
+        let fds = unsafe { slice::from_raw_parts_mut(fds, nfds as usize) };
+
+        let event_path = c_str!("event:");
+        let mut event_file = match File::open(event_path, fcntl::O_RDWR | fcntl::O_CLOEXEC) {
+            Ok(file) => file,
+            Err(_) => return -1,
+        };
+
+        for fd in fds.iter_mut() {
+            let mut flags = 0;
+
+            if fd.events & poll::POLLIN > 0 {
+                flags |= syscall::EVENT_READ;
+            }
+
+            if fd.events & poll::POLLOUT > 0 {
+                flags |= syscall::EVENT_WRITE;
+            }
+
+            fd.revents = 0;
+
+            if fd.fd >= 0 && flags > 0 {
+                if event_file.write(&syscall::Event {
+                    id: fd.fd as usize,
+                    flags: flags,
+                    data: 0,
+                }).is_err() {
+                    return -1;
+                }
+            }
+        }
+
+        const TIMEOUT_TOKEN: usize = 1;
+
+        let timeout_file = if timeout < 0 {
+            None
+        } else {
+            let timeout_path = unsafe {
+                CString::from_vec_unchecked(
+                    format!("time:{}", syscall::CLOCK_MONOTONIC).into_bytes(),
+                )
+            };
+            let mut timeout_file = match File::open(&timeout_path, fcntl::O_RDWR | fcntl::O_CLOEXEC)
+            {
+                Ok(file) => file,
+                Err(_) => return -1,
+            };
+
+            if event_file
+                .write(&syscall::Event {
+                    id: *timeout_file as usize,
+                    flags: syscall::EVENT_READ,
+                    data: TIMEOUT_TOKEN,
+                })
+                .is_err()
+            {
+                return -1;
+            }
+
+            let mut time = syscall::TimeSpec::default();
+            if timeout_file.read(&mut time).is_err() {
+                return -1;
+            }
+
+            time.tv_nsec += timeout * 1000000;
+            while time.tv_nsec >= 1000000000 {
+                time.tv_sec += 1;
+                time.tv_nsec -= 1000000000;
+            }
+
+            if timeout_file.write(&time).is_err() {
+                return -1;
+            }
+
+            Some(timeout_file)
+        };
+
+        let mut events = [syscall::Event::default(); 32];
+        let read = {
+            let mut events = unsafe {
+                slice::from_raw_parts_mut(
+                    &mut events as *mut _ as *mut u8,
+                    mem::size_of::<syscall::Event>() * events.len(),
+                )
+            };
+            match event_file.read(&mut events) {
+                Ok(i) => i / mem::size_of::<syscall::Event>(),
+                Err(_) => return -1,
+            }
+        };
+
+        for event in &events[..read] {
+            if event.data == TIMEOUT_TOKEN {
+                continue;
+            }
+
+            for fd in fds.iter_mut() {
+                if event.id == fd.fd as usize {
+                    if event.flags & syscall::EVENT_READ > 0 {
+                        fd.revents |= poll::POLLIN;
+                    }
+
+                    if event.flags & syscall::EVENT_WRITE > 0 {
+                        fd.revents |= poll::POLLOUT;
+                    }
+                }
+            }
+        }
+
+        let mut total = 0;
+
+        for fd in fds.iter_mut() {
+            if fd.revents > 0 {
+                total += 1;
+            }
+        }
+
+        total
+    }
+
     fn read(fd: c_int, buf: &mut [u8]) -> ssize_t {
         e(syscall::read(fd as usize, buf)) as ssize_t
     }
@@ -756,7 +879,7 @@ impl Pal for Sys {
         let mut exceptfds =
             unsafe { exceptfds.as_mut() }.map(|s| BitSet::from_ref(&mut s.fds_bits));
 
-        let event_path = unsafe { CStr::from_bytes_with_nul_unchecked(b"event:\0") };
+        let event_path = c_str!("event:");
         let mut event_file = match File::open(event_path, fcntl::O_RDWR | fcntl::O_CLOEXEC) {
             Ok(file) => file,
             Err(_) => return -1,
@@ -933,7 +1056,7 @@ impl Pal for Sys {
 
     fn uname(utsname: *mut utsname) -> c_int {
         fn inner(utsname: *mut utsname) -> CoreResult<(), i32> {
-            let file_path = unsafe { CStr::from_bytes_with_nul_unchecked(b"sys:uname\0") };
+            let file_path = c_str!("sys:uname\0");
             let mut file = match File::open(file_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) {
                 Ok(file) => file,
                 Err(_) => return Err(EIO),
-- 
GitLab