Skip to content

Commit c11cb03

Browse files
committed
timers: async track unref timers
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>
1 parent 568b6a5 commit c11cb03

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

lib/timers.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,15 +289,15 @@ TimerWrap.prototype[kOnTimeout] = function listOnTimeout(now) {
289289

290290
// An optimization so that the try/finally only de-optimizes (since at least v8
291291
// 4.7) what is in this smaller function.
292-
function tryOnTimeout(timer) {
292+
function tryOnTimeout(timer, start) {
293293
timer._called = true;
294294
const timerAsyncId = (typeof timer[async_id_symbol] === 'number') ?
295295
timer[async_id_symbol] : null;
296296
var threw = true;
297297
if (timerAsyncId !== null)
298298
emitBefore(timerAsyncId, timer[trigger_async_id_symbol]);
299299
try {
300-
ontimeout(timer);
300+
ontimeout(timer, start);
301301
threw = false;
302302
} finally {
303303
if (timerAsyncId !== null) {
@@ -520,7 +520,7 @@ function unrefdHandle(now) {
520520
try {
521521
// Don't attempt to call the callback if it is not a function.
522522
if (typeof this.owner._onTimeout === 'function') {
523-
ontimeout(this.owner, now);
523+
tryOnTimeout(this.owner, now);
524524
}
525525
} finally {
526526
// Make sure we clean up if the callback is no longer a function
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const tick = require('./tick');
6+
const initHooks = require('./init-hooks');
7+
const { checkInvocations } = require('./hook-checks');
8+
const TIMEOUT = common.platformTimeout(100);
9+
10+
const hooks = initHooks();
11+
hooks.enable();
12+
13+
// install first timeout
14+
setTimeout(common.mustCall(ontimeout), TIMEOUT);
15+
const as = hooks.activitiesOfTypes('Timeout');
16+
assert.strictEqual(as.length, 1);
17+
const t1 = as[0];
18+
assert.strictEqual(t1.type, 'Timeout');
19+
assert.strictEqual(typeof t1.uid, 'number');
20+
assert.strictEqual(typeof t1.triggerAsyncId, 'number');
21+
checkInvocations(t1, { init: 1 }, 't1: when first timer installed');
22+
23+
let timer;
24+
let t2;
25+
function ontimeout() {
26+
checkInvocations(t1, { init: 1, before: 1 }, 't1: when first timer fired');
27+
28+
setTimeout(onSecondTimeout, TIMEOUT).unref();
29+
const as = hooks.activitiesOfTypes('Timeout');
30+
t2 = as[1];
31+
assert.strictEqual(as.length, 2);
32+
checkInvocations(t1, { init: 1, before: 1 },
33+
't1: when second timer installed');
34+
checkInvocations(t2, { init: 1 },
35+
't2: when second timer installed');
36+
37+
timer = setTimeout(common.mustNotCall(), 2 ** 31 - 1);
38+
}
39+
40+
function onSecondTimeout() {
41+
const as = hooks.activitiesOfTypes('Timeout');
42+
assert.strictEqual(as.length, 3);
43+
checkInvocations(t1, { init: 1, before: 1, after: 1 },
44+
't1: when second timer fired');
45+
checkInvocations(t2, { init: 1, before: 1 },
46+
't2: when second timer fired');
47+
clearTimeout(timer);
48+
tick(2);
49+
}
50+
51+
process.on('exit', onexit);
52+
53+
function onexit() {
54+
hooks.disable();
55+
hooks.sanityCheck('Timeout');
56+
57+
checkInvocations(t1, { init: 1, before: 1, after: 1, destroy: 1 },
58+
't1: when process exits');
59+
checkInvocations(t2, { init: 1, before: 1, after: 1, destroy: 1 },
60+
't2: when process exits');
61+
}

0 commit comments

Comments
 (0)