Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
linux: handle EPOLLHUP without EPOLLIN/EPOLLOUT
Browse files Browse the repository at this point in the history
Work around an epoll quirk where it sometimes reports just the EPOLLERR
or EPOLLHUP event.  In order to force the event loop to move forward,
we merge in the read/write events that the watcher is interested in;
uv__read() and uv__write() will then deal with the error or hangup in
the usual fashion.

Fixes #982.

This is a back-port of commit 24bfef2 from the master branch.
  • Loading branch information
bnoordhuis committed Nov 8, 2013
1 parent 991409e commit 0c76cdb
Showing 1 changed file with 25 additions and 7 deletions.
32 changes: 25 additions & 7 deletions src/unix/linux-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
uv__io_t* w;
uint64_t base;
uint64_t diff;
unsigned int masked_events;
int nevents;
int count;
int nfds;
Expand Down Expand Up @@ -209,16 +208,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
continue;
}

/*
* Give users only events they're interested in. Prevents spurious
/* Give users only events they're interested in. Prevents spurious
* callbacks when previous callback invocation in this loop has stopped
* the current watcher. Also, filters out events that users has not
* requested us to watch.
*/
masked_events = pe->events & w->pevents;
if (masked_events != 0)
w->cb(loop, w, masked_events);
nevents++;
pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP;

/* Work around an epoll quirk where it sometimes reports just the
* EPOLLERR or EPOLLHUP event. In order to force the event loop to
* move forward, we merge in the read/write events that the watcher
* is interested in; uv__read() and uv__write() will then deal with
* the error or hangup in the usual fashion.
*
* Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
* reads the available data, calls uv_read_stop(), then sometime later
* calls uv_read_start() again. By then, libuv has forgotten about the
* hangup and the kernel won't report EPOLLIN again because there's
* nothing left to read. If anything, libuv is to blame here. The
* current hack is just a quick bandaid; to properly fix it, libuv
* needs to remember the error/hangup event. We should get that for
* free when we switch over to edge-triggered I/O.
*/
if (pe->events == UV__EPOLLERR || pe->events == UV__EPOLLHUP)
pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT);

if (pe->events != 0) {
w->cb(loop, w, pe->events);
nevents++;
}
}

if (nevents != 0) {
Expand Down

0 comments on commit 0c76cdb

Please sign in to comment.