child_process: add public API for IPC channel
This commit adds a public channel property to ChildProcess. The existing _channel property is aliased to the new property, with the intention of deprecating and removing it in the future. Fixes: https://github.com/nodejs/node/issues/9313 PR-URL: https://github.com/nodejs/node/pull/9322 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
This commit is contained in:
parent
f9814a2caf
commit
2dcb7f3826
@ -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
|
||||
@ -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
|
||||
|
@ -508,6 +508,16 @@ $ bash -c 'exec -a customArgv0 ./node'
|
||||
'customArgv0'
|
||||
```
|
||||
|
||||
## process.channel
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -465,7 +473,7 @@ function setupChannel(target, channel) {
|
||||
target.disconnect();
|
||||
channel.onread = nop;
|
||||
channel.close();
|
||||
target._channel = null;
|
||||
target.channel = null;
|
||||
maybeClose(target);
|
||||
}
|
||||
};
|
||||
@ -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;
|
||||
@ -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');
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
@ -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';
|
||||
@ -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;
|
||||
|
@ -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
|
||||
});
|
||||
|
@ -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();
|
||||
}));
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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) => {
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user