linux: fix potential event loop stall

It was pointed out[0] that libuv could effectively enter an infinite
loop (but not a busy loop) under certain conditions when polling for
events:

1. When the architecture is 32 bits, and
2. When timeout > 0, i.e., finite, and
3. When timeout > max_safe_timeout (~30 minutes), and
4. When epoll_wait(timeout) returns 0, then
5. timeout was not properly updated on the next call to epoll_wait().

Inspection of the code uncovered a secondary bug where under a similar
set of circumstances the timeout could drift when the epoll_wait()
system call returned late.

[0] https://github.com/libuv/libuv/pull/354#discussion_r67837112

PR-URL: https://github.com/libuv/libuv/pull/922
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
Ben Noordhuis 2016-06-21 15:25:43 +02:00
parent 1d27bbbb8d
commit 70002c80bf

View File

@ -289,11 +289,13 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (nfds == 0) { if (nfds == 0) {
assert(timeout != -1); assert(timeout != -1);
timeout = real_timeout - timeout; if (timeout == 0)
if (timeout > 0) return;
continue;
return; /* We may have been inside the system call for longer than |timeout|
* milliseconds so we need to update the timestamp to avoid drift.
*/
goto update_timeout;
} }
if (nfds == -1) { if (nfds == -1) {