From: William Horvath william@horvath.blog
This allows higher precision waits on Linux, to match the other platforms where we can already use a timespec directly.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57849 --- configure.ac | 1 + server/fd.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+)
diff --git a/configure.ac b/configure.ac index dd139950e10..d483096fae6 100644 --- a/configure.ac +++ b/configure.ac @@ -2061,6 +2061,7 @@ AC_CHECK_FUNCS(\ dladdr1 \ dlinfo \ epoll_create \ + epoll_pwait2 \ fstatfs \ futimens \ futimes \ diff --git a/server/fd.c b/server/fd.c index 46217dbdd77..2fb135d997c 100644 --- a/server/fd.c +++ b/server/fd.c @@ -102,6 +102,9 @@ #if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL_CREATE) # include <sys/epoll.h> # define USE_EPOLL +# ifdef HAVE_EPOLL_PWAIT2 +# define USE_EPOLL_PWAIT2 +# endif #endif /* HAVE_SYS_EPOLL_H && HAVE_EPOLL_CREATE */
#if defined(HAVE_PORT_H) && defined(HAVE_PORT_CREATE) @@ -496,6 +499,7 @@ static int active_users; /* current number of active users */ static int allocated_users; /* count of allocated entries in the array */ static struct fd **freelist; /* list of free entries in the array */
+static BOOL get_next_timeout_ts( struct timespec *ts ); static int get_next_timeout(void);
static inline void fd_poll_event( struct fd *fd, int event ) @@ -561,6 +565,52 @@ static inline void remove_epoll_user( struct fd *fd, int user ) } }
+#ifdef USE_EPOLL_PWAIT2 + +static inline void main_loop_epoll(void) +{ + int i, ret; + BOOL infinite; + struct timespec ts; + struct epoll_event events[128]; + + assert( POLLIN == EPOLLIN ); + assert( POLLOUT == EPOLLOUT ); + assert( POLLERR == EPOLLERR ); + assert( POLLHUP == EPOLLHUP ); + + if (epoll_fd == -1) return; + + while (active_users) + { + infinite = !get_next_timeout_ts( &ts ); + + if (!active_users) break; /* last user removed by a timeout */ + if (epoll_fd == -1) break; /* an error occurred with epoll */ + + if (infinite) ret = epoll_pwait2( epoll_fd, events, ARRAY_SIZE( events ), NULL, NULL ); + else ret = epoll_pwait2( epoll_fd, events, ARRAY_SIZE( events ), &ts, NULL ); + + set_current_time(); + + /* put the events into the pollfd array first, like poll does */ + for (i = 0; i < ret; i++) + { + int user = events[i].data.u32; + pollfd[user].revents = events[i].events; + } + + /* read events from the pollfd array, as set_fd_events may modify them */ + for (i = 0; i < ret; i++) + { + int user = events[i].data.u32; + if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents ); + } + } +} + +#else + static inline void main_loop_epoll(void) { int i, ret, timeout; @@ -599,6 +649,8 @@ static inline void main_loop_epoll(void) } }
+#endif /* USE_EPOLL_PWAIT2 */ + #elif defined(HAVE_KQUEUE)
static int kqueue_fd = -1;