-
Notifications
You must be signed in to change notification settings - Fork 30.2k
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
timers: fix regression with clearImmediate() #9086
Conversation
f1481ac
to
2f4bc27
Compare
I think the test can be sped up and simplified like this: 'use strict';
require('../common');
const assert = require('assert');
const jobs = 5;
var count = 0;
for (var i = 0; i < jobs; i++) {
const timeout = setTimeout(() => {
clearTimeout(timeout);
(function retry() {
var immediate = setImmediate(() => {
clearImmediate(immediate);
++count;
});
}());
}, 0);
}
process.on('exit', () => {
assert.strictEqual(count, jobs);
}); This fails reliably for me with v6.8.0 and passes reliably with v6.7.0. |
2f4bc27
to
8d0d489
Compare
I've reduced the test to something even simpler, as it really has nothing to do with |
const assert = require('assert'); | ||
|
||
var count = 0; | ||
const timestamp = Date.now(); |
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.
This constant appears to be unused.
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.
(And before anybody asks, I just checked, and yes, the linter catches it.)
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.
Too late, I already removed it ;-)
8d0d489
to
46f9d1f
Compare
The removal of |
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.
LGTM if there are no surprises lurking in CI.
Since this is a fix of a bug introduced in a change that brought a performance improvement, is it at all worthwhile to run the same benchmark that was run on the original change just to make sure there's no surprises there? (This change seems to me to be unlikely to cause a performance regression, but what do I know?)
next(); | ||
|
||
process.on('exit', () => { | ||
assert.strictEqual(count, 3); |
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.
a failure description (3rd argument) would be nice
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.
Added.
@@ -696,6 +705,7 @@ function createImmediate(args, callback) { | |||
|
|||
|
|||
exports.clearImmediate = function(immediate) { | |||
// TODO: also verify `immediate instanceof Immediate`? |
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.
the linkedlist remove should already be guarding against problems, seems unnecessary
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.
It only checks property names, which I think could be problematic if someone passes in something that isn't a value returned by setImmediate()
? I've removed the comment for now anyway...
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.
hmmm you might be right, probably not for this pr tho
@@ -575,12 +575,21 @@ function processImmediate() { | |||
domain.enter(); | |||
|
|||
immediate._callback = immediate._onImmediate; | |||
|
|||
// Save next in case `clearImmediate(immediate)` is called from callback | |||
var next = immediate._idleNext; |
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.
const?
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 kept with var
because it is still used throughout timers.js.
}); | ||
} | ||
for (var i = 0; i < 3; ++i) | ||
next(); |
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.
wasn't the original test recursive? should this still be?
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.
It wasn't really recursive, just "restarting" an immediate timer. However, that's not necessary to reproduce the original issue. The issue just has to do with calling clearImmediate()
from within an immediate callback when there are other items in the immediate queue.
@Trott I already checked, there is no performance regression with this fix. |
46f9d1f
to
29a03ae
Compare
This commit fixes a regression introduced in 0ed8839 that caused additional queued immediate callbacks to be ignored if `clearImmediate(immediate)` was called within the callback for `immediate`. Fixes: nodejs#9084
29a03ae
to
6750abf
Compare
next(); | ||
|
||
process.on('exit', () => { | ||
assert.strictEqual(count, N, `Expected ${N} immediate callback executions`); |
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.
Nit: Maybe even go a bit further?
'use strict';
const common = require('../common');
function next() {
const immediate = setImmediate(common.mustCall(function callback() {
clearImmediate(immediate);
}));
}
for (var i = 0; i < 3; ++i)
next();
One benefit is that we don't lose the information of what count
was if the assertion fires.
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.
One benefit is that we don't lose the information of what
count
was if the assertion fires.
I don't understand what you mean here.
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.
With the way the test is written now, when the test fails, we get:
AssertionError: Expected 3 immediate callback executions
So, we were expecting 3, but we got some other number. How many? 0? 1? 2? 4?
So I was looking at how to work count
in there so that information would be preserved, but I realized we could just do away with the explicit exit
listener entirely if we use common.mustCall()
. So if you use the test as written in that previous comment and it fails, you get results of this format:
Mismatched callback function calls. Expected 1, actual 0.
And the test is a compact 10 lines to boot.
(As usual: It's a nit, so you know, ignore my suggestion if you don't like it.)
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.
@Fishrock123 Is this ok with you, since you previously requested that a custom assertion message be added?
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.
lgtm
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.
LGTM
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.
LGTM
Landed in 42158a0. Thanks! |
This commit fixes a regression introduced in 0ed8839 that caused additional queued immediate callbacks to be ignored if `clearImmediate(immediate)` was called within the callback for `immediate`. PR-URL: #9086 Fixes: #9084 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
This commit fixes a regression introduced in 0ed8839 that caused additional queued immediate callbacks to be ignored if `clearImmediate(immediate)` was called within the callback for `immediate`. PR-URL: #9086 Fixes: #9084 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
This commit fixes a regression introduced in 0ed8839 that caused additional queued immediate callbacks to be ignored if `clearImmediate(immediate)` was called within the callback for `immediate`. PR-URL: #9086 Fixes: #9084 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
This commit fixes a regression introduced in 0ed8839 that caused additional queued immediate callbacks to be ignored if `clearImmediate(immediate)` was called within the callback for `immediate`. PR-URL: #9086 Fixes: #9084 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Evan Lucas <evanlucas@me.com>
* build: Fix building with shared zlib. (Bradley T. Hughes) [#9077](nodejs/node#9077) * stream: fix `Writable` subclass instanceof checks (Anna Henningsen) [#9088](nodejs/node#9088) * timers: fix regression with clearImmediate() (Brian White) [#9086](nodejs/node#9086) Signed-off-by: Ilkka Myller <ilkka.myller@nodefield.com>
* build: Fix building with shared zlib. (Bradley T. Hughes) [#9077](nodejs/node#9077) * stream: fix `Writable` subclass instanceof checks (Anna Henningsen) [#9088](nodejs/node#9088) * timers: fix regression with clearImmediate() (Brian White) [#9086](nodejs/node#9086) Signed-off-by: Ilkka Myller <ilkka.myller@nodefield.com>
@Fishrock123 should this be bacporrted? |
@thealphanerd The original PR (#8655) these changes depend on was never landed on v4.x, so I would say no. However, the original PR is also marked as |
Checklist
make -j8 test
(UNIX), orvcbuild test nosign
(Windows) passesAffected core subsystem(s)
Description of change
This commit fixes a regression introduced in 0ed8839 that caused additional queued immediate callbacks to be ignored if
clearImmediate(immediate)
was called within the callback forimmediate
.Fixes: #9084
CI: https://ci.nodejs.org/job/node-test-pull-request/4513/
CITGM: https://ci.nodejs.org/view/Node.js-citgm/job/citgm-smoker/415/