Skip to content

Commit 37ffa8c

Browse files
joyeecheungBridgeAR
authored andcommitted
bootstrap: use different scripts to setup different configurations
This patch splits the handling of `isMainThread` and `ownsProcessState` from conditionals in `lib/internal/bootstrap/node.js` into different scripts under `lib/internal/bootstrap/switches/`, and call them accordingly from C++ after `node.js` is run. This: - Creates a common denominator of the main thread and the worker thread bootstrap that can be snapshotted and shared by both. - Makes it possible to override the configurations on-the-fly. PR-URL: #30862 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent 93cf123 commit 37ffa8c

14 files changed

+565
-545
lines changed

lib/internal/bootstrap/node.js

+18-99
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
// This file is invoked by `node::RunBootstrapping()` in `src/node.cc`, and is
44
// responsible for setting up node.js core before executing main scripts
55
// under `lib/internal/main/`.
6-
// This file is currently run to bootstrap both the main thread and the worker
7-
// threads. Some setups are conditional, controlled with isMainThread and
8-
// ownsProcessState.
6+
//
97
// This file is expected not to perform any asynchronous operations itself
108
// when being executed - those should be done in either
119
// `lib/internal/bootstrap/pre_execution.js` or in main scripts. The majority
@@ -22,16 +20,21 @@
2220
// module loaders, including `process.binding()`, `process._linkedBinding()`,
2321
// `internalBinding()` and `NativeModule`.
2422
//
25-
// After this file is run, one of the main scripts under `lib/internal/main/`
26-
// will be selected by C++ to start the actual execution. The main scripts may
27-
// run additional setups exported by `lib/internal/bootstrap/pre_execution.js`,
28-
// depending on the execution mode.
23+
// This file is run to bootstrap both the main thread and the worker threads.
24+
// After this file is run, certain properties are setup according to the
25+
// configuration of the Node.js instance using the files in
26+
// `lib/internal/bootstrap/switches/`.
27+
//
28+
// Then, depending on how the Node.js instance is launched, one of the main
29+
// scripts in `lib/internal/main` will be selected by C++ to start the actual
30+
// execution. They may run additional setups exported by
31+
// `lib/internal/bootstrap/pre_execution.js` depending on the runtime states.
2932

3033
'use strict';
3134

3235
// This file is compiled as if it's wrapped in a function with arguments
3336
// passed by node::RunBootstrapping()
34-
/* global process, require, internalBinding, isMainThread, ownsProcessState */
37+
/* global process, require, internalBinding */
3538

3639
setupPrepareStackTrace();
3740

@@ -54,48 +57,12 @@ setupBuffer();
5457
process.domain = null;
5558
process._exiting = false;
5659

57-
// Bootstrappers for all threads, including worker threads and main thread
58-
const perThreadSetup = require('internal/process/per_thread');
59-
// Bootstrappers for the main thread only
60-
let mainThreadSetup;
61-
// Bootstrappers for the worker threads only
62-
let workerThreadSetup;
63-
if (ownsProcessState) {
64-
mainThreadSetup = require(
65-
'internal/process/main_thread_only'
66-
);
67-
} else {
68-
workerThreadSetup = require(
69-
'internal/process/worker_thread_only'
70-
);
71-
}
72-
7360
// process.config is serialized config.gypi
7461
process.config = JSONParse(internalBinding('native_module').config);
7562

63+
// Bootstrappers for all threads, including worker threads and main thread
64+
const perThreadSetup = require('internal/process/per_thread');
7665
const rawMethods = internalBinding('process_methods');
77-
// Set up methods and events on the process object for the main thread
78-
if (isMainThread) {
79-
process.abort = rawMethods.abort;
80-
const wrapped = mainThreadSetup.wrapProcessMethods(rawMethods);
81-
process.umask = wrapped.umask;
82-
process.chdir = wrapped.chdir;
83-
process.cwd = wrapped.cwd;
84-
85-
// TODO(joyeecheung): deprecate and remove these underscore methods
86-
process._debugProcess = rawMethods._debugProcess;
87-
process._debugEnd = rawMethods._debugEnd;
88-
process._startProfilerIdleNotifier =
89-
rawMethods._startProfilerIdleNotifier;
90-
process._stopProfilerIdleNotifier = rawMethods._stopProfilerIdleNotifier;
91-
} else {
92-
const wrapped = workerThreadSetup.wrapProcessMethods(rawMethods);
93-
94-
process.abort = workerThreadSetup.unavailable('process.abort()');
95-
process.chdir = workerThreadSetup.unavailable('process.chdir()');
96-
process.umask = wrapped.umask;
97-
process.cwd = rawMethods.cwd;
98-
}
9966

