implement poll method, handle enomem by closing a 'random' fd

master
Marc Alexander Lehmann 2007-11-02 16:54:34 +00:00
parent 27d81e6389
commit a650025791
4 changed files with 123 additions and 73 deletions

68
ev.c
View File

@ -58,6 +58,10 @@
# define EV_USE_SELECT 1
#endif
#ifndef EV_USE_POLL
# define EV_USE_POLL 0 /* poll is usually slower than select, and not as well tested */
#endif
#ifndef EV_USE_EPOLL
# define EV_USE_EPOLL 0
#endif
@ -279,20 +283,44 @@ fd_change (int fd)
fdchanges [fdchangecnt - 1] = fd;
}
static void
fd_kill (int fd)
{
struct ev_io *w;
printf ("killing fd %d\n", fd);//D
while ((w = anfds [fd].head))
{
ev_io_stop (w);
event ((W)w, EV_ERROR | EV_READ | EV_WRITE);
}
}
/* called on EBADF to verify fds */
static void
fd_recheck (void)
fd_ebadf (void)
{
int fd;
for (fd = 0; fd < anfdmax; ++fd)
if (anfds [fd].events)
if (fcntl (fd, F_GETFD) == -1 && errno == EBADF)
while (anfds [fd].head)
{
ev_io_stop (anfds [fd].head);
event ((W)anfds [fd].head, EV_ERROR | EV_READ | EV_WRITE);
}
fd_kill (fd);
}
/* called on ENOMEM in select/poll to kill some fds and retry */
static void
fd_enomem (void)
{
int fd = anfdmax;
while (fd--)
if (anfds [fd].events)
{
close (fd);
fd_kill (fd);
return;
}
}
/*****************************************************************************/
@ -456,6 +484,9 @@ childcb (struct ev_signal *sw, int revents)
#if EV_USE_EPOLL
# include "ev_epoll.c"
#endif
#if EV_USE_POLL
# include "ev_poll.c"
#endif
#if EV_USE_SELECT
# include "ev_select.c"
#endif
@ -472,7 +503,15 @@ ev_version_minor (void)
return EV_VERSION_MINOR;
}
int ev_init (int flags)
/* return true if we are running with elevated privileges and ignore env variables */
static int
enable_secure ()
{
return getuid () != geteuid ()
|| getgid () != getegid ();
}
int ev_init (int methods)
{
if (!ev_method)
{
@ -492,12 +531,21 @@ int ev_init (int flags)
if (pipe (sigpipe))
return 0;
ev_method = EVMETHOD_NONE;
if (methods == EVMETHOD_AUTO)
if (!enable_secure () && getenv ("LIBEV_METHODS"))
methods = atoi (getenv ("LIBEV_METHODS"));
else
methods = EVMETHOD_ANY;
ev_method = 0;
#if EV_USE_EPOLL
if (ev_method == EVMETHOD_NONE) epoll_init (flags);
if (!ev_method && (methods & EVMETHOD_EPOLL )) epoll_init (methods);
#endif
#if EV_USE_POLL
if (!ev_method && (methods & EVMETHOD_POLL )) poll_init (methods);
#endif
#if EV_USE_SELECT
if (ev_method == EVMETHOD_NONE) select_init (flags);
if (!ev_method && (methods & EVMETHOD_SELECT)) select_init (methods);
#endif
if (ev_method)

8
ev.h
View File

@ -167,12 +167,14 @@ struct ev_child
int status; /* rw, holds the exit status, use the macros from sys/wait.h */
};
#define EVMETHOD_NONE 0
#define EVMETHOD_AUTO 0 /* consults environment */
#define EVMETHOD_SELECT 1
#define EVMETHOD_EPOLL 2
#define EVMETHOD_POLL 2
#define EVMETHOD_EPOLL 4
#define EVMETHOD_ANY ~0 /* any method, do not consult env */
#if EV_PROTOTYPES
extern int ev_method;
int ev_init (int flags); /* returns ev_method */
int ev_init (int methods); /* returns ev_method */
int ev_version_major (void);
int ev_version_minor (void);

116
ev_poll.c
View File

@ -29,82 +29,80 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/epoll.h>
#include <poll.h>
static int epoll_fd = -1;
static struct pollfd *polls;
static int pollmax, pollcnt;
static int *pollidxs; /* maps fds into structure indices */
static int pollidxmax;
static void
epoll_modify (int fd, int oev, int nev)
pollidx_init (int *base, int count)
{
int mode = nev ? oev ? EPOLL_CTL_MOD : EPOLL_CTL_ADD : EPOLL_CTL_DEL;
struct epoll_event ev;
ev.data.fd = fd;
ev.events =
(nev & EV_READ ? EPOLLIN : 0)
| (nev & EV_WRITE ? EPOLLOUT : 0);
epoll_ctl (epoll_fd, mode, fd, &ev);
while (count--)
*base++ = -1;
}
static void
epoll_postfork_child (void)
poll_modify (int fd, int oev, int nev)
{
int fd;
int idx;
array_needsize (pollidxs, pollidxmax, fd + 1, pollidx_init);
epoll_fd = epoll_create (256);
fcntl (epoll_fd, F_SETFD, FD_CLOEXEC);
idx = pollidxs [fd];
/* re-register interest in fds */
for (fd = 0; fd < anfdmax; ++fd)
if (anfds [fd].events)//D
epoll_modify (fd, EV_NONE, anfds [fd].events);
}
static struct epoll_event *events;
static int eventmax;
static void
epoll_poll (ev_tstamp timeout)
{
int eventcnt = epoll_wait (epoll_fd, events, eventmax, ceil (timeout * 1000.));
int i;
if (eventcnt < 0)
return;
for (i = 0; i < eventcnt; ++i)
fd_event (
events [i].data.fd,
(events [i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP) ? EV_WRITE : 0)
| (events [i].events & (EPOLLIN | EPOLLERR | EPOLLHUP) ? EV_READ : 0)
);
/* if the receive array was full, increase its size */
if (expect_false (eventcnt == eventmax))
if (idx < 0) /* need to allocate a new pollfd */
{
free (events);
eventmax = array_roundsize (events, eventmax << 1);
events = malloc (sizeof (struct epoll_event) * eventmax);
idx = pollcnt++;
array_needsize (polls, pollmax, pollcnt, );
polls [idx].fd = fd;
}
if (nev)
polls [idx].events =
(nev & EV_READ ? POLLIN : 0)
| (nev & EV_WRITE ? POLLOUT : 0);
else /* remove pollfd */
{
if (idx < pollcnt--)
{
pollidxs [fd] = -1;
polls [idx] = polls [pollcnt];
pollidxs [polls [idx].fd] = idx;
}
}
}
static void
epoll_init (int flags)
poll_poll (ev_tstamp timeout)
{
epoll_fd = epoll_create (256);
int res = poll (polls, pollcnt, ceil (timeout * 1000.));
if (epoll_fd < 0)
return;
if (res > 0)
{
int i;
fcntl (epoll_fd, F_SETFD, FD_CLOEXEC);
ev_method = EVMETHOD_EPOLL;
method_fudge = 1e-3; /* needed to compensate for epoll returning early */
method_modify = epoll_modify;
method_poll = epoll_poll;
eventmax = 64; /* intiial number of events receivable per poll */
events = malloc (sizeof (struct epoll_event) * eventmax);
for (i = 0; i < pollcnt; ++i)
fd_event (
polls [i].fd,
(polls [i].revents & (POLLOUT | POLLERR | POLLHUP) ? EV_WRITE : 0)
| (polls [i].revents & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0)
);
}
else if (res < 0)
{
if (errno == EBADF)
fd_ebadf ();
else if (errno == ENOMEM)
fd_enomem ();
}
}
static void
poll_init (int flags)
{
ev_method = EVMETHOD_POLL;
method_fudge = 1e-3; /* needed to compensate for select returning early, very conservative */
method_modify = poll_modify;
method_poll = poll_poll;
}

View File

@ -116,7 +116,9 @@ select_poll (ev_tstamp timeout)
else if (res < 0)
{
if (errno == EBADF)
fd_recheck ();
fd_ebadf ();
else if (errno == ENOMEM)
fd_enomem ();
}
}