-
Notifications
You must be signed in to change notification settings - Fork 30.5k
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
WIP src: don't check closing handles on beforeExit #1317
Conversation
Fixes// before-exit-hangs.js
'use strict';
process.on('beforeExit', function() {
setInterval(function() {}, 1).unref();
}); This one would hang indefinitey // unrefd-timers-execute-onexit.js
var assert = require("assert")
var intervals = 0
var i = setInterval(function () {
intervals++
i.unref()
eatTime()
}, 10)
function eatTime() {
// the goal of this function is to take longer than the interval
var count = 0
while (count++ < 1e7) {
Math.random()
}
}
process.on("exit", function () {
assert.equal(intervals, 1)
}) Still failing// test-regress-GH-io-1151.js
var assert = require('assert');
setImmediate(function () {
require("http");
});
var i = setInterval(function () {
setImmediate(process.exit)
}, 10);
i.unref();
process.on("exit", onexit);
function onexit() {
assert.strictEqual(process._getActiveHandles().length, 0, 'should have no more active handles on exit')
} // test-timers-unref-interval-exit-after-next.js
var assert = require('assert');
var i = setInterval(function () {
// does not matter if we swap the nextTick with the setImmediate
process.nextTick(function() {
setImmediate(process.exit);
})
}, 1);
i.unref();
process.on('exit', function() {
assert.strictEqual(process._getActiveHandles().length, 0);
}); |
8b9cc25
to
583b570
Compare
I investigated into libuv a bit and found the following oddity: If you call Then when you call So if we go around the loop while one handle is closing we won't exit, but during that loop a new handle could be created. Not sure if I'm misunderstanding something here or if this could be at least one reason for this issue. @saghul please correct me if I'm wrong here. |
@thlorenz Your analysis is correct but I wouldn't call it an oddity, it's by design. Close callbacks must run because that's the only place in the life cycle of a handle where it's safe for the libuv embedder to clean up resources associated with the handle. That's why closing an unref'd handle gives it an implicit ref. |
more = true; | ||
more = env->event_loop()->active_handles || | ||
(env->event_loop()->active_reqs[0] != | ||
env->event_loop()->active_reqs[1]); |
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.
You're probably well aware of this but active_handles and active_reqs are implementation details.
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.
Yeah. That was done just to bring up the issue I'm working around, and the fact I can't figure out how to get around it.
583b570
to
4339d83
Compare
Related to #1151 |
uv_loop_alive() returns true if there are closing handles. This causes an issue running the beforeExit event and a timer has been unref'd: process.on('beforeExit', function() { setTimeout(function() { }, 100).unref(); }); The event loop also shouldn't run one additional time or else the timer may execute an additional time.
4339d83
to
190af5e
Compare
FWIW with this patch applied you can see from the logs that there is a race condition regarding active/closing handles when running A timer gets started while the previous one finishes closing. Excerpt
|
@bnoordhuis I understand now why close callbacks must run (also talked to @trevnorris about this). Is that correct? If yes do we need a solution or should we just tell people to not do that? |
That's correct and I'm inclined to say it's more of a documentation issue than a technical issue. |
After thinking on this, and the implications pointed out by @bnoordhuis with the need to run the |
uv_loop_alive() returns true if there are closing handles. This causes
an issue running the beforeExit event and a timer has been unref'd:
The event loop also shouldn't run one additional time or else the timer
may execute an additional time.
This is a WIP commit, and mainly opened to raise discussion around the problem at hand.
R=@bnoordhuis