From 4c8f51ace98818a527ff1b7fcf68c458dfb16a9f Mon Sep 17 00:00:00 2001
From: jD91mZM2 <me@krake.one>
Date: Sun, 28 Apr 2019 14:51:42 +0200
Subject: [PATCH] Avoid allocations in redox epoll

---
 src/header/poll/mod.rs       |  1 +
 src/header/sys_epoll/mod.rs  | 18 +++++++++++++++---
 src/header/sys_select/mod.rs |  3 +++
 src/platform/redox/epoll.rs  | 29 +++++++++++++++++------------
 4 files changed, 36 insertions(+), 15 deletions(-)

diff --git a/src/header/poll/mod.rs b/src/header/poll/mod.rs
index 4d6f9e41..e8d9cba6 100644
--- a/src/header/poll/mod.rs
+++ b/src/header/poll/mod.rs
@@ -54,6 +54,7 @@ pub fn poll_epoll(fds: &mut [pollfd], timeout: c_int) -> c_int {
             data: epoll_data {
                 u64: i as u64,
             },
+            ..Default::default()
         };
 
         for (p, ep) in event_map.iter() {
diff --git a/src/header/sys_epoll/mod.rs b/src/header/sys_epoll/mod.rs
index ab8e4fc0..cdde0244 100644
--- a/src/header/sys_epoll/mod.rs
+++ b/src/header/sys_epoll/mod.rs
@@ -28,12 +28,24 @@ pub union epoll_data {
     pub u32: u32,
     pub u64: u64,
 }
+impl Default for epoll_data {
+    fn default() -> Self {
+        Self { u64: 0 }
+    }
+}
 
 #[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
+// This will match in size with syscall::Event (24 bytes on 64-bit
+// systems) on redox. The `Default` trait is here so we don't need to
+// worry about the padding when using this type.
 pub struct epoll_event {
-    pub events: u32,
-    pub data: epoll_data,
+    pub events: u32, // 4 bytes
+    // 4 automatic alignment bytes
+    pub data: epoll_data, // 8 bytes
+
+    #[cfg(target_os = "redox")]
+    pub _pad: u64, // 8 bytes
 }
 
 #[no_mangle]
diff --git a/src/header/sys_select/mod.rs b/src/header/sys_select/mod.rs
index bf77b819..c87ad6ee 100644
--- a/src/header/sys_select/mod.rs
+++ b/src/header/sys_select/mod.rs
@@ -80,6 +80,7 @@ pub fn select_epoll(
                     data: epoll_data {
                         fd: fd,
                     },
+                    ..Default::default()
                 };
                 if epoll_ctl(*ep, EPOLL_CTL_ADD, fd, &mut event) < 0 {
                     return -1;
@@ -93,6 +94,7 @@ pub fn select_epoll(
                     data: epoll_data {
                         fd: fd,
                     },
+                    ..Default::default()
                 };
                 if epoll_ctl(*ep, EPOLL_CTL_ADD, fd, &mut event) < 0 {
                     return -1;
@@ -106,6 +108,7 @@ pub fn select_epoll(
                     data: epoll_data {
                         fd: fd,
                     },
+                    ..Default::default()
                 };
                 if epoll_ctl(*ep, EPOLL_CTL_ADD, fd, &mut event) < 0 {
                     return -1;
diff --git a/src/platform/redox/epoll.rs b/src/platform/redox/epoll.rs
index c266e463..03e3f591 100644
--- a/src/platform/redox/epoll.rs
+++ b/src/platform/redox/epoll.rs
@@ -23,19 +23,19 @@ impl PalEpoll for Sys {
     }
 
     fn epoll_ctl(epfd: c_int, op: c_int, fd: c_int, event: *mut epoll_event) -> c_int {
-        let flags = unsafe { (*event).events };
         Sys::write(epfd, &Event {
             id: fd as usize,
-            flags: flags as usize,
-            data: event as usize
+            flags: unsafe { (*event).events as usize },
+
+            // NOTE: Danger when using non 64-bit systems. If this is
+            // needed, use a box or something
+            data: unsafe { mem::transmute((*event).data) }
         }) as c_int
     }
 
     fn epoll_pwait(epfd: c_int, mut events: *mut epoll_event, maxevents: c_int, timeout: c_int, _sigset: *const sigset_t) -> c_int {
         // TODO: sigset
 
-        let mut redox_events = vec![Event::default(); maxevents as usize];
-
         let _timer;
         if timeout != -1 {
             _timer = File::open(CStr::from_bytes_with_nul(b"time:\0").unwrap(), O_RDWR);
@@ -63,20 +63,25 @@ impl PalEpoll for Sys {
         }
 
         let bytes_read = Sys::read(epfd, unsafe { slice::from_raw_parts_mut(
-            redox_events.as_mut_ptr() as *mut u8,
-            redox_events.len() * mem::size_of::<Event>()
+            events as *mut u8,
+            maxevents as usize
         ) });
         if bytes_read == -1 {
             return -1;
         }
         let read = bytes_read as usize / mem::size_of::<Event>();
 
-        for event in &redox_events {
-            if event.data == 0 {
-                return EINTR;
-            }
+        for i in 0..maxevents {
             unsafe {
-                *events = *(event.data as *mut epoll_event);
+                let event = *(events as *mut Event);
+                if event.data == 0 {
+                    return EINTR;
+                }
+                *events = epoll_event {
+                    events: event.flags as _,
+                    data: mem::transmute(event.data),
+                    ..Default::default()
+                };
                 events = events.add(mem::size_of::<epoll_event>());
             }
         }
-- 
GitLab