process: split bootstrappers by threads that can run them
This patch split part of the bootstrappers into three files: - `lib/internal/process/main_thread_only.js`: contains bootstrappers that can only be run in the main thread, including - `setupStdio` for the main thread that sets up `process.stdin`, `process.stdout`, `process.error` that may interact with external resources, e.g. TTY/File/Pipe/TCP sockets - `setupProcessMethods` that setup methods changing process-global states, e.g. `process.chdir`, `process.umask`, `process.setuid` - `setupSignalHandlers` - `setupChildProcessIpcChannel` that setup `process.send` for child processes. - `lib/internal/process/worker_thread_only.js`: contains bootstrappers that can only be run in the worker threads, including - `setupStdio` for the worker thread that are streams to be manipulated or piped to the parent thread - `lib/internal/process/per_thread.js`: contains bootstrappers that can be run in all threads, including: - `setupAssert` for `process.assert` - `setupCpuUsage` for `process.cpuUsage` - `setupHrtime` for `process.hrtime` and `process.hrtime.bigint` - `setupMemoryUsage` for `process.memoryUsage` - `setupConfig` for `process.config` - `setupKillAndExit` for `process.kill` and `process.exit` - `setupRawDebug` for `process._rawDebug` - `setupUncaughtExceptionCapture` for `process.setUncaughtExceptionCaptureCallback` and `process.hasUncaughtExceptionCaptureCallback` Hopefully in the future we can sort more bootstrappers in `boostrap/node.js` into these three files and further group them into functions that can be run before creating the snapshot / after loading the snapshot. This patch also moves most of the `isMainThread` conditionals into the main bootstrapper instead of letting them scattered around special-casing different implementations. PR-URL: https://github.com/nodejs/node/pull/21378 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
This commit is contained in:
parent
420d8afe3d
commit
e43d91cdc1
@ -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) {
|
||||
|
@ -1,24 +1,35 @@
|
||||
'use strict';
|
||||
|
||||
// This file contains process bootstrappers that can only be
|
||||
// run in the main thread
|
||||
|
||||
const {
|
||||
ERR_INVALID_ARG_TYPE,
|
||||
ERR_UNKNOWN_CREDENTIAL
|
||||
} = require('internal/errors').codes;
|
||||
errnoException,
|
||||
codes: {
|
||||
ERR_INVALID_ARG_TYPE,
|
||||
ERR_UNKNOWN_CREDENTIAL
|
||||
}
|
||||
} = require('internal/errors');
|
||||
const {
|
||||
validateMode,
|
||||
validateUint32
|
||||
} = require('internal/validators');
|
||||
const {
|
||||
isMainThread
|
||||
} = require('internal/worker');
|
||||
|
||||
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) {
|
||||
// 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);
|
||||
@ -105,4 +116,64 @@ function setupPosixMethods(_initgroups, _setegid, _seteuid,
|
||||
}
|
||||
}
|
||||
|
||||
exports.setup = setupProcessMethods;
|
||||
// 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
|
||||
};
|
@ -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
|
||||
};
|
@ -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,
|
||||
|
24
lib/internal/process/worker_thread_only.js
Normal file
24
lib/internal/process/worker_thread_only.js
Normal file
@ -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
|
||||
};
|
5
node.gyp
5
node.gyp
@ -128,12 +128,13 @@
|
||||
'lib/internal/os.js',
|
||||
'lib/internal/priority_queue.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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user