Skip to content

Commit 581390c

Browse files
joyeecheungtargos
authored andcommitted
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: #21378 Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Jeremiah Senkpiel <[email protected]> Backport-PR-URL: #21866 Reviewed-By: Michaël Zasso <[email protected]>
1 parent eef975e commit 581390c

File tree

7 files changed

+227
-165
lines changed

7 files changed

+227
-165
lines changed

lib/internal/bootstrap/node.js

+45-22
Original file line numberDiff line numberDiff line change
@@ -44,33 +44,57 @@
4444

4545
setupGlobalVariables();
4646

47-
const _process = NativeModule.require('internal/process');
48-
_process.setupConfig(NativeModule._source);
49-
_process.setupSignalHandlers();
50-
_process.setupUncaughtExceptionCapture(exceptionHandlerState,
51-
_shouldAbortOnUncaughtToggle);
47+
// Bootstrappers for all threads, including worker threads and main thread
48+
const perThreadSetup = NativeModule.require('internal/process/per_thread');
49+
// Bootstrappers for the main thread only
50+
let mainThreadSetup;
51+
// Bootstrappers for the worker threads only
52+
let workerThreadSetup;
53+
if (isMainThread) {
54+
mainThreadSetup = NativeModule.require(
55+
'internal/process/main_thread_only'
56+
);
57+
} else {
58+
workerThreadSetup = NativeModule.require(
59+
'internal/process/worker_thread_only'
60+
);
61+
}
62+
63+
perThreadSetup.setupAssert();
64+
perThreadSetup.setupConfig(NativeModule._source);
65+
66+
if (isMainThread) {
67+
mainThreadSetup.setupSignalHandlers();
68+
}
69+
70+
perThreadSetup.setupUncaughtExceptionCapture(exceptionHandlerState,
71+
_shouldAbortOnUncaughtToggle);
72+
5273
NativeModule.require('internal/process/warning').setup();
5374
NativeModule.require('internal/process/next_tick').setup(_setupNextTick,
5475
_setupPromises);
55-
NativeModule.require('internal/process/stdio').setup();
56-
NativeModule.require('internal/process/methods').setup(_chdir,
57-
_umask,
58-
_initgroups,
59-
_setegid,
60-
_seteuid,
61-
_setgid,
62-
_setuid,
63-
_setgroups);
76+
77+
if (isMainThread) {
78+
mainThreadSetup.setupStdio();
79+
mainThreadSetup.setupProcessMethods(
80+
_chdir, _umask, _initgroups, _setegid, _seteuid,
81+
_setgid, _setuid, _setgroups
82+
);
83+
} else {
84+
workerThreadSetup.setupStdio();
85+
}
6486

6587
const perf = process.binding('performance');
6688
const {
6789
NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE,
6890
} = perf.constants;
6991

70-
_process.setup_hrtime(_hrtime, _hrtimeBigInt);
71-
_process.setup_cpuUsage(_cpuUsage);
72-
_process.setupMemoryUsage(_memoryUsage);
73-
_process.setupKillAndExit();
92+
perThreadSetup.setupRawDebug(_rawDebug);
93+
perThreadSetup.setupHrtime(_hrtime, _hrtimeBigInt);
94+
perThreadSetup.setupCpuUsage(_cpuUsage);
95+
perThreadSetup.setupMemoryUsage(_memoryUsage);
96+
perThreadSetup.setupKillAndExit();
97+
7498
if (global.__coverage__)
7599
NativeModule.require('internal/process/write-coverage').setup();
76100

@@ -90,10 +114,9 @@
90114
NativeModule.require('internal/inspector_async_hook').setup();
91115
}
92116

93-
if (isMainThread)
94-
_process.setupChannel();
95-
96-
_process.setupRawDebug(_rawDebug);
117+
if (isMainThread) {
118+
mainThreadSetup.setupChildProcessIpcChannel();
119+
}
97120

