Skip to content

Commit ff3ce11

Browse files
committed
child_process: support stdio option in fork()
This commit allows child_process.fork() to pass stdio options to spawn(). This allows fork() to more easily take advantage of additional stdio channels. Refs: nodejs/node-v0.x-archive#5727 PR-URL: #7811 Reviewed-By: Myles Borins <[email protected]> Reviewed-By: Minwoo Jung <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]>
1 parent 6123075 commit ff3ce11

File tree

3 files changed

+64
-4
lines changed

3 files changed

+64
-4
lines changed

doc/api/child_process.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,8 @@ added: v0.5.0
253253
piped to the parent, otherwise they will be inherited from the parent, see
254254
the `'pipe'` and `'inherit'` options for [`child_process.spawn()`][]'s
255255
[`stdio`][] for more details (Default: `false`)
256+
* `stdio` {Array} Supports the array version of [`child_process.spawn()`][]'s
257+
[`stdio`][] option. When this option is provided, it overrides `silent`.
256258
* `uid` {Number} Sets the user identity of the process. (See setuid(2).)
257259
* `gid` {Number} Sets the group identity of the process. (See setgid(2).)
258260
* Return: {ChildProcess}

lib/child_process.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,14 @@ exports.fork = function(modulePath /*, args, options*/) {
4949

5050
args = execArgv.concat([modulePath], args);
5151

52-
// Leave stdin open for the IPC channel. stdout and stderr should be the
53-
// same as the parent's if silent isn't set.
54-
options.stdio = options.silent ? ['pipe', 'pipe', 'pipe', 'ipc'] :
55-
[0, 1, 2, 'ipc'];
52+
if (!Array.isArray(options.stdio)) {
53+
// Leave stdin open for the IPC channel. stdout and stderr should be the
54+
// same as the parent's if silent isn't set.
55+
options.stdio = options.silent ? ['pipe', 'pipe', 'pipe', 'ipc'] :
56+
[0, 1, 2, 'ipc'];
57+
} else if (options.stdio.indexOf('ipc') === -1) {
58+
throw new TypeError('Forked processes must have an IPC channel');
59+
}
5660

5761
options.execPath = options.execPath || process.execPath;
5862

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const cp = require('child_process');
5+
const net = require('net');
6+
7+
if (process.argv[2] === 'child') {
8+
process.stdout.write('this should be ignored');
9+
process.stderr.write('this should not be ignored');
10+
11+
const pipe = new net.Socket({ fd: 4 });
12+
13+
process.on('disconnect', () => {
14+
pipe.unref();
15+
});
16+
17+
pipe.setEncoding('utf8');
18+
pipe.on('data', (data) => {
19+
process.send(data);
20+
});
21+
} else {
22+
assert.throws(() => {
23+
cp.fork(__filename, {stdio: ['pipe', 'pipe', 'pipe', 'pipe']});
24+
}, /Forked processes must have an IPC channel/);
25+
26+
let ipc = '';
27+
let stderr = '';
28+
const buf = Buffer.from('data to send via pipe');
29+
const child = cp.fork(__filename, ['child'], {
30+
stdio: [0, 'ignore', 'pipe', 'ipc', 'pipe']
31+
});
32+
33+
assert.strictEqual(child.stdout, null);
34+
35+
child.on('message', (msg) => {
36+
ipc += msg;
37+
38+
if (ipc === buf.toString()) {
39+
child.disconnect();
40+
}
41+
});
42+
43+
child.stderr.on('data', (chunk) => {
44+
stderr += chunk;
45+
});
46+
47+
child.on('exit', common.mustCall((code, signal) => {
48+
assert.strictEqual(code, 0);
49+
assert.strictEqual(signal, null);
50+
assert.strictEqual(stderr, 'this should not be ignored');
51+
}));
52+
53+
child.stdio[4].write(buf);
54+
}

0 commit comments

Comments
 (0)