Commit 969f57c2 authored by Alexandre Julliard's avatar Alexandre Julliard

Added support for epoll() as an alternative to poll() (based on the

work of Shachar Shemesh and Mike McCormack).
parent 24ab49e2
...@@ -16277,6 +16277,7 @@ fi ...@@ -16277,6 +16277,7 @@ fi
for ac_func in \ for ac_func in \
_lwp_create \ _lwp_create \
_lwp_self \ _lwp_self \
...@@ -16289,6 +16290,7 @@ for ac_func in \ ...@@ -16289,6 +16290,7 @@ for ac_func in \
_vsnprintf \ _vsnprintf \
chsize \ chsize \
clone \ clone \
epoll_create \
finite \ finite \
fpclass \ fpclass \
fstatfs \ fstatfs \
...@@ -16525,6 +16527,7 @@ done ...@@ -16525,6 +16527,7 @@ done
for ac_header in \ for ac_header in \
arpa/inet.h \ arpa/inet.h \
arpa/nameser.h \ arpa/nameser.h \
...@@ -16575,6 +16578,7 @@ for ac_header in \ ...@@ -16575,6 +16578,7 @@ for ac_header in \
sys/cdio.h \ sys/cdio.h \
sys/elf32.h \ sys/elf32.h \
sys/errno.h \ sys/errno.h \
sys/epoll.h \
sys/exec_elf.h \ sys/exec_elf.h \
sys/file.h \ sys/file.h \
sys/filio.h \ sys/filio.h \
......
...@@ -1065,6 +1065,7 @@ AC_CHECK_FUNCS(\ ...@@ -1065,6 +1065,7 @@ AC_CHECK_FUNCS(\
_vsnprintf \ _vsnprintf \
chsize \ chsize \
clone \ clone \
epoll_create \
finite \ finite \
fpclass \ fpclass \
fstatfs \ fstatfs \
...@@ -1165,6 +1166,7 @@ AC_CHECK_HEADERS(\ ...@@ -1165,6 +1166,7 @@ AC_CHECK_HEADERS(\
sys/cdio.h \ sys/cdio.h \
sys/elf32.h \ sys/elf32.h \
sys/errno.h \ sys/errno.h \
sys/epoll.h \
sys/exec_elf.h \ sys/exec_elf.h \
sys/file.h \ sys/file.h \
sys/filio.h \ sys/filio.h \
......
...@@ -80,6 +80,9 @@ ...@@ -80,6 +80,9 @@
/* Define to 1 if you have the <elf.h> header file. */ /* Define to 1 if you have the <elf.h> header file. */
#undef HAVE_ELF_H #undef HAVE_ELF_H
/* Define to 1 if you have the `epoll_create' function. */
#undef HAVE_EPOLL_CREATE
/* Define to 1 if you have the `finite' function. */ /* Define to 1 if you have the `finite' function. */
#undef HAVE_FINITE #undef HAVE_FINITE
...@@ -617,6 +620,9 @@ ...@@ -617,6 +620,9 @@
/* Define to 1 if you have the <sys/elf32.h> header file. */ /* Define to 1 if you have the <sys/elf32.h> header file. */
#undef HAVE_SYS_ELF32_H #undef HAVE_SYS_ELF32_H
/* Define to 1 if you have the <sys/epoll.h> header file. */
#undef HAVE_SYS_EPOLL_H
/* Define to 1 if you have the <sys/errno.h> header file. */ /* Define to 1 if you have the <sys/errno.h> header file. */
#undef HAVE_SYS_ERRNO_H #undef HAVE_SYS_ERRNO_H
......
...@@ -33,6 +33,12 @@ ...@@ -33,6 +33,12 @@
#ifdef HAVE_SYS_POLL_H #ifdef HAVE_SYS_POLL_H
#include <sys/poll.h> #include <sys/poll.h>
#endif #endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_SYS_EPOLL_H
#include <sys/epoll.h>
#endif
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
...@@ -48,6 +54,10 @@ ...@@ -48,6 +54,10 @@
#include "winreg.h" #include "winreg.h"
#include "winternl.h" #include "winternl.h"
#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL_CREATE)
# define USE_EPOLL
#endif
/* Because of the stupid Posix locking semantics, we need to keep /* Because of the stupid Posix locking semantics, we need to keep
* track of all file descriptors referencing a given file, and not * track of all file descriptors referencing a given file, and not
* close a single one until all the locks are gone (sigh). * close a single one until all the locks are gone (sigh).
...@@ -236,6 +246,58 @@ static int active_users; /* current number of active users */ ...@@ -236,6 +246,58 @@ static int active_users; /* current number of active users */
static int allocated_users; /* count of allocated entries in the array */ static int allocated_users; /* count of allocated entries in the array */
static struct fd **freelist; /* list of free entries in the array */ static struct fd **freelist; /* list of free entries in the array */
#ifdef USE_EPOLL
static int epoll_fd;
static struct epoll_event *epoll_events;
/* set the events that epoll waits for on this fd; helper for set_fd_events */
static inline void set_fd_epoll_events( struct fd *fd, int user, int events )
{
struct epoll_event ev;
int ctl;
if (epoll_fd == -1) return;
if (events == -1) /* stop waiting on this fd completely */
{
if (pollfd[user].fd == -1) return; /* already removed */
ctl = EPOLL_CTL_DEL;
}
else if (pollfd[user].fd == -1)
{
if (pollfd[user].events) return; /* stopped waiting on it, don't restart */
ctl = EPOLL_CTL_ADD;
}
else
{
if (pollfd[user].events == events) return; /* nothing to do */
ctl = EPOLL_CTL_MOD;
}
ev.events = events;
ev.data.u32 = user;
if (epoll_ctl( epoll_fd, ctl, fd->unix_fd, &ev ) == -1)
{
if (errno == ENOMEM) /* not enough memory, give up on epoll */
{
close( epoll_fd );
epoll_fd = -1;
}
else perror( "epoll_ctl" ); /* should not happen */
}
}
#else /* USE_EPOLL */
static inline void set_fd_epoll_events( struct fd *fd, int user, int events )
{
}
#endif /* USE_EPOLL */
/* add a user in the poll array and return its index, or -1 on failure */ /* add a user in the poll array and return its index, or -1 on failure */
static int add_poll_user( struct fd *fd ) static int add_poll_user( struct fd *fd )
{ {
...@@ -263,6 +325,16 @@ static int add_poll_user( struct fd *fd ) ...@@ -263,6 +325,16 @@ static int add_poll_user( struct fd *fd )
} }
poll_users = newusers; poll_users = newusers;
pollfd = newpoll; pollfd = newpoll;
#ifdef USE_EPOLL
if (!allocated_users) epoll_fd = epoll_create( new_count );
if (epoll_fd != -1)
{
struct epoll_event *new_events;
if (!(new_events = realloc( epoll_events, new_count * sizeof(*epoll_events) )))
return -1;
epoll_events = new_events;
}
#endif
allocated_users = new_count; allocated_users = new_count;
} }
ret = nb_users++; ret = nb_users++;
...@@ -280,6 +352,14 @@ static void remove_poll_user( struct fd *fd, int user ) ...@@ -280,6 +352,14 @@ static void remove_poll_user( struct fd *fd, int user )
{ {
assert( user >= 0 ); assert( user >= 0 );
assert( poll_users[user] == fd ); assert( poll_users[user] == fd );
#ifdef USE_EPOLL
if (epoll_fd != -1 && pollfd[user].fd != -1)
{
struct epoll_event dummy;
epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd->unix_fd, &dummy );
}
#endif
pollfd[user].fd = -1; pollfd[user].fd = -1;
pollfd[user].events = 0; pollfd[user].events = 0;
pollfd[user].revents = 0; pollfd[user].revents = 0;
...@@ -340,6 +420,41 @@ void main_loop(void) ...@@ -340,6 +420,41 @@ void main_loop(void)
{ {
int i, ret, timeout; int i, ret, timeout;
#ifdef USE_EPOLL
assert( POLLIN == EPOLLIN );
assert( POLLOUT == EPOLLOUT );
assert( POLLERR == EPOLLERR );
assert( POLLHUP == EPOLLHUP );
if (epoll_fd != -1)
{
while (active_users)
{
timeout = get_next_timeout();
if (!active_users) break; /* last user removed by a timeout */
if (epoll_fd == -1) break; /* an error occurred with epoll */
ret = epoll_wait( epoll_fd, epoll_events, allocated_users, timeout );
/* put the events into the pollfd array first, like poll does */
for (i = 0; i < ret; i++)
{
int user = epoll_events[i].data.u32;
pollfd[user].revents = epoll_events[i].events;
}
/* read events from the pollfd array, as set_fd_events may modify them */
for (i = 0; i < ret; i++)
{
int user = epoll_events[i].data.u32;
if (pollfd[user].revents) fd_poll_event( poll_users[user], pollfd[user].revents );
}
}
}
/* fall through to normal poll loop */
#endif /* USE_EPOLL */
while (active_users) while (active_users)
{ {
timeout = get_next_timeout(); timeout = get_next_timeout();
...@@ -841,6 +956,9 @@ void set_fd_events( struct fd *fd, int events ) ...@@ -841,6 +956,9 @@ void set_fd_events( struct fd *fd, int events )
{ {
int user = fd->poll_index; int user = fd->poll_index;
assert( poll_users[user] == fd ); assert( poll_users[user] == fd );
set_fd_epoll_events( fd, user, events );
if (events == -1) /* stop waiting on this fd completely */ if (events == -1) /* stop waiting on this fd completely */
{ {
pollfd[user].fd = -1; pollfd[user].fd = -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment