diff options
Diffstat (limited to 'ev_epoll.c')
-rw-r--r-- | ev_epoll.c | 20 |
1 files changed, 16 insertions, 4 deletions
@@ -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; |