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

process: group main thread execution preparation code #26000

Closed
wants to merge 3 commits into from
Closed
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
25 changes: 0 additions & 25 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,31 +176,6 @@ if (config.hasInspector) {
internalBinding('inspector').registerAsyncHook(enable, disable);
}

// If the process is spawned with env NODE_CHANNEL_FD, it's probably
// spawned by our child_process module, then initialize IPC.
// This attaches some internal event listeners and creates:
// process.send(), process.channel, process.connected,
// process.disconnect()
if (process.env.NODE_CHANNEL_FD) {
if (ownsProcessState) {
mainThreadSetup.setupChildProcessIpcChannel();
} else {
Object.defineProperty(process, 'channel', {
enumerable: false,
get: workerThreadSetup.unavailable('process.channel')
});

Object.defineProperty(process, 'connected', {
enumerable: false,
get: workerThreadSetup.unavailable('process.connected')
});

process.send = workerThreadSetup.unavailable('process.send()');
process.disconnect =
workerThreadSetup.unavailable('process.disconnect()');
}
}

const browserGlobals = !process._noBrowserGlobals;
if (browserGlobals) {
setupGlobalTimeouts();
Expand Down
42 changes: 37 additions & 5 deletions lib/internal/bootstrap/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@

const { getOptionValue } = require('internal/options');

function prepareMainThreadExecution() {
// If the process is spawned with env NODE_CHANNEL_FD, it's probably
// spawned by our child_process module, then initialize IPC.
// This attaches some internal event listeners and creates:
// process.send(), process.channel, process.connected,
// process.disconnect().
setupChildProcessIpcChannel();

// Load policy from disk and parse it.
initializePolicy();

// If this is a worker in cluster mode, start up the communication
// channel. This needs to be done before any user code gets executed
// (including preload modules).
initializeClusterIPC();

initializeDeprecations();
initializeESMLoader();
loadPreloadModules();
}

// In general deprecations are intialized wherever the APIs are implemented,
// this is used to deprecate APIs implemented in C++ where the deprecation
// utitlities are not easily accessible.
Expand Down Expand Up @@ -41,10 +62,22 @@ function initializeDeprecations() {
}
}

function setupChildProcessIpcChannel() {
if (process.env.NODE_CHANNEL_FD) {
const assert = require('internal/assert');

const fd = parseInt(process.env.NODE_CHANNEL_FD, 10);
assert(fd >= 0);

// Make sure it's not accidentally inherited by child processes.
delete process.env.NODE_CHANNEL_FD;

require('child_process')._forkChild(fd);
assert(process.send);
}
}

