timers: setInterval interval includes cb duration

setInterval callback should be scheduled on the interval

Fixes: https://github.com/nodejs/node/issues/7346

PR-URL: https://github.com/nodejs/node/pull/14815
Fixes: https://github.com/nodejs/node/issues/7346
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
This commit is contained in:
zhangzifa 2017-08-14 09:59:15 +08:00 committed by Ruben Bridgewater
parent e8c491a801
commit 1385e1bc63
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
2 changed files with 36 additions and 5 deletions

View File

@ -167,11 +167,15 @@ exports._unrefActive = function(item) {
// Appends a timer onto the end of an existing timers list, or creates a new // Appends a timer onto the end of an existing timers list, or creates a new
// TimerWrap backed list if one does not already exist for the specified timeout // TimerWrap backed list if one does not already exist for the specified timeout
// duration. // duration.
function insert(item, unrefed) { function insert(item, unrefed, start) {
const msecs = item._idleTimeout; const msecs = item._idleTimeout;
if (msecs < 0 || msecs === undefined) return; if (msecs < 0 || msecs === undefined) return;
item._idleStart = TimerWrap.now(); if (typeof start === 'number') {
item._idleStart = start;
} else {
item._idleStart = TimerWrap.now();
}
const lists = unrefed === true ? unrefedLists : refedLists; const lists = unrefed === true ? unrefedLists : refedLists;
@ -446,16 +450,17 @@ function ontimeout(timer) {
var args = timer._timerArgs; var args = timer._timerArgs;
if (typeof timer._onTimeout !== 'function') if (typeof timer._onTimeout !== 'function')
return promiseResolve(timer._onTimeout, args[0]); return promiseResolve(timer._onTimeout, args[0]);
const start = TimerWrap.now();
if (!args) if (!args)
timer._onTimeout(); timer._onTimeout();
else else
Reflect.apply(timer._onTimeout, timer, args); Reflect.apply(timer._onTimeout, timer, args);
if (timer._repeat) if (timer._repeat)
rearm(timer); rearm(timer, start);
} }
function rearm(timer) { function rearm(timer, start) {
// // Do not re-arm unenroll'd or closed timers. // // Do not re-arm unenroll'd or closed timers.
if (timer._idleTimeout === -1) return; if (timer._idleTimeout === -1) return;
@ -464,7 +469,15 @@ function rearm(timer) {
timer._handle.start(timer._repeat); timer._handle.start(timer._repeat);
} else { } else {
timer._idleTimeout = timer._repeat; timer._idleTimeout = timer._repeat;
active(timer);
const duration = TimerWrap.now() - start;
if (duration >= timer._repeat) {
// If callback duration >= timer._repeat,
// add 1 ms to avoid blocking eventloop
insert(timer, false, start + duration - timer._repeat + 1);
} else {
insert(timer, false, start);
}
} }
} }

View File

@ -0,0 +1,18 @@
'use strict';
const common = require('../common');
const Timer = process.binding('timer_wrap').Timer;
const assert = require('assert');
let cntr = 0;
let first, second;
const t = setInterval(() => {
common.busyLoop(50);
cntr++;
if (cntr === 1) {
first = Timer.now();
} else if (cntr === 2) {
second = Timer.now();
assert(Math.abs(second - first - 100) < 10);
clearInterval(t);
}
}, 100);