10067
// Set up methods on the process object for all threads
10168
{
@@ -119,6 +86,11 @@ if (isMainThread) {
11986
process.memoryUsage = wrapped.memoryUsage;
12087
process.kill = wrapped.kill;
12188
process.exit = wrapped.exit;
89+
90+
process.openStdin = function() {
91+
process.stdin.resume();
92+
return process.stdin;
93+
};
12294
}
12395

12496
const credentials = internalBinding('credentials');
@@ -128,34 +100,6 @@ if (credentials.implementsPosixCredentials) {
128100
process.getgid = credentials.getgid;
129101
process.getegid = credentials.getegid;
130102
process.getgroups = credentials.getgroups;
131-
132-
if (ownsProcessState) {
133-
const wrapped = mainThreadSetup.wrapPosixCredentialSetters(credentials);
134-
process.initgroups = wrapped.initgroups;
135-
process.setgroups = wrapped.setgroups;
136-
process.setegid = wrapped.setegid;
137-
process.seteuid = wrapped.seteuid;
138-
process.setgid = wrapped.setgid;
139-
process.setuid = wrapped.setuid;
140-
} else {
141-
process.initgroups =
142-
workerThreadSetup.unavailable('process.initgroups()');
143-
process.setgroups = workerThreadSetup.unavailable('process.setgroups()');
144-
process.setegid = workerThreadSetup.unavailable('process.setegid()');
145-
process.seteuid = workerThreadSetup.unavailable('process.seteuid()');
146-
process.setgid = workerThreadSetup.unavailable('process.setgid()');
147-
process.setuid = workerThreadSetup.unavailable('process.setuid()');
148-
}
149-
}
150-
151-
if (isMainThread) {
152-
const { getStdout, getStdin, getStderr } =
153-
require('internal/process/stdio').getMainThreadStdio();
154-
setupProcessStdio(getStdout, getStdin, getStderr);
155-
} else {
156-
const { getStdout, getStdin, getStderr } =
157-
workerThreadSetup.createStdioGetters();
158-
setupProcessStdio(getStdout, getStdin, getStderr);
159103
}
160104

161105
// Setup the callbacks that node::AsyncWrap will call when there are hooks to
@@ -343,31 +287,6 @@ function setupProcessObject() {
343287
});
344288
}
345289

