Skip to content

Commit 5a91a06

Browse files
authored
fix: implement child_process IPC (#21490)
This PR implements the Node child_process IPC functionality in Deno on Unix systems. For `fd > 2` a duplex unix pipe is set up between the parent and child processes. Currently implements data passing via the channel in the JSON serialization format.
1 parent bbf8f69 commit 5a91a06

22 files changed

+1158
-32
lines changed

Diff for: Cargo.lock

+145
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: cli/args/mod.rs

+11
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,17 @@ impl CliOptions {
939939
.map(Some)
940940
}
941941

942+
pub fn node_ipc_fd(&self) -> Option<i32> {
943+
let maybe_node_channel_fd = std::env::var("DENO_CHANNEL_FD").ok();
944+
if let Some(node_channel_fd) = maybe_node_channel_fd {
945+
// Remove so that child processes don't inherit this environment variable.
946+
std::env::remove_var("DENO_CHANNEL_FD");
947+
node_channel_fd.parse::<i32>().ok()
948+
} else {
949+
None
950+
}
951+
}
952+
942953
pub fn resolve_main_module(&self) -> Result<ModuleSpecifier, AnyError> {
943954
match &self.flags.subcommand {
944955
DenoSubcommand::Bundle(bundle_flags) => {

Diff for: cli/factory.rs

+1
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ impl CliFactory {
672672
self.maybe_lockfile().clone(),
673673
self.feature_checker().clone(),
674674
self.create_cli_main_worker_options()?,
675+
self.options.node_ipc_fd(),
675676
))
676677
}
677678

Diff for: cli/standalone/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ pub async fn run(
530530
unstable: metadata.unstable,
531531
maybe_root_package_json_deps: package_json_deps_provider.deps().cloned(),
532532
},
533+
None,
533534
);
534535

535536
v8_set_flags(construct_v8_flags(&[], &metadata.v8_flags, vec![]));

Diff for: cli/tests/node_compat/config.jsonc

+7-11
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
"test-child-process-execfile.js",
3939
"test-child-process-execsync-maxbuf.js",
4040
"test-child-process-exit-code.js",
41+
// TODO(littledivy): windows ipc streams not yet implemented
42+
"test-child-process-fork-ref.js",
43+
"test-child-process-fork-ref2.js",
44+
"test-child-process-ipc-next-tick.js",
4145
"test-child-process-ipc.js",
4246
"test-child-process-spawnsync-env.js",
4347
"test-child-process-stdio-inherit.js",
@@ -109,9 +113,7 @@
109113
"test-zlib-zero-windowBits.js"
110114
],
111115
"pummel": [],
112-
"sequential": [
113-
"test-child-process-exit.js"
114-
]
116+
"sequential": ["test-child-process-exit.js"]
115117
},
116118
"tests": {
117119
"common": [
@@ -138,11 +140,7 @@
138140
"print-chars.js",
139141
"x.txt"
140142
],
141-
"fixtures/keys": [
142-
"agent1-cert.pem",
143-
"agent1-key.pem",
144-
"ca1-cert.pem"
145-
],
143+
"fixtures/keys": ["agent1-cert.pem", "agent1-key.pem", "ca1-cert.pem"],
146144
"internet": [
147145
"test-dns-any.js",
148146
"test-dns-idna2008.js",
@@ -695,9 +693,7 @@
695693
"test-tty-stdout-end.js"
696694
],
697695
"pummel": [],
698-
"sequential": [
699-
"test-child-process-exit.js"
700-
]
696+
"sequential": ["test-child-process-exit.js"]
701697
},
702698
"windowsIgnore": {
703699
"parallel": [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// deno-fmt-ignore-file
2+
// deno-lint-ignore-file
3+
4+
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
5+
// Taken from Node 18.12.1
6+
// This file is automatically generated by `tools/node_compat/setup.ts`. Do not modify this file manually.
7+
8+
// Copyright Joyent, Inc. and other Node contributors.
9+
//
10+
// Permission is hereby granted, free of charge, to any person obtaining a
11+
// copy of this software and associated documentation files (the
12+
// "Software"), to deal in the Software without restriction, including
13+
// without limitation the rights to use, copy, modify, merge, publish,
14+
// distribute, sublicense, and/or sell copies of the Software, and to permit
15+
// persons to whom the Software is furnished to do so, subject to the
16+
// following conditions:
17+
//
18+
// The above copyright notice and this permission notice shall be included
19+
// in all copies or substantial portions of the Software.
20+
//
21+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
24+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
25+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
26+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
27+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
28+
29+
'use strict';
30+
31+
// Ignore on Windows.
32+
if (process.platform === 'win32') {
33+
process.exit(0);
34+
}
35+
36+
require('../common');
37+
const assert = require('assert');
38+
const fork = require('child_process').fork;
39+
40+
if (process.argv[2] === 'child') {
41+
process.send('1');
42+
43+
// Check that child don't instantly die
44+
setTimeout(function() {
45+
process.send('2');
46+
}, 200);
47+
48+
process.on('disconnect', function() {
49+
process.stdout.write('3');
50+
});
51+
52+
} else {
53+
const child = fork(__filename, ['child'], { silent: true });
54+
55+
const ipc = [];
56+
let stdout = '';
57+
58+
child.on('message', function(msg) {
59+
ipc.push(msg);
60+
61+
if (msg === '2') child.disconnect();
62+
});
63+
64+
child.stdout.on('data', function(chunk) {
65+
stdout += chunk;
66+
});
67+
68+
child.once('exit', function() {
69+
assert.deepStrictEqual(ipc, ['1', '2']);
70+
assert.strictEqual(stdout, '3');
71+
});
72+
}

0 commit comments

Comments
 (0)