function initializeClusterIPC() {
// If this is a worker in cluster mode, start up the communication
// channel. This needs to be done before any user code gets executed
// (including preload modules).
if (process.argv[1] && process.env.NODE_UNIQUE_ID) {
const cluster = require('cluster');
cluster._setupWorker();
Expand Down Expand Up @@ -114,9 +147,8 @@ function loadPreloadModules() {
}

module.exports = {
prepareMainThreadExecution,
initializeDeprecations,
initializeClusterIPC,
initializePolicy,
initializeESMLoader,
loadPreloadModules
};
21 changes: 9 additions & 12 deletions lib/internal/main/check_syntax.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
// instead of actually running the file.

const {
initializeDeprecations,
initializeClusterIPC,
initializePolicy,
initializeESMLoader,
loadPreloadModules
prepareMainThreadExecution
} = require('internal/bootstrap/pre_execution');

const {
Expand All @@ -21,13 +17,6 @@ const {
stripShebang, stripBOM
} = require('internal/modules/cjs/helpers');

// TODO(joyeecheung): not every one of these are necessary
initializeDeprecations();
initializeClusterIPC();
initializePolicy();
initializeESMLoader();
loadPreloadModules();
markBootstrapComplete();

if (process.argv[1] && process.argv[1] !== '-') {
// Expand process.argv[1] into a full path.
Expand All @@ -39,8 +28,16 @@ if (process.argv[1] && process.argv[1] !== '-') {
const fs = require('fs');
const source = fs.readFileSync(filename, 'utf-8');

// TODO(joyeecheung): not every one of these are necessary
prepareMainThreadExecution();
markBootstrapComplete();

checkScriptSyntax(source, filename);
} else {
// TODO(joyeecheung): not every one of these are necessary
prepareMainThreadExecution();
markBootstrapComplete();

readStdin((code) => {
checkScriptSyntax(code, '[stdin]');
});
Expand Down
12 changes: 2 additions & 10 deletions lib/internal/main/eval_stdin.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,15 @@
// Stdin is not a TTY, we will read it and execute it.

const {
initializeDeprecations,
initializeClusterIPC,
initializePolicy,
initializeESMLoader,
loadPreloadModules
prepareMainThreadExecution
} = require('internal/bootstrap/pre_execution');

const {
evalScript,
readStdin
} = require('internal/process/execution');

initializeDeprecations();
initializeClusterIPC();
initializePolicy();
initializeESMLoader();
loadPreloadModules();
prepareMainThreadExecution();
markBootstrapComplete();

readStdin((code) => {
Expand Down
12 changes: 2 additions & 10 deletions lib/internal/main/eval_string.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,13 @@
// `--interactive`.

const {
initializeDeprecations,
initializeClusterIPC,
initializePolicy,
initializeESMLoader,
loadPreloadModules
prepareMainThreadExecution
} = require('internal/bootstrap/pre_execution');
const { evalScript } = require('internal/process/execution');
const { addBuiltinLibsToObject } = require('internal/modules/cjs/helpers');

const source = require('internal/options').getOptionValue('--eval');
initializeDeprecations();
initializeClusterIPC();
initializePolicy();
initializeESMLoader();
loadPreloadModules();
prepareMainThreadExecution();
addBuiltinLibsToObject(global);
markBootstrapComplete();
evalScript('[eval]', source, process._breakFirstLine);
12 changes: 2 additions & 10 deletions lib/internal/main/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,14 @@
// the main module is not specified and stdin is a TTY.

const {
initializeDeprecations,
initializeClusterIPC,
initializePolicy,
initializeESMLoader,
loadPreloadModules
prepareMainThreadExecution
} = require('internal/bootstrap/pre_execution');

const {
evalScript
} = require('internal/process/execution');

initializeDeprecations();
initializeClusterIPC();
initializePolicy();
initializeESMLoader();
loadPreloadModules();
prepareMainThreadExecution();

const cliRepl = require('internal/repl');
cliRepl.createInternalRepl(process.env, (err, repl) => {
Expand Down
14 changes: 3 additions & 11 deletions lib/internal/main/run_main_module.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
'use strict';

const {
initializeDeprecations,
initializeClusterIPC,
initializePolicy,
initializeESMLoader,
loadPreloadModules
prepareMainThreadExecution
} = require('internal/bootstrap/pre_execution');

initializeDeprecations();
initializeClusterIPC();
initializePolicy();
initializeESMLoader();
loadPreloadModules();

// Expand process.argv[1] into a full path.
const path = require('path');
process.argv[1] = path.resolve(process.argv[1]);

prepareMainThreadExecution();

const CJSModule = require('internal/modules/cjs/loader');

markBootstrapComplete();
Expand Down
22 changes: 20 additions & 2 deletions lib/internal/main/worker_thread.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

const {
initializeDeprecations,
initializeClusterIPC,
initializeESMLoader,
loadPreloadModules
} = require('internal/bootstrap/pre_execution');
Expand Down Expand Up @@ -42,6 +41,26 @@ debug(`[${threadId}] is setting up worker child environment`);
// Set up the message port and start listening
const port = getEnvMessagePort();

// If the main thread is spawned with env NODE_CHANNEL_FD, it's probably
// spawned by our child_process module. In the work threads, mark the
// related IPC properties as unavailable.
if (process.env.NODE_CHANNEL_FD) {
const workerThreadSetup = require('internal/process/worker_thread_only');
Object.defineProperty(process, 'channel', {
enumerable: false,
get: workerThreadSetup.unavailable('process.channel')
});

Object.defineProperty(process, 'connected', {
enumerable: false,
get: workerThreadSetup.unavailable('process.connected')
});

process.send = workerThreadSetup.unavailable('process.send()');
process.disconnect =
workerThreadSetup.unavailable('process.disconnect()');
}

port.on('message', (message) => {
if (message.type === LOAD_SCRIPT) {
const {
Expand All @@ -57,7 +76,6 @@ port.on('message', (message) => {
require('internal/process/policy').setup(manifestSrc, manifestURL);
}
initializeDeprecations();
initializeClusterIPC();
initializeESMLoader();
loadPreloadModules();
publicWorker.parentPort = publicPort;
Expand Down
14 changes: 0 additions & 14 deletions lib/internal/process/main_thread_only.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,22 +152,8 @@ function createSignalHandlers() {
};
}

function setupChildProcessIpcChannel() {
const assert = require('internal/assert');

const fd = parseInt(process.env.NODE_CHANNEL_FD, 10);
assert(fd >= 0);

// Make sure it's not accidentally inherited by child processes.
delete process.env.NODE_CHANNEL_FD;

require('child_process')._forkChild(fd);
assert(process.send);
}

module.exports = {
wrapProcessMethods,
createSignalHandlers,
setupChildProcessIpcChannel,
wrapPosixCredentialSetters
};
38 changes: 38 additions & 0 deletions test/parallel/test-preload-print-process-argv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';
Copy link
Member

Choose a reason for hiding this comment

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

Thank you @joyeecheung!


// This tests that process.argv is the same in the preloaded module
// and the user module.

const common = require('../common');

const tmpdir = require('../common/tmpdir');
const assert = require('assert');
const { spawnSync } = require('child_process');
const fs = require('fs');

if (!common.isMainThread) {
common.skip('Cannot chdir to the tmp directory in workers');
}

tmpdir.refresh();

process.chdir(tmpdir.path);
fs.writeFileSync(
'preload.js',
'console.log(JSON.stringify(process.argv));',
'utf-8');

fs.writeFileSync(
'main.js',
'console.log(JSON.stringify(process.argv));',
'utf-8');

const child = spawnSync(process.execPath, ['-r', './preload.js', 'main.js']);

if (child.status !== 0) {
console.log(child.stderr.toString());
assert.strictEqual(child.status, 0);
}

const lines = child.stdout.toString().trim().split('\n');
assert.deepStrictEqual(JSON.parse(lines[0]), JSON.parse(lines[1]));