-
Notifications
You must be signed in to change notification settings - Fork 30.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
dgram: call send callback asynchronously #1313
Conversation
(also, this may be semver-major, like process.send) |
I vote for bug fix, as it was once asynchronous and we just didn't notice the regression (?). |
@brendanashworth I agree with that. |
I feel like a fix for this should belong in libuv rather than io.js, it feels rather hacky, as I don't believe we do this for any other libuv bindings. Plus, it was a commit in libuv that caused this regression, thoughts? |
"every callback should be asynchronous" is a rule for Node/io.js (#486 (comment)). libuv does not have the rule. According to the libuv pull request joyent/libuv#1358, this change is to improve UDP request performance. So, this is not regression for libuv. |
var self = this; | ||
setImmediate(function() { | ||
self.callback(err, self.length); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm. Would there still be the same problem if you used process.nextTick()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried earlier today. setImmediate() works but process.nextTick() still hangs.
From some ad hoc testing I got the impression that the event loop is making some progress - i.e. it's not that dgram.send() is truly synchronous - but it's not making enough progress for the setTimeout timer in benchmark/net/dgram.js to fire.
Agreed this is a bug fix. The callback should have always been called asynchronously, and there's no API dependency requiring the order in which the callback is called. |
throw new Error('infinite loop detected'); | ||
} | ||
if (received < limit) { | ||
client.send(chunk, 0, chunk.length, common.PORT, common.localhostIPv4, onsend); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry to be that guy but can you wrap this line at 80 columns?
LGTM with style nits. The issue of why dgram behaves this way needs further investigation because I couldn't quite figure it out earlier today. What I observed is this:
|
I think I had a moment of rubber duck debugging just there, I think I figured it out. :-) uv_udp_send() pushes the request onto the completed queue when the write succeeds (which is nearly always.) The first time the callback fires:
I think this qualifies as a libuv bug. /cc @saghul |
For the record, the patch below fixes (what is effectively) the infinite loop. 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);
- }
}
|
Yeah, I think it does qualify as a libuv bug. Can you open an issue for it?
|
Done: libuv/libuv#301 |
Thank you @bnoordhuis !! I fixed a test as you reviewed. And I tried to apply the patch, but I got some
|
Sorry, I should have made clear that I don't consider that patch a proper fix, it's just to demonstrate that the uv__udp_run_completed() call causes the issue. The PR LGTM but I suggest that in the commit log you explain what the issue is and that it's a temporary fix until libuv/libuv#301 is resolved. |
@yosuke-furukawa ping on a merge |
oops, I will merge it soon. |
dgram#send callback was changed synchronously. The PR-URL is here joyent/libuv#1358 This commit is temporary fix until libuv issue is resolved. libuv/libuv#301 PR-URL: #1313 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Landed on 18d457b |
This test case fails on our CI. Please make sure to run things like this on the CI before landing. :)
|
PR-URL: nodejs#1679 Notable Changes: * win,node-gyp: the delay-load hook for windows addons has now been correctly enabled by default, it had wrongly defaulted to off in the release version of 2.0.0 (Bert Belder) nodejs#1433 * os: tmpdir()'s trailing slash stripping has been refined to fix an issue when the temp directory is at '/'. Also considers which slash is used by the operating system. (cjihrig) nodejs#1673 * tls: default ciphers have been updated to use gcm and aes128 (Mike MacCana) nodejs#1660 * build: v8 snapshots have been re-enabled by default as suggested by the v8 team, since prior security issues have been resolved. This should give some perf improvements to both startup and vm context creation. (Trevor Norris) nodejs#1663 * src: fixed preload modules not working when other flags were used before --require (Yosuke Furukawa) nodejs#1694 * dgram: fixed send()'s callback not being asynchronous (Yosuke Furukawa) nodejs#1313 * readline: emitKeys now keeps buffering data until it has enough to parse. This fixes an issue with parsing split escapes. (Alex Kocharin) * cluster: works now properly emit 'disconnect' to cluser.worker (Oleg Elifantiev) nodejs#1386 events: uncaught errors now provide some context (Evan Lucas) nodejs#1654
dgram#send callback was changed synchronously. The PR-URL is here joyent/libuv#1358 This commit is temporary fix until libuv issue is resolved. libuv/libuv#301 PR-URL: nodejs#1313 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Revert "dgram: call send callback asynchronously" partially, since the fix is now done in libuv. Refs: nodejs#1313 Refs: libuv/libuv#371
Revert "dgram: call send callback asynchronously" partially, since the fix is now done in libuv. Refs: #1313 Refs: libuv/libuv#371 PR-URL: #1889 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
According to this issue #486, every callbacks should be called asynchronously, But
dgram.send
callback is not called asynchronously.We can not run full benchmark test.
benchmark/net/dgram.js
uses send callback recursively.But send callback is not asynchronous, the recursive callback goes infinite loop.
If this fix is accepted, we could run full benchmark test on every release.
I think libuv changes the uv_udp_send API on this commit libuv/libuv@4189122.
So I just fixed callback asynchronously using
setImmediate
.