Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

child_process: add public API for IPC channel #9322

Merged
merged 1 commit into from
Nov 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/api/child_process.md
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,16 @@ added: v0.5.9
The `'message'` event is triggered when a child process uses [`process.send()`][]
to send messages.

### child.channel
<!-- YAML
added: REPLACEME
-->

* {Object} A pipe representing the IPC channel to the child process.

The `child.channel` property is a reference to the child's IPC channel. If no
IPC channel currently exists, this property is `undefined`.

### child.connected
<!-- YAML
added: v0.7.2
Expand Down Expand Up @@ -1145,6 +1155,7 @@ console.log('中文测试');
[`'error'`]: #child_process_event_error
[`'exit'`]: #child_process_event_exit
[`'message'`]: #child_process_event_message
[`child.channel`]: #child_process_child_channel
[`child.connected`]: #child_process_child_connected
[`child.disconnect()`]: #child_process_child_disconnect
[`child.kill()`]: #child_process_child_kill_signal
Expand Down
10 changes: 10 additions & 0 deletions doc/api/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,16 @@ $ bash -c 'exec -a customArgv0 ./node'
'customArgv0'
```

## process.channel
<!-- YAML
added: REPLACEME
-->

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • {Object} A pipe representing the IPC channel to the child process.

Not needed here, the style of docs is different in child_process and process?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I noticed that the style of the docs in this file are slightly different. I think a good first contribution would be to bring additional consistency to this file. For example, see https://nodejs.org/api/process.html#process_process_connected vs. https://nodejs.org/api/child_process.html#child_process_child_connected.

If the Node.js process was spawned with an IPC channel (see the
[Child Process][] documentation), the `process.channel`
property is a reference to the IPC channel. If no IPC channel exists, this
property is `undefined`.

## process.chdir(directory)
<!-- YAML
added: v0.1.17
Expand Down
32 changes: 20 additions & 12 deletions lib/internal/child_process.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const handleConversion = {
// the slave should keep track of the socket
message.key = socket.server._connectionKey;

var firstTime = !this._channel.sockets.send[message.key];
var firstTime = !this.channel.sockets.send[message.key];
var socketList = getSocketList('send', this, message.key);

// the server should no longer expose a .connection property
Expand Down Expand Up @@ -409,7 +409,15 @@ ChildProcess.prototype.unref = function() {


function setupChannel(target, channel) {
target._channel = channel;
target.channel = channel;

// _channel can be deprecated in version 8
Object.defineProperty(target, '_channel', {
get() { return target.channel; },
set(val) { target.channel = val; },
enumerable: true
});

target._handleQueue = null;
target._pendingHandle = null;

Expand Down Expand Up @@ -465,7 +473,7 @@ function setupChannel(target, channel) {
target.disconnect();
channel.onread = nop;
channel.close();
target._channel = null;
target.channel = null;
maybeClose(target);
}
};
Expand All @@ -491,7 +499,7 @@ function setupChannel(target, channel) {
});

// Process a pending disconnect (if any).
if (!target.connected && target._channel && !target._handleQueue)
if (!target.connected && target.channel && !target._handleQueue)
target._disconnect();

return;
Expand Down Expand Up @@ -547,7 +555,7 @@ function setupChannel(target, channel) {
};

target._send = function(message, handle, options, callback) {
assert(this.connected || this._channel);
assert(this.connected || this.channel);

if (message === undefined)
throw new TypeError('"message" argument cannot be undefined');
Expand Down Expand Up @@ -667,11 +675,11 @@ function setupChannel(target, channel) {
// connected will be set to false immediately when a disconnect() is
// requested, even though the channel might still be alive internally to
// process queued messages. The three states are distinguished as follows:
// - disconnect() never requested: _channel is not null and connected
// - disconnect() never requested: channel is not null and connected
// is true
// - disconnect() requested, messages in the queue: _channel is not null
// - disconnect() requested, messages in the queue: channel is not null
// and connected is false
// - disconnect() requested, channel actually disconnected: _channel is
// - disconnect() requested, channel actually disconnected: channel is
// null and connected is false
target.connected = true;

Expand All @@ -692,10 +700,10 @@ function setupChannel(target, channel) {
};

target._disconnect = function() {
assert(this._channel);
assert(this.channel);

// This marks the fact that the channel is actually disconnected.
this._channel = null;
this.channel = null;

if (this._pendingHandle) {
this._pendingHandle.close();
Expand Down Expand Up @@ -729,7 +737,7 @@ function setupChannel(target, channel) {

const INTERNAL_PREFIX = 'NODE_';
function handleMessage(target, message, handle) {
if (!target._channel)
if (!target.channel)
return;

var eventName = 'message';
Expand Down Expand Up @@ -860,7 +868,7 @@ function _validateStdio(stdio, sync) {


function getSocketList(type, slave, key) {
var sockets = slave._channel.sockets[type];
var sockets = slave.channel.sockets[type];
var socketList = sockets[key];
if (!socketList) {
var Construct = type === 'send' ? SocketListSend : SocketListReceive;
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/process/stdio.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ function setupStdio() {
// sitting on fd=0, in such case the pipe for this fd is already
// present and creating a new one will lead to the assertion failure
// in libuv.
if (process._channel && process._channel.fd === fd) {
if (process.channel && process.channel.fd === fd) {
stdin = new net.Socket({
handle: process._channel,
handle: process.channel,
readable: true,
writable: false
});
Expand Down
4 changes: 2 additions & 2 deletions test/parallel/test-child-process-fork-regr-gh-2847.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ var server = net.createServer(function(s) {
}

worker.process.once('close', common.mustCall(function() {
// Otherwise the crash on `_channel.fd` access may happen
assert.strictEqual(worker.process._channel, null);
// Otherwise the crash on `channel.fd` access may happen
assert.strictEqual(worker.process.channel, null);
server.close();
}));

Expand Down
2 changes: 2 additions & 0 deletions test/parallel/test-child-process-fork.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ var fork = require('child_process').fork;
var args = ['foo', 'bar'];

var n = fork(common.fixturesDir + '/child-process-spawn-node.js', args);

assert.strictEqual(n.channel, n._channel);
assert.deepStrictEqual(args, ['foo', 'bar']);

n.on('message', function(m) {
Expand Down
4 changes: 2 additions & 2 deletions test/parallel/test-child-process-recv-handle.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ function master() {
}

function worker() {
process._channel.readStop(); // Make messages batch up.
process.channel.readStop(); // Make messages batch up.
process.stdout.ref();
process.stdout.write('ok\r\n');
process.stdin.once('data', common.mustCall((data) => {
assert.strictEqual(data.toString(), 'ok\r\n');
process._channel.readStart();
process.channel.readStart();
}));
let n = 0;
process.on('message', common.mustCall((msg, handle) => {
Expand Down
4 changes: 2 additions & 2 deletions test/parallel/test-child-process-silent.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ if (process.argv[2] === 'pipe') {
const child = childProcess.fork(process.argv[1], ['pipe'], {silent: true});

// Allow child process to self terminate
child._channel.close();
child._channel = null;
child.channel.close();
child.channel = null;

child.on('exit', function() {
process.exit(0);
Expand Down