Added support for epoll() as an alternative to poll() (based on the
work of Shachar Shemesh and Mike McCormack).
This commit is contained in:
parent
24ab49e250
commit
969f57c24a
|
@ -16275,6 +16275,7 @@ fi
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for ac_func in \
|
||||
|
@ -16289,6 +16290,7 @@ for ac_func in \
|
|||
_vsnprintf \
|
||||
chsize \
|
||||
clone \
|
||||
epoll_create \
|
||||
finite \
|
||||
fpclass \
|
||||
fstatfs \
|
||||
|
@ -16523,6 +16525,7 @@ done
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for ac_header in \
|
||||
|
@ -16575,6 +16578,7 @@ for ac_header in \
|
|||
sys/cdio.h \
|
||||
sys/elf32.h \
|
||||
sys/errno.h \
|
||||
sys/epoll.h \
|
||||
sys/exec_elf.h \
|
||||
sys/file.h \
|
||||
sys/filio.h \
|
||||
|
|
|
@ -1065,6 +1065,7 @@ AC_CHECK_FUNCS(\
|
|||
_vsnprintf \
|
||||
chsize \
|
||||
clone \
|
||||
epoll_create \
|
||||
finite \
|
||||
fpclass \
|
||||
fstatfs \
|
||||
|
@ -1165,6 +1166,7 @@ AC_CHECK_HEADERS(\
|
|||
sys/cdio.h \
|
||||
sys/elf32.h \
|
||||
sys/errno.h \
|
||||
sys/epoll.h \
|
||||
sys/exec_elf.h \
|
||||
sys/file.h \
|
||||
sys/filio.h \
|
||||
|
|
|
@ -80,6 +80,9 @@
|
|||
/* Define to 1 if you have the <elf.h> header file. */
|
||||
#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. */
|
||||
#undef HAVE_FINITE
|
||||
|
||||
|
@ -617,6 +620,9 @@
|
|||
/* Define to 1 if you have the <sys/elf32.h> header file. */
|
||||
#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. */
|
||||
#undef HAVE_SYS_ERRNO_H
|
||||
|
||||
|
|
118
server/fd.c
118
server/fd.c
|
@ -33,6 +33,12 @@
|
|||
#ifdef HAVE_SYS_POLL_H
|
||||
#include <sys/poll.h>
|
||||
#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/time.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -48,6 +54,10 @@
|
|||
#include "winreg.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
|
||||
* track of all file descriptors referencing a given file, and not
|
||||
* 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 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 */
|
||||
static int add_poll_user( struct fd *fd )
|
||||
{
|
||||
|
@ -263,6 +325,16 @@ static int add_poll_user( struct fd *fd )
|
|||
}
|
||||
poll_users = newusers;
|
||||
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;
|
||||
}
|
||||
ret = nb_users++;
|
||||
|
@ -280,6 +352,14 @@ static void remove_poll_user( struct fd *fd, int user )
|
|||
{
|
||||
assert( user >= 0 );
|
||||
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].events = 0;
|
||||
pollfd[user].revents = 0;
|
||||
|
@ -340,6 +420,41 @@ void main_loop(void)
|
|||
{
|
||||
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)
|
||||
{
|
||||
timeout = get_next_timeout();
|
||||
|
@ -841,6 +956,9 @@ void set_fd_events( struct fd *fd, int events )
|
|||
{
|
||||
int user = fd->poll_index;
|
||||
assert( poll_users[user] == fd );
|
||||
|
||||
set_fd_epoll_events( fd, user, events );
|
||||
|
||||
if (events == -1) /* stop waiting on this fd completely */
|
||||
{
|
||||
pollfd[user].fd = -1;
|
||||
|
|
Loading…
Reference in New Issue