diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 61146a32aad010..ab1695125df6bc 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -44,33 +44,57 @@ setupGlobalVariables(); - const _process = NativeModule.require('internal/process'); - _process.setupConfig(NativeModule._source); - _process.setupSignalHandlers(); - _process.setupUncaughtExceptionCapture(exceptionHandlerState, - _shouldAbortOnUncaughtToggle); + // Bootstrappers for all threads, including worker threads and main thread + const perThreadSetup = NativeModule.require('internal/process/per_thread'); + // Bootstrappers for the main thread only + let mainThreadSetup; + // Bootstrappers for the worker threads only + let workerThreadSetup; + if (isMainThread) { + mainThreadSetup = NativeModule.require( + 'internal/process/main_thread_only' + ); + } else { + workerThreadSetup = NativeModule.require( + 'internal/process/worker_thread_only' + ); + } + + perThreadSetup.setupAssert(); + perThreadSetup.setupConfig(NativeModule._source); + + if (isMainThread) { + mainThreadSetup.setupSignalHandlers(); + } + + perThreadSetup.setupUncaughtExceptionCapture(exceptionHandlerState, + _shouldAbortOnUncaughtToggle); + NativeModule.require('internal/process/warning').setup(); NativeModule.require('internal/process/next_tick').setup(_setupNextTick, _setupPromises); - NativeModule.require('internal/process/stdio').setup(); - NativeModule.require('internal/process/methods').setup(_chdir, - _umask, - _initgroups, - _setegid, - _seteuid, - _setgid, - _setuid, - _setgroups); + + if (isMainThread) { + mainThreadSetup.setupStdio(); + mainThreadSetup.setupProcessMethods( + _chdir, _umask, _initgroups, _setegid, _seteuid, + _setgid, _setuid, _setgroups + ); + } else { + workerThreadSetup.setupStdio(); + } const perf = process.binding('performance'); const { NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE, } = perf.constants; - _process.setup_hrtime(_hrtime, _hrtimeBigInt); - _process.setup_cpuUsage(_cpuUsage); - _process.setupMemoryUsage(_memoryUsage); - _process.setupKillAndExit(); + perThreadSetup.setupRawDebug(_rawDebug); + perThreadSetup.setupHrtime(_hrtime, _hrtimeBigInt); + perThreadSetup.setupCpuUsage(_cpuUsage); + perThreadSetup.setupMemoryUsage(_memoryUsage); + perThreadSetup.setupKillAndExit(); + if (global.__coverage__) NativeModule.require('internal/process/write-coverage').setup(); @@ -90,10 +114,9 @@ NativeModule.require('internal/inspector_async_hook').setup(); } - if (isMainThread) - _process.setupChannel(); - - _process.setupRawDebug(_rawDebug); + if (isMainThread) { + mainThreadSetup.setupChildProcessIpcChannel(); + } const browserGlobals = !process._noBrowserGlobals; if (browserGlobals) { diff --git a/lib/internal/process/main_thread_only.js b/lib/internal/process/main_thread_only.js new file mode 100644 index 00000000000000..814cca266d6675 --- /dev/null +++ b/lib/internal/process/main_thread_only.js @@ -0,0 +1,127 @@ +'use strict'; + +// This file contains process bootstrappers that can only be +// run in the main thread + +const { + errnoException +} = require('internal/errors'); + +const { + setupProcessStdio, + getMainThreadStdio +} = require('internal/process/stdio'); + +const assert = require('assert').strict; + +function setupStdio() { + setupProcessStdio(getMainThreadStdio()); +} + +// Non-POSIX platforms like Windows don't have certain methods. +// Workers also lack these methods since they change process-global state. +function setupProcessMethods(_chdir, _umask, _initgroups, _setegid, + _seteuid, _setgid, _setuid, _setgroups) { + if (_setgid !== undefined) { + setupPosixMethods(_initgroups, _setegid, _seteuid, + _setgid, _setuid, _setgroups); + } + + process.chdir = function chdir(...args) { + return _chdir(...args); + }; + + process.umask = function umask(...args) { + return _umask(...args); + }; +} + +function setupPosixMethods(_initgroups, _setegid, _seteuid, + _setgid, _setuid, _setgroups) { + + process.initgroups = function initgroups(...args) { + return _initgroups(...args); + }; + + process.setegid = function setegid(...args) { + return _setegid(...args); + }; + + process.seteuid = function seteuid(...args) { + return _seteuid(...args); + }; + + process.setgid = function setgid(...args) { + return _setgid(...args); + }; + + process.setuid = function setuid(...args) { + return _setuid(...args); + }; + + process.setgroups = function setgroups(...args) { + return _setgroups(...args); + }; +} + +// Worker threads don't receive signals. +function setupSignalHandlers() { + const constants = process.binding('constants').os.signals; + const signalWraps = Object.create(null); + let Signal; + + function isSignal(event) { + return typeof event === 'string' && constants[event] !== undefined; + } + + // Detect presence of a listener for the special signal types + process.on('newListener', function(type) { + if (isSignal(type) && signalWraps[type] === undefined) { + if (Signal === undefined) + Signal = process.binding('signal_wrap').Signal; + const wrap = new Signal(); + + wrap.unref(); + + wrap.onsignal = process.emit.bind(process, type, type); + + const signum = constants[type]; + const err = wrap.start(signum); + if (err) { + wrap.close(); + throw errnoException(err, 'uv_signal_start'); + } + + signalWraps[type] = wrap; + } + }); + + process.on('removeListener', function(type) { + if (signalWraps[type] !== undefined && this.listenerCount(type) === 0) { + signalWraps[type].close(); + delete signalWraps[type]; + } + }); +} + +function setupChildProcessIpcChannel() { + // If we were spawned with env NODE_CHANNEL_FD then load that up and + // start parsing data from that stream. + if (process.env.NODE_CHANNEL_FD) { + 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 = { + setupStdio, + setupProcessMethods, + setupSignalHandlers, + setupChildProcessIpcChannel +}; diff --git a/lib/internal/process/methods.js b/lib/internal/process/methods.js deleted file mode 100644 index 38ba5f84b5a30a..00000000000000 --- a/lib/internal/process/methods.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict'; - -const { - isMainThread -} = require('internal/worker'); - -function setupProcessMethods(_chdir, _umask, _initgroups, _setegid, - _seteuid, _setgid, _setuid, _setgroups) { - // Non-POSIX platforms like Windows don't have certain methods. - // Workers also lack these methods since they change process-global state. - if (!isMainThread) - return; - - if (_setgid !== undefined) { - setupPosixMethods(_initgroups, _setegid, _seteuid, - _setgid, _setuid, _setgroups); - } - - process.chdir = function chdir(...args) { - return _chdir(...args); - }; - - process.umask = function umask(...args) { - return _umask(...args); - }; -} - -function setupPosixMethods(_initgroups, _setegid, _seteuid, - _setgid, _setuid, _setgroups) { - - process.initgroups = function initgroups(...args) { - return _initgroups(...args); - }; - - process.setegid = function setegid(...args) { - return _setegid(...args); - }; - - process.seteuid = function seteuid(...args) { - return _seteuid(...args); - }; - - process.setgid = function setgid(...args) { - return _setgid(...args); - }; - - process.setuid = function setuid(...args) { - return _setuid(...args); - }; - - process.setgroups = function setgroups(...args) { - return _setgroups(...args); - }; -} - -exports.setup = setupProcessMethods; diff --git a/lib/internal/process.js b/lib/internal/process/per_thread.js similarity index 75% rename from lib/internal/process.js rename to lib/internal/process/per_thread.js index 098edaeaaff183..fbf60bac6e9fff 100644 --- a/lib/internal/process.js +++ b/lib/internal/process/per_thread.js @@ -1,5 +1,9 @@ 'use strict'; +// This files contains process bootstrappers that can be +// run when setting up each thread, including the main +// thread and the worker threads. + const { errnoException, codes: { @@ -14,19 +18,19 @@ const { } = require('internal/errors'); const util = require('util'); const constants = process.binding('constants').os.signals; -const assert = require('assert').strict; const { deprecate } = require('internal/util'); -const { isMainThread } = require('internal/worker'); -process.assert = deprecate( - function(x, msg) { - if (!x) throw new ERR_ASSERTION(msg || 'assertion error'); - }, - 'process.assert() is deprecated. Please use the `assert` module instead.', - 'DEP0100'); +function setupAssert() { + process.assert = deprecate( + function(x, msg) { + if (!x) throw new ERR_ASSERTION(msg || 'assertion error'); + }, + 'process.assert() is deprecated. Please use the `assert` module instead.', + 'DEP0100'); +} // Set up the process.cpuUsage() function. -function setup_cpuUsage(_cpuUsage) { +function setupCpuUsage(_cpuUsage) { // Create the argument array that will be passed to the native function. const cpuValues = new Float64Array(2); @@ -90,7 +94,7 @@ function setup_cpuUsage(_cpuUsage) { // The 3 entries filled in by the original process.hrtime contains // the upper/lower 32 bits of the second part of the value, // and the remaining nanoseconds of the value. -function setup_hrtime(_hrtime, _hrtimeBigInt) { +function setupHrtime(_hrtime, _hrtimeBigInt) { const hrValues = new Uint32Array(3); process.hrtime = function hrtime(time) { @@ -193,67 +197,6 @@ function setupKillAndExit() { }; } - -function setupSignalHandlers() { - if (!isMainThread) { - // Worker threads don't receive signals. - return; - } - - const signalWraps = Object.create(null); - let Signal; - - function isSignal(event) { - return typeof event === 'string' && constants[event] !== undefined; - } - - // Detect presence of a listener for the special signal types - process.on('newListener', function(type) { - if (isSignal(type) && signalWraps[type] === undefined) { - if (Signal === undefined) - Signal = process.binding('signal_wrap').Signal; - const wrap = new Signal(); - - wrap.unref(); - - wrap.onsignal = process.emit.bind(process, type, type); - - const signum = constants[type]; - const err = wrap.start(signum); - if (err) { - wrap.close(); - throw errnoException(err, 'uv_signal_start'); - } - - signalWraps[type] = wrap; - } - }); - - process.on('removeListener', function(type) { - if (signalWraps[type] !== undefined && this.listenerCount(type) === 0) { - signalWraps[type].close(); - delete signalWraps[type]; - } - }); -} - - -function setupChannel() { - // If we were spawned with env NODE_CHANNEL_FD then load that up and - // start parsing data from that stream. - if (process.env.NODE_CHANNEL_FD) { - 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 setupRawDebug(_rawDebug) { process._rawDebug = function() { _rawDebug(util.format.apply(null, arguments)); @@ -288,13 +231,12 @@ function setupUncaughtExceptionCapture(exceptionHandlerState, } module.exports = { - setup_cpuUsage, - setup_hrtime, + setupAssert, + setupCpuUsage, + setupHrtime, setupMemoryUsage, setupConfig, setupKillAndExit, - setupSignalHandlers, - setupChannel, setupRawDebug, setupUncaughtExceptionCapture }; diff --git a/lib/internal/process/stdio.js b/lib/internal/process/stdio.js index f4a07cd06d09d9..e4207a1aa768bd 100644 --- a/lib/internal/process/stdio.js +++ b/lib/internal/process/stdio.js @@ -6,21 +6,17 @@ const { ERR_UNKNOWN_STDIN_TYPE, ERR_UNKNOWN_STREAM_TYPE } = require('internal/errors').codes; -const { - isMainThread, - workerStdio -} = require('internal/worker'); -exports.setup = setupStdio; +exports.setupProcessStdio = setupProcessStdio; +exports.getMainThreadStdio = getMainThreadStdio; -function setupStdio() { +function getMainThreadStdio() { var stdin; var stdout; var stderr; function getStdout() { if (stdout) return stdout; - if (!isMainThread) return workerStdio.stdout; stdout = createWritableStdioStream(1); stdout.destroySoon = stdout.destroy; stdout._destroy = function(er, cb) { @@ -36,7 +32,6 @@ function setupStdio() { function getStderr() { if (stderr) return stderr; - if (!isMainThread) return workerStdio.stderr; stderr = createWritableStdioStream(2); stderr.destroySoon = stderr.destroy; stderr._destroy = function(er, cb) { @@ -52,8 +47,6 @@ function setupStdio() { function getStdin() { if (stdin) return stdin; - if (!isMainThread) return workerStdio.stdin; - const tty_wrap = process.binding('tty_wrap'); const fd = 0; @@ -136,6 +129,14 @@ function setupStdio() { return stdin; } + return { + getStdout, + getStderr, + getStdin + }; +} + +function setupProcessStdio({ getStdout, getStdin, getStderr }) { Object.defineProperty(process, 'stdout', { configurable: true, enumerable: true, diff --git a/lib/internal/process/worker_thread_only.js b/lib/internal/process/worker_thread_only.js new file mode 100644 index 00000000000000..834ba6078fca44 --- /dev/null +++ b/lib/internal/process/worker_thread_only.js @@ -0,0 +1,24 @@ +'use strict'; + +// This file contains process bootstrappers that can only be +// run in the worker thread. + +const { + setupProcessStdio +} = require('internal/process/stdio'); + +const { + workerStdio +} = require('internal/worker'); + +function setupStdio() { + setupProcessStdio({ + getStdout: () => workerStdio.stdout, + getStderr: () => workerStdio.stderr, + getStdin: () => workerStdio.stdin + }); +} + +module.exports = { + setupStdio +}; diff --git a/node.gyp b/node.gyp index 04784715c34f86..56315baf7006b3 100644 --- a/node.gyp +++ b/node.gyp @@ -133,12 +133,13 @@ 'lib/internal/net.js', 'lib/internal/os.js', 'lib/internal/process/esm_loader.js', - 'lib/internal/process/methods.js', + 'lib/internal/process/main_thread_only.js', 'lib/internal/process/next_tick.js', + 'lib/internal/process/per_thread.js', 'lib/internal/process/promises.js', 'lib/internal/process/stdio.js', 'lib/internal/process/warning.js', - 'lib/internal/process.js', + 'lib/internal/process/worker_thread_only.js', 'lib/internal/querystring.js', 'lib/internal/process/write-coverage.js', 'lib/internal/readline.js',