346-
function setupProcessStdio(getStdout, getStdin, getStderr) {
347-
ObjectDefineProperty(process, 'stdout', {
348-
configurable: true,
349-
enumerable: true,
350-
get: getStdout
351-
});
352-
353-
ObjectDefineProperty(process, 'stderr', {
354-
configurable: true,
355-
enumerable: true,
356-
get: getStderr
357-
});
358-
359-
ObjectDefineProperty(process, 'stdin', {
360-
configurable: true,
361-
enumerable: true,
362-
get: getStdin
363-
});
364-
365-
process.openStdin = function() {
366-
process.stdin.resume();
367-
return process.stdin;
368-
};
369-
}
370-
371290
function setupGlobalProxy() {
372291
ObjectDefineProperty(global, SymbolToStringTag, {
373292
value: 'global',

lib/internal/bootstrap/pre_execution.js

+1-17
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ function prepareMainThreadExecution(expandArgv1 = false) {
3636

3737
setupDebugEnv();
3838

39-
// Only main thread receives signals.
40-
setupSignalHandlers();
41-
4239
// Process initial diagnostic reporting configuration, if present.
4340
initializeReport();
4441
initializeReportSignalHandlers(); // Main-thread-only.
@@ -174,20 +171,7 @@ function setupDebugEnv() {
174171
}
175172
}
176173

177-
function setupSignalHandlers() {
178-
const {
179-
createSignalHandlers
180-
} = require('internal/process/main_thread_only');
181-
const {
182-
startListeningIfSignal,
183-
stopListeningIfSignal
184-
} = createSignalHandlers();
185-
process.on('newListener', startListeningIfSignal);
186-
process.on('removeListener', stopListeningIfSignal);
187-
}
188-
189-
// This has to be called after both initializeReport() and
190-
// setupSignalHandlers() are called
174+
// This has to be called after initializeReport() is called
191175
function initializeReportSignalHandlers() {
192176
if (!getOptionValue('--experimental-report')) {
193177
return;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict';
2+
3+
const credentials = internalBinding('credentials');
4+
5+
if (credentials.implementsPosixCredentials) {
6+
// TODO: this should be detached from ERR_WORKER_UNSUPPORTED_OPERATION
7+
const { unavailable } = require('internal/process/worker_thread_only');
8+
9+
process.initgroups = unavailable('process.initgroups()');
10+
process.setgroups = unavailable('process.setgroups()');
11+
process.setegid = unavailable('process.setegid()');
12+
process.seteuid = unavailable('process.seteuid()');
13+
process.setgid = unavailable('process.setgid()');
14+
process.setuid = unavailable('process.setuid()');
15+
}
16+
17+
// ---- keep the attachment of the wrappers above so that it's easier to ----
18+
// ---- compare the setups side-by-side -----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
'use strict';
2+
3+
const credentials = internalBinding('credentials');
4+
5+
if (credentials.implementsPosixCredentials) {
6+
const wrapped = wrapPosixCredentialSetters(credentials);
7+
8+
process.initgroups = wrapped.initgroups;
9+
process.setgroups = wrapped.setgroups;
10+
process.setegid = wrapped.setegid;
11+
process.seteuid = wrapped.seteuid;
12+
process.setgid = wrapped.setgid;
13+
process.setuid = wrapped.setuid;
14+
}
15+
16+
// ---- keep the attachment of the wrappers above so that it's easier to ----
17+
// ---- compare the setups side-by-side -----
18+
19+
function wrapPosixCredentialSetters(credentials) {
20+
const {
21+
ArrayIsArray,
22+
} = primordials;
23+
const {
24+
codes: {
25+
ERR_INVALID_ARG_TYPE,
26+
ERR_UNKNOWN_CREDENTIAL
27+
}
28+
} = require('internal/errors');
29+
const {
30+
validateUint32
31+
} = require('internal/validators');
32+
33+
const {
34+
initgroups: _initgroups,
35+
setgroups: _setgroups,
36+
setegid: _setegid,
37+
seteuid: _seteuid,
38+
setgid: _setgid,
39+
setuid: _setuid
40+
} = credentials;
41+
42+
function initgroups(user, extraGroup) {
43+
validateId(user, 'user');
44+
validateId(extraGroup, 'extraGroup');
45+
// Result is 0 on success, 1 if user is unknown, 2 if group is unknown.
46+
const result = _initgroups(user, extraGroup);
47+
if (result === 1) {
48+
throw new ERR_UNKNOWN_CREDENTIAL('User', user);
49+
} else if (result === 2) {
50+
throw new ERR_UNKNOWN_CREDENTIAL('Group', extraGroup);
51+
}
52+
}
53+
54+
function setgroups(groups) {
55+
if (!ArrayIsArray(groups)) {
56+
throw new ERR_INVALID_ARG_TYPE('groups', 'Array', groups);
57+
}
58+
for (let i = 0; i < groups.length; i++) {
59+
validateId(groups[i], `groups[${i}]`);
60+
}
61+
// Result is 0 on success. A positive integer indicates that the
62+
// corresponding group was not found.
63+
const result = _setgroups(groups);
64+
if (result > 0) {
65+
throw new ERR_UNKNOWN_CREDENTIAL('Group', groups[result - 1]);
66+
}
67+
}
68+
69+
function wrapIdSetter(type, method) {
70+
return function(id) {
71+
validateId(id, 'id');
72+
// Result is 0 on success, 1 if credential is unknown.
73+
const result = method(id);
74+
if (result === 1) {
75+
throw new ERR_UNKNOWN_CREDENTIAL(type, id);
76+
}
77+
};
78+
}
79+
80+
function validateId(id, name) {
81+
if (typeof id === 'number') {
82+
validateUint32(id, name);
83+
} else if (typeof id !== 'string') {
84+
throw new ERR_INVALID_ARG_TYPE(name, ['number', 'string'], id);
85+
}
86+
}
87+
88+
return {
89+
initgroups,
90+
setgroups,
91+
setegid: wrapIdSetter('Group', _setegid),
92+
seteuid: wrapIdSetter('User', _seteuid),
93+
setgid: wrapIdSetter('Group', _setgid),
94+
setuid: wrapIdSetter('User', _setuid)
95+
};
96+
}

0 commit comments

Comments
 (0)