Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

unix: fix loop starvation under high network load

uv__read() and uv__udp_recvmsg() read incoming data in a loop. If data comes
in at high speeds, the kernel receive buffer never drains and said functions
never terminate, stalling the event loop indefinitely. Limit the number of
consecutive reads to 32 to stop that from happening.

The number 32 was chosen at random. Empirically, it seems to maintain a high
throughput while still making the event loop move forward at a reasonable pace.

This is a back-port of commit 738b31e from the master branch.

Conflicts:
	src/unix/stream.c
  • Loading branch information...
commit 06e03193d59b9e8a4714e83902d1938c07192a34 1 parent dbe681e
@bnoordhuis bnoordhuis authored
Showing with 16 additions and 3 deletions.
  1. +9 −2 src/unix/stream.c
  2. +7 −1 src/unix/udp.c
View
11 src/unix/stream.c
@@ -523,12 +523,19 @@ static void uv__read(uv_stream_t* stream) {
struct cmsghdr* cmsg;
char cmsg_space[64];
struct ev_loop* ev = stream->loop->ev;
+ int count;
+
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
+ */
+ count = 32;
/* XXX: Maybe instead of having UV_READING we just test if
* tcp->read_cb is NULL or not?
*/
- while ((stream->read_cb || stream->read2_cb) &&
- stream->flags & UV_READING) {
+ while ((stream->read_cb || stream->read2_cb)
+ && (stream->flags & UV_READING)
+ && (count-- > 0)) {
assert(stream->alloc_cb);
buf = stream->alloc_cb((uv_handle_t*)stream, 64 * 1024);
View
8 src/unix/udp.c
@@ -208,12 +208,17 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
ssize_t nread;
uv_buf_t buf;
int flags;
+ int count;
assert(handle->recv_cb != NULL);
assert(handle->alloc_cb != NULL);
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
+ */
+ count = 32;
+
do {
- /* FIXME: hoist alloc_cb out the loop but for now follow uv__read() */
buf = handle->alloc_cb((uv_handle_t*)handle, 64 * 1024);
assert(buf.len > 0);
assert(buf.base != NULL);
@@ -254,6 +259,7 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
}
/* recv_cb callback may decide to pause or close the handle */
while (nread != -1
+ && count-- > 0
&& handle->fd != -1
&& handle->recv_cb != NULL);
}
Please sign in to comment.
Something went wrong with that request. Please try again.