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

work of Shachar Shemesh and Mike McCormack).
This commit is contained in:
Alexandre Julliard 2004-09-23 04:48:24 +00:00
parent 24ab49e250
commit 969f57c24a
4 changed files with 130 additions and 0 deletions

4
configure vendored
View File

@ -16275,6 +16275,7 @@ fi
for ac_func in \ 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 \
@ -16523,6 +16525,7 @@ done
for ac_header in \ 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 \

View File

@ -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(\
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 \

View File

@ -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 @@
/* 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

View File

@ -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 @@
#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 */
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 )
} }
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 )
{ {
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)
{ {
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 )
{ {
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;