summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changes3
-rw-r--r--ev.c1
-rw-r--r--ev_epoll.c34
3 files changed, 21 insertions, 17 deletions
diff --git a/Changes b/Changes
index 24be5db..2280fb6 100644
--- a/Changes
+++ b/Changes
@@ -6,7 +6,8 @@ WISH? monotonic clocks times/GetTickCount for coarse corrections?
backend by assuming the kernel event mask hasn't changed if
ADD fails with EEXIST.
- work around spurious event notification bugs in epoll by using
- an 8-bit generation counter.
+ an 8-bit generation counter. recreate kernel state if we receive
+ spurious notifications or unwanted events.
- use memset to initialise most arrays now and do away with the
init functions.
- expand time-out strategies into a "Be smart about timeouts" section.
diff --git a/ev.c b/ev.c
index 66a70ec..a6077f8 100644
--- a/ev.c
+++ b/ev.c
@@ -808,6 +808,7 @@ fd_rearm_all (EV_P)
if (anfds [fd].events)
{
anfds [fd].events = 0;
+ anfds [fd].emask = 0;
fd_change (EV_A_ fd, EV_IOFDSET | 1);
}
}
diff --git a/ev_epoll.c b/ev_epoll.c
index 4c36cfa..f1e16ab 100644
--- a/ev_epoll.c
+++ b/ev_epoll.c
@@ -52,19 +52,13 @@
*
* lots of "weird code" and complication handling in this file is due
* to these design problems with epoll, as we try very hard to avoid
- * epoll_ctl syscalls for common usage patterns.
+ * epoll_ctl syscalls for common usage patterns and handle the breakage
+ * ensuing from receiving events for closed and otherwise long gone
+ * file descriptors.
*/
#include <sys/epoll.h>
-void inline_size
-unsigned_char_init (unsigned char *base, int count)
-{
- /* memset might be overkill */
- while (count--)
- *base++ = 0;
-}
-
static void
epoll_modify (EV_P_ int fd, int oev, int nev)
{
@@ -138,14 +132,18 @@ epoll_poll (EV_P_ ev_tstamp timeout)
{
struct epoll_event *ev = epoll_events + i;
- int fd = (uint32_t)ev->data.u64; /* mask out the lower 32 bits */
+ int fd = (uint32_t)ev->data.u64; /* mask out the lower 32 bits */
+ int want = anfds [fd].events;
int got = (ev->events & (EPOLLOUT | EPOLLERR | EPOLLHUP) ? EV_WRITE : 0)
| (ev->events & (EPOLLIN | EPOLLERR | EPOLLHUP) ? EV_READ : 0);
- int want = anfds [fd].events;
- if (anfds [fd].egen != (unsigned char)(ev->data.u64 >> 32))
- /*fprintf (stderr, "spurious notification fd %d, %d vs %d\n", fd, (int)(ev->data.u64 >> 32), anfds [fd].egen);*/
- continue;
+ /* check for spurious notification */
+ if (expect_false (anfds [fd].egen != (unsigned char)(ev->data.u64 >> 32)))
+ {
+ /* recreate kernel state */
+ postfork = 1;
+ continue;
+ }
if (expect_false (got & ~want))
{
@@ -156,7 +154,11 @@ epoll_poll (EV_P_ ev_tstamp timeout)
ev->events = (want & EV_READ ? EPOLLIN : 0)
| (want & EV_WRITE ? EPOLLOUT : 0);
- epoll_ctl (backend_fd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev);
+ if (epoll_ctl (backend_fd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev))
+ {
+ postfork = 1; /* an error occured, recreate kernel state */
+ continue;
+ }
}
fd_event (EV_A_ fd, got);
@@ -185,7 +187,7 @@ epoll_init (EV_P_ int flags)
backend_modify = epoll_modify;
backend_poll = epoll_poll;
- epoll_eventmax = 64; /* intiial number of events receivable per poll */
+ epoll_eventmax = 64; /* initial number of events receivable per poll */
epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax);
return EVBACKEND_EPOLL;