Skip to content

Commit

Permalink
dgram: use uv_udp_try_send()
Browse files Browse the repository at this point in the history
This improves dgram performance by avoiding unnecessary async
operations.

One issue with this commit is that it seems hard to actually create
conditions under which the fallback path to the async case is
actually taken, for all supported OS, so an internal CLI option
is used for testing that path.

Another caveat is that the lack of an async operation means
that there are slight timing differences (essentially `nextTick()`
rather than `setImmediate()` for the send callback).

PR-URL: nodejs/node#29832
Reviewed-By: David Carlier <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
  • Loading branch information
addaleax authored and juanarbol committed Dec 17, 2019
1 parent cf1b39e commit ed57956
Showing 1 changed file with 39 additions and 4 deletions.
43 changes: 39 additions & 4 deletions src/udp_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -512,9 +512,7 @@ void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
// array in js-land
size_t count = args[2].As<Uint32>()->Value();

wrap->current_send_req_wrap_ = args[0].As<Object>();
wrap->current_send_has_callback_ =
sendto ? args[5]->IsTrue() : args[3]->IsTrue();
size_t msg_size = 0;

MaybeStackBuffer<uv_buf_t, 16> bufs(count);

Expand All @@ -539,8 +537,45 @@ void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
}
}

uv_buf_t* bufs_ptr = *bufs;
if (err == 0 && !UNLIKELY(env->options()->test_udp_no_try_send)) {
err = uv_udp_try_send(&wrap->handle_, bufs_ptr, count, addr);
if (err == UV_ENOSYS || err == UV_EAGAIN) {
err = 0;
} else if (err >= 0) {
size_t sent = err;
while (count > 0 && bufs_ptr->len <= sent) {
sent -= bufs_ptr->len;
bufs_ptr++;
count--;
}
if (count > 0) {
CHECK_LT(sent, bufs_ptr->len);
bufs_ptr->base += sent;
bufs_ptr->len -= sent;
} else {
CHECK_EQ(static_cast<size_t>(err), msg_size);
// + 1 so that the JS side can distinguish 0-length async sends from
// 0-length sync sends.
args.GetReturnValue().Set(static_cast<uint32_t>(msg_size) + 1);
return;
}
}
}

if (err == 0) {
err = wrap->Send(*bufs, count, addr);
AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(wrap);
SendWrap* req_wrap = new SendWrap(env, req_wrap_obj, have_callback);
req_wrap->msg_size = msg_size;

err = req_wrap->Dispatch(uv_udp_send,
&wrap->handle_,
bufs_ptr,
count,
addr,
OnSend);
if (err)
delete req_wrap;
}

args.GetReturnValue().Set(err);
Expand Down

0 comments on commit ed57956

Please sign in to comment.