From 54fb8b9b2bdd066cf95fba8da3d67b7cda39cbb8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller <jeremy@system76.com> Date: Sun, 28 Apr 2019 10:07:42 -0600 Subject: [PATCH] Fix select on regular files --- src/header/sys_select/mod.rs | 58 +++++++++++++++++++++++------------- tests/expected/select.stdout | 5 ++++ tests/select.c | 47 +++++++++++++++++++++++++++-- 3 files changed, 86 insertions(+), 24 deletions(-) diff --git a/src/header/sys_select/mod.rs b/src/header/sys_select/mod.rs index bf77b819..d39f4316 100644 --- a/src/header/sys_select/mod.rs +++ b/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 }; diff --git a/tests/expected/select.stdout b/tests/expected/select.stdout index 965e612d..a4a5b784 100644 --- a/tests/expected/select.stdout +++ b/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 diff --git a/tests/select.c b/tests/select.c index 25326a75..dfe7161c 100644 --- a/tests/select.c +++ b/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; +} -- GitLab