summaryrefslogtreecommitdiff
path: root/ev_epoll.c
diff options
context:
space:
mode:
authorroot <root>2008-10-27 11:08:29 +0000
committerroot <root>2008-10-27 11:08:29 +0000
commited3f7d82632357b7ba925cb742cd9ef61ceed26d (patch)
tree1c03ccb4ac30a7c147b4b5be39f99b5fe1325e14 /ev_epoll.c
parent591339236dd05d5184c977fea78de5f5d82e70e1 (diff)
work around epoll spurious notifications
Diffstat (limited to 'ev_epoll.c')
-rw-r--r--ev_epoll.c20
1 files changed, 16 insertions, 4 deletions
diff --git a/ev_epoll.c b/ev_epoll.c
index e36dbcc..4c36cfa 100644
--- a/ev_epoll.c
+++ b/ev_epoll.c
@@ -85,7 +85,8 @@ epoll_modify (EV_P_ int fd, int oev, int nev)
oldmask = anfds [fd].emask;
anfds [fd].emask = nev;
- ev.data.u64 = fd; /* use u64 to fully initialise the struct, for nicer strace etc. */
+ /* store the generation counter in the upper 32 bits */
+ ev.data.u64 = fd | ((uint64_t)++anfds [fd].egen << 32);
ev.events = (nev & EV_READ ? EPOLLIN : 0)
| (nev & EV_WRITE ? EPOLLOUT : 0);
@@ -96,7 +97,7 @@ epoll_modify (EV_P_ int fd, int oev, int nev)
{
/* if ENOENT then the fd went away, so try to do the right thing */
if (!nev)
- return;
+ goto dec_egen;
if (!epoll_ctl (backend_fd, EPOLL_CTL_ADD, fd, &ev))
return;
@@ -105,11 +106,18 @@ epoll_modify (EV_P_ int fd, int oev, int nev)
{
/* EEXIST means we ignored a previous DEL, but the fd is still active */
/* if the kernel mask is the same as the new mask, we assume it hasn't changed */
- if (oldmask == nev || !epoll_ctl (backend_fd, EPOLL_CTL_MOD, fd, &ev))
+ if (oldmask == nev)
+ goto dec_egen;
+
+ if (!epoll_ctl (backend_fd, EPOLL_CTL_MOD, fd, &ev))
return;
}
fd_kill (EV_A_ fd);
+
+dec_egen:
+ /* we didn't successfully call epoll_ctl, so decrement the generation counter again */
+ --anfds [fd].egen;
}
static void
@@ -130,11 +138,15 @@ epoll_poll (EV_P_ ev_tstamp timeout)
{
struct epoll_event *ev = epoll_events + i;
- int fd = ev->data.u64;
+ int fd = (uint32_t)ev->data.u64; /* mask out the lower 32 bits */
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;
+
if (expect_false (got & ~want))
{
anfds [fd].emask = want;