Jeremy Soller 5 лет назад
Родитель
Сommit
54fb8b9b2b
3 измененных файлов с 86 добавлено и 24 удалено
  1. 37 21
      src/header/sys_select/mod.rs
  2. 5 0
      tests/expected/select.stdout
  3. 44 3
      tests/select.c

+ 37 - 21
src/header/sys_select/mod.rs

@@ -72,8 +72,10 @@ pub fn select_epoll(
         File::new(epfd)
     };
 
+    // Keep track of the number of file descriptors that do not support epoll
+    let mut not_epoll = 0;
     for fd in 0..nfds {
-        if let Some(ref fd_set) = readfds {
+        if let Some(ref mut fd_set) = readfds {
             if fd_set.isset(fd) {
                 let mut event = epoll_event {
                     events: EPOLLIN,
@@ -82,11 +84,17 @@ pub fn select_epoll(
                     },
                 };
                 if epoll_ctl(*ep, EPOLL_CTL_ADD, fd, &mut event) < 0 {
-                    return -1;
+                    if unsafe { platform::errno == errno::EPERM } {
+                        not_epoll += 1;
+                    } else {
+                        return -1;
+                    }
+                } else {
+                    fd_set.clr(fd);
                 }
             }
         }
-        if let Some(ref fd_set) = writefds {
+        if let Some(ref mut fd_set) = writefds {
             if fd_set.isset(fd) {
                 let mut event = epoll_event {
                     events: EPOLLOUT,
@@ -95,11 +103,17 @@ pub fn select_epoll(
                     },
                 };
                 if epoll_ctl(*ep, EPOLL_CTL_ADD, fd, &mut event) < 0 {
-                    return -1;
+                    if unsafe { platform::errno == errno::EPERM } {
+                        not_epoll += 1;
+                    } else {
+                        return -1;
+                    }
+                } else {
+                    fd_set.clr(fd);
                 }
             }
         }
-        if let Some(ref fd_set) = exceptfds {
+        if let Some(ref mut fd_set) = exceptfds {
             if fd_set.isset(fd) {
                 let mut event = epoll_event {
                     events: EPOLLERR,
@@ -108,17 +122,23 @@ pub fn select_epoll(
                     },
                 };
                 if epoll_ctl(*ep, EPOLL_CTL_ADD, fd, &mut event) < 0 {
-                    return -1;
+                    if unsafe { platform::errno == errno::EPERM } {
+                        not_epoll += 1;
+                    } else {
+                        return -1;
+                    }
+                } else {
+                    fd_set.clr(fd);
                 }
             }
         }
     }
 
     let mut events: [epoll_event; 32] = unsafe { mem::zeroed() };
-    let res = epoll_wait(
-        *ep,
-        events.as_mut_ptr(),
-        events.len() as c_int,
+    let epoll_timeout = if not_epoll > 0 {
+        // Do not wait if any non-epoll file descriptors were found
+        0
+    } else {
         match timeout {
             Some(timeout) => {
                 //TODO: Check for overflow
@@ -127,22 +147,18 @@ pub fn select_epoll(
             },
             None => -1
         }
+    };
+    let res = epoll_wait(
+        *ep,
+        events.as_mut_ptr(),
+        events.len() as c_int,
+        epoll_timeout
     );
     if res < 0 {
         return -1;
     }
 
-    if let Some(ref mut fd_set) = readfds {
-        fd_set.zero();
-    }
-    if let Some(ref mut fd_set) = writefds {
-        fd_set.zero();
-    }
-    if let Some(ref mut fd_set) = exceptfds {
-        fd_set.zero();
-    }
-
-    let mut count = 0;
+    let mut count = not_epoll;
     for i in 0..res as usize {
         let event = &events[i];
         let fd = unsafe { event.data.fd };

+ 5 - 0
tests/expected/select.stdout

@@ -1,3 +1,8 @@
+Testing select on file
+Is set before? 1
+Amount of things ready: 1
+Is set after? 1
+Testing select on pipe
 Is set before? 1
 Amount of things ready: 1
 Is set after? 1

+ 44 - 3
tests/select.c

@@ -5,7 +5,36 @@
 
 #include "test_helpers.h"
 
-int main(void) {
+int file_test(void) {
+    int fd = open("select.c", 0, 0);
+    if (fd < 0) {
+        perror("open");
+        return -1;
+    }
+
+    printf("Testing select on file\n");
+
+    fd_set read;
+    FD_ZERO(&read);
+    FD_SET(fd, &read);
+
+    printf("Is set before? %d\n", FD_ISSET(fd, &read));
+
+    int nfds = select(fd + 1, &read, NULL, NULL, NULL);
+    if (nfds < 0) {
+        perror("select");
+        return 1;
+    }
+    printf("Amount of things ready: %d\n", nfds);
+
+    printf("Is set after? %d\n", FD_ISSET(fd, &read));
+
+    close(fd);
+
+    return 0;
+}
+
+int pipe_test(void) {
     int pipefd[2];
     if (pipe2(pipefd, O_NONBLOCK) < 0) {
         perror("pipe");
@@ -18,14 +47,14 @@ int main(void) {
         return 1;
     }
 
+    printf("Testing select on pipe\n");
+
     fd_set read;
     FD_ZERO(&read);
     FD_SET(pipefd[0], &read);
 
     printf("Is set before? %d\n", FD_ISSET(pipefd[0], &read));
 
-    // This should actually test TCP streams and stuff, but for now I'm simply
-    // testing whether it ever returns or not.
     int nfds = select(pipefd[0] + 1, &read, NULL, NULL, NULL);
     if (nfds < 0) {
         perror("select");
@@ -40,3 +69,15 @@ int main(void) {
 
     return 0;
 }
+
+int main(void) {
+    if (file_test()) {
+        return 1;
+    }
+
+    if (pipe_test()) {
+        return 1;
+    }
+
+    return 0;
+}