Skip to content

Commit 16f2600

Browse files
cjihrigaddaleax
authored andcommitted
child_process: emit IPC messages on next tick
This commit fixes a regression related to IPC 'message' events. When messages are not emitted in the next tick, a 'message' handler that throws can break the IPC read loop. Refs: #6909 Refs: #13459 Refs: #13648 PR-URL: #13856 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]>
1 parent f2d7b80 commit 16f2600

File tree

2 files changed

+46
-11
lines changed

2 files changed

+46
-11
lines changed

lib/internal/child_process.js

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,6 @@ function setupChannel(target, channel) {
456456
}
457457
chunks[0] = jsonBuffer + chunks[0];
458458

459-
var nextTick = false;
460459
for (var i = 0; i < numCompleteChunks; i++) {
461460
var message = JSON.parse(chunks[i]);
462461

@@ -465,12 +464,11 @@ function setupChannel(target, channel) {
465464
// that we deliver the handle with the right message however.
466465
if (isInternal(message)) {
467466
if (message.cmd === 'NODE_HANDLE')
468-
handleMessage(message, recvHandle, true, false);
467+
handleMessage(message, recvHandle, true);
469468
else
470-
handleMessage(message, undefined, true, false);
469+
handleMessage(message, undefined, true);
471470
} else {
472-
handleMessage(message, undefined, false, nextTick);
473-
nextTick = true;
471+
handleMessage(message, undefined, false);
474472
}
475473
}
476474
jsonBuffer = incompleteChunk;
@@ -532,7 +530,7 @@ function setupChannel(target, channel) {
532530

533531
// Convert handle object
534532
obj.got.call(this, message, handle, function(handle) {
535-
handleMessage(message.msg, handle, isInternal(message.msg), false);
533+
handleMessage(message.msg, handle, isInternal(message.msg));
536534
});
537535
});
538536

@@ -742,15 +740,13 @@ function setupChannel(target, channel) {
742740
target.emit(event, message, handle);
743741
}
744742

745-
function handleMessage(message, handle, internal, nextTick) {
743+
function handleMessage(message, handle, internal) {
746744
if (!target.channel)
747745
return;
748746

749747
var eventName = (internal ? 'internalMessage' : 'message');
750-
if (nextTick)
751-
process.nextTick(emit, eventName, message, handle);
752-
else
753-
target.emit(eventName, message, handle);
748+
749+
process.nextTick(emit, eventName, message, handle);
754750
}
755751

756752
channel.readStart();
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const cp = require('child_process');
5+
const NUM_MESSAGES = 10;
6+
const values = [];
7+
8+
for (let i = 0; i < NUM_MESSAGES; ++i) {
9+
values[i] = i;
10+
}
11+
12+
if (process.argv[2] === 'child') {
13+
const received = values.map(() => { return false; });
14+
15+
process.on('uncaughtException', common.mustCall((err) => {
16+
received[err] = true;
17+
const done = received.every((element) => { return element === true; });
18+
19+
if (done)
20+
process.disconnect();
21+
}, NUM_MESSAGES));
22+
23+
process.on('message', (msg) => {
24+
// If messages are handled synchronously, throwing should break the IPC
25+
// message processing.
26+
throw msg;
27+
});
28+
29+
process.send('ready');
30+
} else {
31+
const child = cp.fork(__filename, ['child']);
32+
33+
child.on('message', common.mustCall((msg) => {
34+
assert.strictEqual(msg, 'ready');
35+
values.forEach((value) => {
36+
child.send(value);
37+
});
38+
}));
39+
}

0 commit comments

Comments
 (0)