Skip to content

Commit

Permalink
src: move more process methods initialization in bootstrap/node.js
Browse files Browse the repository at this point in the history
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: nodejs#24961
  • Loading branch information
joyeecheung committed Dec 19, 2018
1 parent 74f7a84 commit c4fbbd4
Show file tree
Hide file tree
Showing 9 changed files with 322 additions and 317 deletions.
100 changes: 77 additions & 23 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@

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

Expand Down Expand Up @@ -57,15 +53,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,
Expand All @@ -91,22 +129,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();

Expand Down Expand Up @@ -209,9 +235,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();
}
Expand Down
24 changes: 14 additions & 10 deletions lib/internal/process/main_thread_only.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,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
};
}

Expand Down Expand Up @@ -175,7 +179,7 @@ function setupChildProcessIpcChannel() {

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

0 comments on commit c4fbbd4

Please sign in to comment.