mirror of /home/gitosis/repositories/libev.git
implement poll method, handle enomem by closing a 'random' fd
This commit is contained in:
parent
27d81e6389
commit
a650025791
68
ev.c
68
ev.c
|
@ -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
8
ev.h
|
@ -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
116
ev_poll.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue