Skip to content
Permalink
Browse files

src: move more process methods initialization in bootstrap/node.js

Instead of:

- Writing methods onto the process directly in C++ during
  `SetupProcessObject()` and overwrite with argument checks later
- Or, wrapping and writing them in `internal/process/*.js`

Do:

- Move the C++ implementations in node_process.cc and mark them static
  wherever possible
- Expose the C++ methods through a new
  `internalBinding('process_methods')`
- Wrap the methods in `internal/process/*.js` in a
  side-effect-free manner and return them back to
  `internal/bootstrap/node.js`
- Centralize the write to the process object based on conditions
  in `bootstrap/node.js`

So it's easier to see what methods are attached to the process object
during bootstrap under what condition and in what order.

The eventual goal is to figure out the dependency of process methods
and the write/read access to the process object during bootstrap, group
these access properly and remove the process properties that should not
be exposed to users this way.

Also correct the NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE milestone
which should be marked before code execution.

Refs: #24961

PR-URL: #25127
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>

Backport-PR-URL: #25496
  • Loading branch information...
joyeecheung authored and addaleax committed Dec 19, 2018
1 parent a4f50a6 commit dde71520ba7439741c3314b719ea88dc0ed8b9a7
@@ -19,11 +19,7 @@

const {
_setupNextTick,
_setupPromises, _chdir, _cpuUsage,
_hrtime, _hrtimeBigInt,
_memoryUsage, _rawDebug,
_umask,
_shouldAbortOnUncaughtToggle
_setupPromises
} = bootstrappers;
const { internalBinding, NativeModule } = loaderExports;

@@ -56,15 +52,57 @@ function startup() {
);
}

perThreadSetup.setupAssert();
perThreadSetup.setupConfig();
// process.config is serialized config.gypi
process.config = JSON.parse(internalBinding('native_module').config);

const rawMethods = internalBinding('process_methods');
// Set up methods and events on the process object for the main thread
if (isMainThread) {
// This depends on process being an event emitter
mainThreadSetup.setupSignalHandlers(internalBinding);

process.abort = rawMethods.abort;
const wrapped = mainThreadSetup.wrapProcessMethods(rawMethods);
process.umask = wrapped.umask;
process.chdir = wrapped.chdir;

// TODO(joyeecheung): deprecate and remove these underscore methods
process._debugProcess = rawMethods._debugProcess;
process._debugEnd = rawMethods._debugEnd;
process._startProfilerIdleNotifier =
rawMethods._startProfilerIdleNotifier;
process._stopProfilerIdleNotifier = rawMethods._stopProfilerIdleNotifier;
}

perThreadSetup.setupUncaughtExceptionCapture(exceptionHandlerState,
_shouldAbortOnUncaughtToggle);
// Set up methods on the process object for all threads
{
process.cwd = rawMethods.cwd;
process.dlopen = rawMethods.dlopen;
process.uptime = rawMethods.uptime;

// TODO(joyeecheung): either remove them or make them public
process._getActiveRequests = rawMethods._getActiveRequests;
process._getActiveHandles = rawMethods._getActiveHandles;

// TODO(joyeecheung): remove these
process.reallyExit = rawMethods.reallyExit;
process._kill = rawMethods._kill;

const wrapped = perThreadSetup.wrapProcessMethods(
rawMethods, exceptionHandlerState
);
process._rawDebug = wrapped._rawDebug;
process.hrtime = wrapped.hrtime;
process.hrtime.bigint = wrapped.hrtimeBigInt;
process.cpuUsage = wrapped.cpuUsage;
process.memoryUsage = wrapped.memoryUsage;
process.kill = wrapped.kill;
process.exit = wrapped.exit;
process.setUncaughtExceptionCaptureCallback =
wrapped.setUncaughtExceptionCaptureCallback;
process.hasUncaughtExceptionCaptureCallback =
wrapped.hasUncaughtExceptionCaptureCallback;
}

NativeModule.require('internal/process/warning').setup();
NativeModule.require('internal/process/next_tick').setup(_setupNextTick,
@@ -90,22 +128,10 @@ function startup() {

if (isMainThread) {
mainThreadSetup.setupStdio();
mainThreadSetup.setupProcessMethods(_chdir, _umask);
} else {
workerThreadSetup.setupStdio();
}

const perf = internalBinding('performance');
const {
NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE,
} = perf.constants;

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();

@@ -237,9 +263,37 @@ function startup() {
}
}

perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
// process.allowedNodeEnvironmentFlags
Object.defineProperty(process, 'allowedNodeEnvironmentFlags', {
get() {
const flags = perThreadSetup.buildAllowedFlags();
process.allowedNodeEnvironmentFlags = flags;
return process.allowedNodeEnvironmentFlags;
},
// If the user tries to set this to another value, override
// this completely to that value.
set(value) {
Object.defineProperty(this, 'allowedNodeEnvironmentFlags', {
value,
configurable: true,
enumerable: true,
writable: true
});
},
enumerable: true,
configurable: true
});
// process.assert
process.assert = deprecate(
perThreadSetup.assert,
'process.assert() is deprecated. Please use the `assert` module instead.',
'DEP0100');

perThreadSetup.setupAllowedFlags();
const perf = internalBinding('performance');
const {
NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE,
} = perf.constants;
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);

startExecution();
}
@@ -25,21 +25,25 @@ 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) {
process.chdir = function chdir(directory) {
// The execution of this function itself should not cause any side effects.
function wrapProcessMethods(binding) {
function chdir(directory) {
validateString(directory, 'directory');
return _chdir(directory);
};
return binding.chdir(directory);
}

process.umask = function umask(mask) {
function umask(mask) {
if (mask === undefined) {
// Get the mask
return _umask(mask);
return binding.umask(mask);
}
mask = validateMode(mask, 'mask');
return _umask(mask);
return binding.umask(mask);
}

return {
chdir,
umask
};
}

@@ -171,7 +175,7 @@ function setupChildProcessIpcChannel() {

module.exports = {
setupStdio,
setupProcessMethods,
wrapProcessMethods,
setupSignalHandlers,
setupChildProcessIpcChannel,
wrapPosixCredentialSetters

0 comments on commit dde7152

Please sign in to comment.
You can’t perform that action at this time.