timers: reuse timer in setTimeout().unref()
Instead of creating new timer - reuse the timer from the freelist. This won't make the freelist timer active for the duration of `uv_close()`, and will let the event-loop exit properly. Fix: #1264 PR-URL: https://github.com/nodejs/node/pull/3407 Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
This commit is contained in:
parent
57f99a9479
commit
3eecdf9f14
@ -119,16 +119,27 @@ function listOnTimeoutNT(list) {
|
||||
}
|
||||
|
||||
|
||||
const unenroll = exports.unenroll = function(item) {
|
||||
function reuse(item) {
|
||||
L.remove(item);
|
||||
|
||||
var list = lists[item._idleTimeout];
|
||||
// if empty then stop the watcher
|
||||
debug('unenroll');
|
||||
// if empty - reuse the watcher
|
||||
if (list && L.isEmpty(list)) {
|
||||
debug('reuse hit');
|
||||
list.stop();
|
||||
delete lists[item._idleTimeout];
|
||||
return list;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
const unenroll = exports.unenroll = function(item) {
|
||||
var list = reuse(item);
|
||||
if (list) {
|
||||
debug('unenroll: list empty');
|
||||
list.close();
|
||||
delete lists[item._idleTimeout];
|
||||
}
|
||||
// if active is called later, then we want to make sure not to insert again
|
||||
item._idleTimeout = -1;
|
||||
@ -312,12 +323,16 @@ Timeout.prototype.unref = function() {
|
||||
if (!this._idleStart) this._idleStart = now;
|
||||
var delay = this._idleStart + this._idleTimeout - now;
|
||||
if (delay < 0) delay = 0;
|
||||
exports.unenroll(this);
|
||||
|
||||
// Prevent running cb again when unref() is called during the same cb
|
||||
if (this._called && !this._repeat) return;
|
||||
if (this._called && !this._repeat) {
|
||||
exports.unenroll(this);
|
||||
return;
|
||||
}
|
||||
|
||||
this._handle = new Timer();
|
||||
var handle = reuse(this);
|
||||
|
||||
this._handle = handle || new Timer();
|
||||
this._handle.owner = this;
|
||||
this._handle[kOnTimeout] = unrefdHandle;
|
||||
this._handle.start(delay, 0);
|
||||
|
20
test/parallel/test-timers-unrefed-in-beforeexit.js
Normal file
20
test/parallel/test-timers-unrefed-in-beforeexit.js
Normal file
@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
var once = 0;
|
||||
|
||||
process.on('beforeExit', () => {
|
||||
if (once > 1)
|
||||
throw new RangeError('beforeExit should only have been called once!');
|
||||
|
||||
setTimeout(() => {}, 1).unref();
|
||||
once++;
|
||||
});
|
||||
|
||||
process.on('exit', (code) => {
|
||||
if (code !== 0) return;
|
||||
|
||||
assert.strictEqual(once, 1);
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user