summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroot <root>2007-11-02 16:54:34 +0000
committerroot <root>2007-11-02 16:54:34 +0000
commit0c513fd963e79da73c7d77018523ac956a5066bd (patch)
tree811c9fc8f69f24915a0aeee5200544a0c9be5bb2
parent6879205607d844eab17dd6c735f8e80bf1490baf (diff)
implement poll method, handle enomem by closing a 'random' fd
-rw-r--r--ev.c68
-rw-r--r--ev.h8
-rw-r--r--ev_poll.c112
-rw-r--r--ev_select.c4
4 files changed, 121 insertions, 71 deletions
diff --git a/ev.c b/ev.c
index e94ede4..c77ad2a 100644
--- a/ev.c
+++ b/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)
diff --git a/ev.h b/ev.h
index 1ffed6f..66e9bd1 100644
--- a/ev.h
+++ b/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);
diff --git a/ev_poll.c b/ev_poll.c
index 4793212..0af63f3 100644
--- a/ev_poll.c
+++ b/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);
-}
+ if (idx < 0) /* need to allocate a new pollfd */
+ {
+ idx = pollcnt++;
+ array_needsize (polls, pollmax, pollcnt, );
+ polls [idx].fd = fd;
+ }
-static struct epoll_event *events;
-static int eventmax;
+ 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_poll (ev_tstamp timeout)
+poll_poll (ev_tstamp timeout)
{
- int eventcnt = epoll_wait (epoll_fd, events, eventmax, ceil (timeout * 1000.));
- int i;
-
- if (eventcnt < 0)
- return;
+ int res = poll (polls, pollcnt, ceil (timeout * 1000.));
- 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 (res > 0)
+ {
+ int i;
+
+ 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)
{
- free (events);
- eventmax = array_roundsize (events, eventmax << 1);
- events = malloc (sizeof (struct epoll_event) * eventmax);
+ if (errno == EBADF)
+ fd_ebadf ();
+ else if (errno == ENOMEM)
+ fd_enomem ();
}
}
static void
-epoll_init (int flags)
+poll_init (int flags)
{
- epoll_fd = epoll_create (256);
-
- if (epoll_fd < 0)
- return;
-
- 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);
+ 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;
}
-
diff --git a/ev_select.c b/ev_select.c
index 7bbf622..0333d63 100644
--- a/ev_select.c
+++ b/ev_select.c
@@ -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 ();
}
}