• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2const common = require('../common');
3
4if (common.isWindows)
5  common.skip('no signals in Windows');
6if (!common.isMainThread)
7  common.skip('No signal handling available in Workers');
8
9const assert = require('assert');
10const initHooks = require('./init-hooks');
11const { checkInvocations } = require('./hook-checks');
12const exec = require('child_process').exec;
13
14const hooks = initHooks();
15
16hooks.enable();
17
18// Keep the event loop open so process doesn't exit before receiving signals.
19const interval = setInterval(() => {}, 9999);
20
21process.on('SIGUSR2', common.mustCall(onsigusr2, 2));
22
23const as = hooks.activitiesOfTypes('SIGNALWRAP');
24assert.strictEqual(as.length, 1);
25const signal1 = as[0];
26assert.strictEqual(signal1.type, 'SIGNALWRAP');
27assert.strictEqual(typeof signal1.uid, 'number');
28assert.strictEqual(typeof signal1.triggerAsyncId, 'number');
29checkInvocations(signal1, { init: 1 }, 'when SIGUSR2 handler is set up');
30
31let count = 0;
32exec(`kill -USR2 ${process.pid}`);
33
34let signal2;
35
36function onsigusr2() {
37  count++;
38
39  if (count === 1) {
40    // first invocation
41    checkInvocations(
42      signal1, { init: 1, before: 1 },
43      ' signal1: when first SIGUSR2 handler is called for the first time');
44
45    // Trigger same signal handler again
46    exec(`kill -USR2 ${process.pid}`);
47  } else {
48    // second invocation
49    checkInvocations(
50      signal1, { init: 1, before: 2, after: 1 },
51      'signal1: when first SIGUSR2 handler is called for the second time');
52
53    // Install another signal handler
54    process.removeAllListeners('SIGUSR2');
55    process.on('SIGUSR2', common.mustCall(onsigusr2Again));
56
57    const as = hooks.activitiesOfTypes('SIGNALWRAP');
58    // The isTTY checks are needed to allow test to work whether run with
59    // test.py or directly with the node executable. The third signal event
60    // listener is the SIGWINCH handler that node installs when it thinks
61    // process.stdout is a tty.
62    const expectedLen = 2 + (!!process.stdout.isTTY || !!process.stderr.isTTY);
63    assert.strictEqual(as.length, expectedLen);
64    signal2 = as[expectedLen - 1]; // Last item in the array.
65    assert.strictEqual(signal2.type, 'SIGNALWRAP');
66    assert.strictEqual(typeof signal2.uid, 'number');
67    assert.strictEqual(typeof signal2.triggerAsyncId, 'number');
68
69    checkInvocations(
70      signal1, { init: 1, before: 2, after: 1 },
71      'signal1: when second SIGUSR2 handler is set up');
72    checkInvocations(
73      signal2, { init: 1 },
74      'signal2: when second SIGUSR2 handler is setup');
75
76    exec(`kill -USR2 ${process.pid}`);
77  }
78}
79
80function onsigusr2Again() {
81  clearInterval(interval);
82  setImmediate(() => {
83    checkInvocations(
84      signal1, { init: 1, before: 2, after: 2, destroy: 1 },
85      'signal1: when second SIGUSR2 handler is called');
86    checkInvocations(
87      signal2, { init: 1, before: 1 },
88      'signal2: when second SIGUSR2 handler is called');
89  });
90}
91
92process.on('exit', onexit);
93
94function onexit() {
95  hooks.disable();
96  hooks.sanityCheck('SIGNALWRAP');
97  checkInvocations(
98    signal1, { init: 1, before: 2, after: 2, destroy: 1 },
99    'signal1: when second SIGUSR2 process exits');
100  // Second signal not destroyed yet since its event listener is still active
101  checkInvocations(
102    signal2, { init: 1, before: 1, after: 1 },
103    'signal2: when second SIGUSR2 process exits');
104}
105