98121
const browserGlobals = !process._noBrowserGlobals;
99122
if (browserGlobals) {
+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
'use strict';
2+
3+
// This file contains process bootstrappers that can only be
4+
// run in the main thread
5+
6+
const {
7+
errnoException
8+
} = require('internal/errors');
9+
10+
const {
11+
setupProcessStdio,
12+
getMainThreadStdio
13+
} = require('internal/process/stdio');
14+
15+
const assert = require('assert').strict;
16+
17+
function setupStdio() {
18+
setupProcessStdio(getMainThreadStdio());
19+
}
20+
21+
// Non-POSIX platforms like Windows don't have certain methods.
22+
// Workers also lack these methods since they change process-global state.
23+
function setupProcessMethods(_chdir, _umask, _initgroups, _setegid,
24+
_seteuid, _setgid, _setuid, _setgroups) {
25+
if (_setgid !== undefined) {
26+
setupPosixMethods(_initgroups, _setegid, _seteuid,
27+
_setgid, _setuid, _setgroups);
28+
}
29+
30+
process.chdir = function chdir(...args) {
31+
return _chdir(...args);
32+
};
33+
34+
process.umask = function umask(...args) {
35+
return _umask(...args);
36+
};
37+
}
38+
39+
function setupPosixMethods(_initgroups, _setegid, _seteuid,
40+
_setgid, _setuid, _setgroups) {
41+
42+
process.initgroups = function initgroups(...args) {
43+
return _initgroups(...args);
44+
};
45+
46+
process.setegid = function setegid(...args) {
47+
return _setegid(...args);
48+
};
49+
50+
process.seteuid = function seteuid(...args) {
51+
return _seteuid(...args);
52+
};
53+
54+
process.setgid = function setgid(...args) {
55+
return _setgid(...args);
56+
};
57+
58+
process.setuid = function setuid(...args) {
59+
return _setuid(...args);
60+
};
61+
62+
process.setgroups = function setgroups(...args) {
63+
return _setgroups(...args);
64+
};
65+
}
66+
67+
// Worker threads don't receive signals.
68+
function setupSignalHandlers() {
69+
const constants = process.binding('constants').os.signals;
70+
const signalWraps = Object.create(null);
71+
let Signal;
72+
73+
function isSignal(event) {
74+
return typeof event === 'string' && constants[event] !== undefined;
75+
}
76+
77+
// Detect presence of a listener for the special signal types
78+
process.on('newListener', function(type) {
79+
if (isSignal(type) && signalWraps[type] === undefined) {
80+
if (Signal === undefined)
81+
Signal = process.binding('signal_wrap').Signal;
82+
const wrap = new Signal();
83+
84+
wrap.unref();
85+
86+
wrap.onsignal = process.emit.bind(process, type, type);
87+
88+
const signum = constants[type];
89+
const err = wrap.start(signum);
90+
if (err) {
91+
wrap.close();
92+
throw errnoException(err, 'uv_signal_start');
93+
}
94+
95+
signalWraps[type] = wrap;
96+
}
97+
});
98+
99+
process.on('removeListener', function(type) {
100+
if (signalWraps[type] !== undefined && this.listenerCount(type) === 0) {
101+
signalWraps[type].close();
102+
delete signalWraps[type];
103+
}
104+
});
105+
}
106+
107+
function setupChildProcessIpcChannel() {
108+
// If we were spawned with env NODE_CHANNEL_FD then load that up and
109+
// start parsing data from that stream.
110+
if (process.env.NODE_CHANNEL_FD) {
111+
const fd = parseInt(process.env.NODE_CHANNEL_FD, 10);
112+
assert(fd >= 0);
113+
114+
// Make sure it's not accidentally inherited by child processes.
115+
delete process.env.NODE_CHANNEL_FD;
116+
117+
require('child_process')._forkChild(fd);
118+
assert(process.send);
119+
}
120+
}
121+
122+
module.exports = {
123+
setupStdio,
124+
setupProcessMethods,
125+
setupSignalHandlers,
126+
setupChildProcessIpcChannel
127+
};

lib/internal/process/methods.js

-56
This file was deleted.

0 commit comments

Comments
 (0)