diff options
author | root <root> | 2008-10-27 11:08:29 +0000 |
---|---|---|
committer | root <root> | 2008-10-27 11:08:29 +0000 |
commit | ed3f7d82632357b7ba925cb742cd9ef61ceed26d (patch) | |
tree | 1c03ccb4ac30a7c147b4b5be39f99b5fe1325e14 /ev_epoll.c | |
parent | 591339236dd05d5184c977fea78de5f5d82e70e1 (diff) |
work around epoll spurious notifications
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; |