Skip to content

Commit

Permalink
timers: async track unref timers
Browse files Browse the repository at this point in the history
When async hooks integration for Timers was introduced, it was
not included in the code for unref'd or subsequently ref'd
timers which means those timers only have Timerwrap hooks.

PR-URL: #18579
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
  • Loading branch information
apapirovski committed Feb 8, 2018
1 parent 568b6a5 commit c11cb03
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 3 deletions.
6 changes: 3 additions & 3 deletions lib/timers.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,15 @@ TimerWrap.prototype[kOnTimeout] = function listOnTimeout(now) {

// An optimization so that the try/finally only de-optimizes (since at least v8
// 4.7) what is in this smaller function.
function tryOnTimeout(timer) {
function tryOnTimeout(timer, start) {
timer._called = true;
const timerAsyncId = (typeof timer[async_id_symbol] === 'number') ?
timer[async_id_symbol] : null;
var threw = true;
if (timerAsyncId !== null)
emitBefore(timerAsyncId, timer[trigger_async_id_symbol]);
try {
ontimeout(timer);
ontimeout(timer, start);
threw = false;
} finally {
if (timerAsyncId !== null) {
Expand Down Expand Up @@ -520,7 +520,7 @@ function unrefdHandle(now) {
try {
// Don't attempt to call the callback if it is not a function.
if (typeof this.owner._onTimeout === 'function') {
ontimeout(this.owner, now);
tryOnTimeout(this.owner, now);
}
} finally {
// Make sure we clean up if the callback is no longer a function
Expand Down
61 changes: 61 additions & 0 deletions test/async-hooks/test-timers.setTimeout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict';

const common = require('../common');
const assert = require('assert');
const tick = require('./tick');
const initHooks = require('./init-hooks');
const { checkInvocations } = require('./hook-checks');
const TIMEOUT = common.platformTimeout(100);

const hooks = initHooks();
hooks.enable();

// install first timeout
setTimeout(common.mustCall(ontimeout), TIMEOUT);
const as = hooks.activitiesOfTypes('Timeout');
assert.strictEqual(as.length, 1);
const t1 = as[0];
assert.strictEqual(t1.type, 'Timeout');
assert.strictEqual(typeof t1.uid, 'number');
assert.strictEqual(typeof t1.triggerAsyncId, 'number');
checkInvocations(t1, { init: 1 }, 't1: when first timer installed');

let timer;
let t2;
function ontimeout() {
checkInvocations(t1, { init: 1, before: 1 }, 't1: when first timer fired');

setTimeout(onSecondTimeout, TIMEOUT).unref();
const as = hooks.activitiesOfTypes('Timeout');
t2 = as[1];
assert.strictEqual(as.length, 2);
checkInvocations(t1, { init: 1, before: 1 },
't1: when second timer installed');
checkInvocations(t2, { init: 1 },
't2: when second timer installed');

timer = setTimeout(common.mustNotCall(), 2 ** 31 - 1);
}

function onSecondTimeout() {
const as = hooks.activitiesOfTypes('Timeout');
assert.strictEqual(as.length, 3);
checkInvocations(t1, { init: 1, before: 1, after: 1 },
't1: when second timer fired');
checkInvocations(t2, { init: 1, before: 1 },
't2: when second timer fired');
clearTimeout(timer);
tick(2);
}

process.on('exit', onexit);

function onexit() {
hooks.disable();
hooks.sanityCheck('Timeout');

checkInvocations(t1, { init: 1, before: 1, after: 1, destroy: 1 },
't1: when process exits');
checkInvocations(t2, { init: 1, before: 1, after: 1, destroy: 1 },
't2: when process exits');
}

0 comments on commit c11cb03

Please sign in to comment.