Skip to content

udp: callbacks are effectively synchronous #301

@bnoordhuis

Description

@bnoordhuis

From nodejs/node#1313 (comment):

  1. Libuv loops over the write requests in the completed queue.
  2. For every request, it hands it off to io.js
  3. io.js calls into JS land
  4. JS land calls uv_udp_send() again (dgram.send())
  5. The write succeed immediately and uv_udp_send() pushes the request onto the completed queue, the same queue it's currently iterating over.

Commit 4189122 introduced this. The (very lightly tested) patch below fixes it:

diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c
index 941c0ae..177ad43 100644
--- a/deps/uv/src/unix/udp.c
+++ b/deps/uv/src/unix/udp.c
@@ -133,10 +133,8 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
   if (revents & UV__POLLIN)
     uv__udp_recvmsg(handle);

-  if (revents & UV__POLLOUT) {
+  if (revents & UV__POLLOUT)
     uv__udp_sendmsg(handle);
-    uv__udp_run_completed(handle);
-  }
 }

Running QUEUE_SPLIT on handle->write_completed_queue before dispatching the callbacks in uv__udp_run_completed does not have the desired effect.

I'm not sure if a better fix that maintains the throughput benefits of calling uv__udp_run_completed() repeatedly is possible.

Refs: nodejs/node#486
Refs: nodejs/node#1258
Refs: nodejs/node#1313

/cc @saghul

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions