summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/internal/bootstrap/node.js100
-rw-r--r--lib/internal/process/main_thread_only.js24
-rw-r--r--lib/internal/process/per_thread.js141
-rw-r--r--src/bootstrapper.cc14
-rw-r--r--src/node.cc155
-rw-r--r--src/node_binding.cc1
-rw-r--r--src/node_internals.h15
-rw-r--r--src/node_process.cc187
-rw-r--r--test/parallel/test-bootstrap-modules.js2
9 files changed, 322 insertions, 317 deletions
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js
index c51961e9ce..c375374164 100644
--- a/lib/internal/bootstrap/node.js
+++ b/lib/internal/bootstrap/node.js
@@ -20,11 +20,7 @@
const {
_setupTraceCategoryState,
_setupNextTick,
- _setupPromises, _chdir, _cpuUsage,
- _hrtime, _hrtimeBigInt,
- _memoryUsage, _rawDebug,
- _umask,
- _shouldAbortOnUncaughtToggle
+ _setupPromises
} = bootstrappers;
const { internalBinding, NativeModule } = loaderExports;
@@ -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,
@@ -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();
@@ -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();
}
diff --git a/lib/internal/process/main_thread_only.js b/lib/internal/process/main_thread_only.js
index 5f53f34084..1db693f1ec 100644
--- a/lib/internal/process/main_thread_only.js
+++ b/lib/internal/process/main_thread_only.js
@@ -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
};
}
@@ -175,7 +179,7 @@ function setupChildProcessIpcChannel() {
module.exports = {
setupStdio,
- setupProcessMethods,
+ wrapProcessMethods,
setupSignalHandlers,
setupChildProcessIpcChannel,
wrapPosixCredentialSetters
diff --git a/lib/internal/process/per_thread.js b/lib/internal/process/per_thread.js
index 57cc9c3814..f1629e3a97 100644
--- a/lib/internal/process/per_thread.js
+++ b/lib/internal/process/per_thread.js
@@ -18,25 +18,30 @@ const {
} = require('internal/errors');
const util = require('util');
const constants = internalBinding('constants').os.signals;
-const { deprecate } = require('internal/util');
-
-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');
+
+function assert(x, msg) {
+ if (!x) throw new ERR_ASSERTION(msg || 'assertion error');
}
-// Set up the process.cpuUsage() function.
-function setupCpuUsage(_cpuUsage) {
+// The execution of this function itself should not cause any side effects.
+function wrapProcessMethods(binding, exceptionHandlerState) {
+ const {
+ hrtime: _hrtime,
+ hrtimeBigInt: _hrtimeBigInt,
+ cpuUsage: _cpuUsage,
+ memoryUsage: _memoryUsage
+ } = binding;
+
+ function _rawDebug(...args) {
+ binding._rawDebug(util.format.apply(null, args));
+ }
+
// Create the argument array that will be passed to the native function.
const cpuValues = new Float64Array(2);
// Replace the native function with the JS version that calls the native
// function.
- process.cpuUsage = function cpuUsage(prevValue) {
+ function cpuUsage(prevValue) {
// If a previous value was passed in, ensure it has the correct shape.
if (prevValue) {
if (!previousValueIsValid(prevValue.user)) {
@@ -80,7 +85,7 @@ function setupCpuUsage(_cpuUsage) {
user: cpuValues[0],
system: cpuValues[1]
};
- };
+ }
// Ensure that a previously passed in value is valid. Currently, the native
// implementation always returns numbers <= Number.MAX_SAFE_INTEGER.
@@ -89,15 +94,13 @@ function setupCpuUsage(_cpuUsage) {
num <= Number.MAX_SAFE_INTEGER &&
num >= 0;
}
-}
-// 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 setupHrtime(_hrtime, _hrtimeBigInt) {
+ // 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.
const hrValues = new Uint32Array(3);
- process.hrtime = function hrtime(time) {
+ function hrtime(time) {
_hrtime(hrValues);
if (time !== undefined) {
@@ -118,21 +121,18 @@ function setupHrtime(_hrtime, _hrtimeBigInt) {
hrValues[0] * 0x100000000 + hrValues[1],
hrValues[2]
];
- };
+ }
// Use a BigUint64Array in the closure because V8 does not have an API for
// creating a BigInt out of a uint64_t yet.
const hrBigintValues = new BigUint64Array(1);
- process.hrtime.bigint = function() {
+ function hrtimeBigInt() {
_hrtimeBigInt(hrBigintValues);
return hrBigintValues[0];
- };
-}
+ }
-function setupMemoryUsage(_memoryUsage) {
const memValues = new Float64Array(4);
-
- process.memoryUsage = function memoryUsage() {
+ function memoryUsage() {
_memoryUsage(memValues);
return {
rss: memValues[0],
@@ -140,18 +140,9 @@ function setupMemoryUsage(_memoryUsage) {
heapUsed: memValues[2],
external: memValues[3]
};
- };
-}
-
-function setupConfig() {
- // Serialized config.gypi
- process.config = JSON.parse(internalBinding('native_module').config);
-}
-
-
-function setupKillAndExit() {
+ }
- process.exit = function(code) {
+ function exit(code) {
if (code || code === 0)
process.exitCode = code;
@@ -159,10 +150,10 @@ function setupKillAndExit() {
process._exiting = true;
process.emit('exit', process.exitCode || 0);
}
- process.reallyExit(process.exitCode || 0);
- };
+ binding.reallyExit(process.exitCode || 0);
+ }
- process.kill = function(pid, sig) {
+ function kill(pid, sig) {
var err;
if (process.env.NODE_V8_COVERAGE) {
const { writeCoverage } = require('internal/process/coverage');
@@ -176,6 +167,8 @@ function setupKillAndExit() {
// preserve null signal
if (sig === (sig | 0)) {
+ // XXX(joyeecheung): we have to use process._kill here because
+ // it's monkey-patched by tests.
err = process._kill(pid, sig);
} else {
sig = sig || 'SIGTERM';
@@ -190,22 +183,13 @@ function setupKillAndExit() {
throw errnoException(err, 'kill');
return true;
- };
-}
-
-function setupRawDebug(_rawDebug) {
- process._rawDebug = function() {
- _rawDebug(util.format.apply(null, arguments));
- };
-}
-
+ }
-function setupUncaughtExceptionCapture(exceptionHandlerState,
- shouldAbortOnUncaughtToggle) {
// shouldAbortOnUncaughtToggle is a typed array for faster
// communication with JS.
+ const { shouldAbortOnUncaughtToggle } = binding;
- process.setUncaughtExceptionCaptureCallback = function(fn) {
+ function setUncaughtExceptionCaptureCallback(fn) {
if (fn === null) {
exceptionHandlerState.captureFn = fn;
shouldAbortOnUncaughtToggle[0] = 1;
@@ -219,10 +203,22 @@ function setupUncaughtExceptionCapture(exceptionHandlerState,
}
exceptionHandlerState.captureFn = fn;
shouldAbortOnUncaughtToggle[0] = 0;
- };
+ }
- process.hasUncaughtExceptionCaptureCallback = function() {
+ function hasUncaughtExceptionCaptureCallback() {
return exceptionHandlerState.captureFn !== null;
+ }
+
+ return {
+ _rawDebug,
+ hrtime,
+ hrtimeBigInt,
+ cpuUsage,
+ memoryUsage,
+ kill,
+ exit,
+ setUncaughtExceptionCaptureCallback,
+ hasUncaughtExceptionCaptureCallback
};
}
@@ -326,38 +322,13 @@ function buildAllowedFlags() {
Object.freeze(NodeEnvironmentFlagsSet.prototype.constructor);
Object.freeze(NodeEnvironmentFlagsSet.prototype);
- return process.allowedNodeEnvironmentFlags = Object.freeze(
- new NodeEnvironmentFlagsSet(
- allowedNodeEnvironmentFlags
- ));
-}
-
-function setupAllowedFlags() {
- Object.defineProperty(process, 'allowedNodeEnvironmentFlags', {
- get: buildAllowedFlags,
- set(value) {
- // If the user tries to set this to another value, override
- // this completely to that value.
- Object.defineProperty(this, 'allowedNodeEnvironmentFlags', {
- value,
- configurable: true,
- enumerable: true,
- writable: true
- });
- },
- enumerable: true,
- configurable: true
- });
+ return Object.freeze(new NodeEnvironmentFlagsSet(
+ allowedNodeEnvironmentFlags
+ ));
}
module.exports = {
- setupAllowedFlags,
- setupAssert,
- setupCpuUsage,
- setupHrtime,
- setupMemoryUsage,
- setupConfig,
- setupKillAndExit,
- setupRawDebug,
- setupUncaughtExceptionCapture
+ assert,
+ buildAllowedFlags,
+ wrapProcessMethods
};
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index 0a1cfed210..60c05a58a6 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -139,20 +139,6 @@ void SetupBootstrapObject(Environment* env,
BOOTSTRAP_METHOD(_setupTraceCategoryState, SetupTraceCategoryState);
BOOTSTRAP_METHOD(_setupNextTick, SetupNextTick);
BOOTSTRAP_METHOD(_setupPromises, SetupPromises);
- BOOTSTRAP_METHOD(_chdir, Chdir);
- BOOTSTRAP_METHOD(_cpuUsage, CPUUsage);
- BOOTSTRAP_METHOD(_hrtime, Hrtime);
- BOOTSTRAP_METHOD(_hrtimeBigInt, HrtimeBigInt);
- BOOTSTRAP_METHOD(_memoryUsage, MemoryUsage);
- BOOTSTRAP_METHOD(_rawDebug, RawDebug);
- BOOTSTRAP_METHOD(_umask, Umask);
-
- Local<String> should_abort_on_uncaught_toggle =
- FIXED_ONE_BYTE_STRING(env->isolate(), "_shouldAbortOnUncaughtToggle");
- CHECK(bootstrapper->Set(env->context(),
- should_abort_on_uncaught_toggle,
- env->should_abort_on_uncaught_toggle().GetJSArray())
- .FromJust());
}
#undef BOOTSTRAP_METHOD
diff --git a/src/node.cc b/src/node.cc
index 077d9c4996..9bd2ac9ff6 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -95,8 +95,6 @@
#if defined(_MSC_VER)
#include <direct.h>
#include <io.h>
-#define umask _umask
-typedef int mode_t;
#else
#include <pthread.h>
#include <sys/resource.h> // getrlimit, setrlimit
@@ -689,8 +687,7 @@ static void WaitForInspectorDisconnect(Environment* env) {
#endif
}
-
-static void Exit(const FunctionCallbackInfo<Value>& args) {
+void Exit(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
WaitForInspectorDisconnect(env);
v8_platform.StopTracingAgent();
@@ -1114,29 +1111,6 @@ void SetupProcessObject(Environment* env,
DebugPortGetter,
env->is_main_thread() ? DebugPortSetter : nullptr,
env->as_external()).FromJust());
-
- // define various internal methods
- if (env->is_main_thread()) {
- env->SetMethod(process, "_debugProcess", DebugProcess);
- env->SetMethod(process, "_debugEnd", DebugEnd);
- env->SetMethod(process,
- "_startProfilerIdleNotifier",
- StartProfilerIdleNotifier);
- env->SetMethod(process,
- "_stopProfilerIdleNotifier",
- StopProfilerIdleNotifier);
- env->SetMethod(process, "abort", Abort);
- env->SetMethod(process, "chdir", Chdir);
- env->SetMethod(process, "umask", Umask);
- }
- env->SetMethod(process, "_getActiveRequests", GetActiveRequests);
- env->SetMethod(process, "_getActiveHandles", GetActiveHandles);
- env->SetMethod(process, "_kill", Kill);
-
- env->SetMethodNoSideEffect(process, "cwd", Cwd);
- env->SetMethod(process, "dlopen", binding::DLOpen);
- env->SetMethod(process, "reallyExit", Exit);
- env->SetMethodNoSideEffect(process, "uptime", Uptime);
}
@@ -1278,135 +1252,8 @@ void RegisterSignalHandler(int signal,
CHECK_EQ(sigaction(signal, &sa, nullptr), 0);
}
-
-void DebugProcess(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args);
-
- if (args.Length() != 1) {
- return env->ThrowError("Invalid number of arguments.");
- }
-
- CHECK(args[0]->IsNumber());
- pid_t pid = args[0].As<Integer>()->Value();
- int r = kill(pid, SIGUSR1);
-
- if (r != 0) {
- return env->ThrowErrnoException(errno, "kill");
- }
-}
#endif // __POSIX__
-
-#ifdef _WIN32
-static int GetDebugSignalHandlerMappingName(DWORD pid, wchar_t* buf,
- size_t buf_len) {
- return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
-}
-
-
-static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args);
- Isolate* isolate = args.GetIsolate();
-
- if (args.Length() != 1) {
- env->ThrowError("Invalid number of arguments.");
- return;
- }
-
- HANDLE process = nullptr;
- HANDLE thread = nullptr;
- HANDLE mapping = nullptr;
- wchar_t mapping_name[32];
- LPTHREAD_START_ROUTINE* handler = nullptr;
- DWORD pid = 0;
-
- OnScopeLeave cleanup([&]() {
- if (process != nullptr)
- CloseHandle(process);
- if (thread != nullptr)
- CloseHandle(thread);
- if (handler != nullptr)
- UnmapViewOfFile(handler);
- if (mapping != nullptr)
- CloseHandle(mapping);
- });
-
- CHECK(args[0]->IsNumber());
- pid = args[0].As<Integer>()->Value();
-
- process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
- PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
- PROCESS_VM_READ,
- FALSE,
- pid);
- if (process == nullptr) {
- isolate->ThrowException(
- WinapiErrnoException(isolate, GetLastError(), "OpenProcess"));
- return;
- }
-
- if (GetDebugSignalHandlerMappingName(pid,
- mapping_name,
- arraysize(mapping_name)) < 0) {
- env->ThrowErrnoException(errno, "sprintf");
- return;
- }
-
- mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name);
- if (mapping == nullptr) {
- isolate->ThrowException(WinapiErrnoException(isolate,
- GetLastError(),
- "OpenFileMappingW"));
- return;
- }
-
- handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
- MapViewOfFile(mapping,
- FILE_MAP_READ,
- 0,
- 0,
- sizeof *handler));
- if (handler == nullptr || *handler == nullptr) {
- isolate->ThrowException(
- WinapiErrnoException(isolate, GetLastError(), "MapViewOfFile"));
- return;
- }
-
- thread = CreateRemoteThread(process,
- nullptr,
- 0,
- *handler,
- nullptr,
- 0,
- nullptr);
- if (thread == nullptr) {
- isolate->ThrowException(WinapiErrnoException(isolate,
- GetLastError(),
- "CreateRemoteThread"));
- return;
- }
-
- // Wait for the thread to terminate
- if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
- isolate->ThrowException(WinapiErrnoException(isolate,
- GetLastError(),
- "WaitForSingleObject"));
- return;
- }
-}
-#endif // _WIN32
-
-
-static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
-#if HAVE_INSPECTOR
- Environment* env = Environment::GetCurrent(args);
- if (env->inspector_agent()->IsListening()) {
- env->inspector_agent()->Stop();
- }
-#endif
-}
-
-
inline void PlatformInit() {
#ifdef __POSIX__
#if HAVE_INSPECTOR
diff --git a/src/node_binding.cc b/src/node_binding.cc
index 0758741ffc..46ae5f6840 100644
--- a/src/node_binding.cc
+++ b/src/node_binding.cc
@@ -44,6 +44,7 @@
V(performance) \
V(pipe_wrap) \
V(process_wrap) \
+ V(process_methods) \
V(serdes) \
V(signal_wrap) \
V(spawn_sync) \
diff --git a/src/node_internals.h b/src/node_internals.h
index 03017fb4f5..99498a6218 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -119,6 +119,7 @@ void GetSockOrPeerName(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(err);
}
+void Exit(const v8::FunctionCallbackInfo<v8::Value>& args);
void SignalExit(int signo);
#ifdef __POSIX__
void RegisterSignalHandler(int signal,
@@ -698,21 +699,7 @@ static inline const char* errno_string(int errorno) {
extern double prog_start_time;
-void Abort(const v8::FunctionCallbackInfo<v8::Value>& args);
-void Chdir(const v8::FunctionCallbackInfo<v8::Value>& args);
-void CPUUsage(const v8::FunctionCallbackInfo<v8::Value>& args);
-void Cwd(const v8::FunctionCallbackInfo<v8::Value>& args);
-void GetActiveHandles(const v8::FunctionCallbackInfo<v8::Value>& args);
-void GetActiveRequests(const v8::FunctionCallbackInfo<v8::Value>& args);
-void Hrtime(const v8::FunctionCallbackInfo<v8::Value>& args);
-void HrtimeBigInt(const v8::FunctionCallbackInfo<v8::Value>& args);
-void Kill(const v8::FunctionCallbackInfo<v8::Value>& args);
-void MemoryUsage(const v8::FunctionCallbackInfo<v8::Value>& args);
void RawDebug(const v8::FunctionCallbackInfo<v8::Value>& args);
-void StartProfilerIdleNotifier(const v8::FunctionCallbackInfo<v8::Value>& args);
-void StopProfilerIdleNotifier(const v8::FunctionCallbackInfo<v8::Value>& args);
-void Umask(const v8::FunctionCallbackInfo<v8::Value>& args);
-void Uptime(const v8::FunctionCallbackInfo<v8::Value>& args);
void DebugPortGetter(v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& info);
diff --git a/src/node_process.cc b/src/node_process.cc
index b9376953e2..477ac2adc8 100644
--- a/src/node_process.cc
+++ b/src/node_process.cc
@@ -8,6 +8,8 @@
#include "uv.h"
#include "v8.h"
+#include <vector>
+
#if HAVE_INSPECTOR
#include "inspector_io.h"
#endif
@@ -36,10 +38,12 @@ using v8::Float64Array;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::HeapStatistics;
+using v8::Integer;
using v8::Isolate;
using v8::Local;
using v8::Name;
using v8::NewStringType;
+using v8::Object;
using v8::PropertyCallbackInfo;
using v8::String;
using v8::Uint32;
@@ -61,11 +65,11 @@ Mutex environ_mutex;
#define CHDIR_BUFSIZE (PATH_MAX)
#endif
-void Abort(const FunctionCallbackInfo<Value>& args) {
+static void Abort(const FunctionCallbackInfo<Value>& args) {
Abort();
}
-void Chdir(const FunctionCallbackInfo<Value>& args) {
+static void Chdir(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(env->is_main_thread());
@@ -88,7 +92,7 @@ void Chdir(const FunctionCallbackInfo<Value>& args) {
// which are uv_timeval_t structs (long tv_sec, long tv_usec).
// Returns those values as Float64 microseconds in the elements of the array
// passed to the function.
-void CPUUsage(const FunctionCallbackInfo<Value>& args) {
+static void CPUUsage(const FunctionCallbackInfo<Value>& args) {
uv_rusage_t rusage;
// Call libuv to get the values we'll return.
@@ -111,7 +115,7 @@ void CPUUsage(const FunctionCallbackInfo<Value>& args) {
fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
}
-void Cwd(const FunctionCallbackInfo<Value>& args) {
+static void Cwd(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
char buf[CHDIR_BUFSIZE];
size_t cwd_len = sizeof(buf);
@@ -138,7 +142,7 @@ void Cwd(const FunctionCallbackInfo<Value>& args) {
// broken into the upper/lower 32 bits to be converted back in JS,
// because there is no Uint64Array in JS.
// The third entry contains the remaining nanosecond part of the value.
-void Hrtime(const FunctionCallbackInfo<Value>& args) {
+static void Hrtime(const FunctionCallbackInfo<Value>& args) {
uint64_t t = uv_hrtime();
Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
@@ -149,13 +153,13 @@ void Hrtime(const FunctionCallbackInfo<Value>& args) {
fields[2] = t % NANOS_PER_SEC;
}
-void HrtimeBigInt(const FunctionCallbackInfo<Value>& args) {
+static void HrtimeBigInt(const FunctionCallbackInfo<Value>& args) {
Local<ArrayBuffer> ab = args[0].As<BigUint64Array>()->Buffer();
uint64_t* fields = static_cast<uint64_t*>(ab->GetContents().Data());
fields[0] = uv_hrtime();
}
-void Kill(const FunctionCallbackInfo<Value>& args) {
+static void Kill(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Local<Context> context = env->context();
@@ -170,8 +174,7 @@ void Kill(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(err);
}
-
-void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
+static void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
size_t rss;
@@ -209,18 +212,17 @@ void RawDebug(const FunctionCallbackInfo<Value>& args) {
fflush(stderr);
}
-void StartProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
+static void StartProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
env->StartProfilerIdleNotifier();
}
-
-void StopProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
+static void StopProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
env->StopProfilerIdleNotifier();
}
-void Umask(const FunctionCallbackInfo<Value>& args) {
+static void Umask(const FunctionCallbackInfo<Value>& args) {
uint32_t old;
CHECK_EQ(args.Length(), 1);
@@ -237,7 +239,7 @@ void Umask(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(old);
}
-void Uptime(const FunctionCallbackInfo<Value>& args) {
+static void Uptime(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
double uptime;
@@ -255,7 +257,6 @@ void ProcessTitleGetter(Local<Name> property,
NewStringType::kNormal).ToLocalChecked());
}
-
void ProcessTitleSetter(Local<Name> property,
Local<Value> value,
const PropertyCallbackInfo<void>& info) {
@@ -270,7 +271,7 @@ void GetParentProcessId(Local<Name> property,
info.GetReturnValue().Set(uv_os_getppid());
}
-void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
+static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
std::vector<Local<Value>> request_v;
@@ -315,5 +316,159 @@ void DebugPortSetter(Local<Name> property,
env->inspector_host_port()->set_port(static_cast<int>(port));
}
+#ifdef __POSIX__
+static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+
+ if (args.Length() != 1) {
+ return env->ThrowError("Invalid number of arguments.");
+ }
+
+ CHECK(args[0]->IsNumber());
+ pid_t pid = args[0].As<Integer>()->Value();
+ int r = kill(pid, SIGUSR1);
+
+ if (r != 0) {
+ return env->ThrowErrnoException(errno, "kill");
+ }
+}
+#endif // __POSIX__
+
+#ifdef _WIN32
+static int GetDebugSignalHandlerMappingName(DWORD pid,
+ wchar_t* buf,
+ size_t buf_len) {
+ return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
+}
+
+static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ Isolate* isolate = args.GetIsolate();
+
+ if (args.Length() != 1) {
+ env->ThrowError("Invalid number of arguments.");
+ return;
+ }
+
+ HANDLE process = nullptr;
+ HANDLE thread = nullptr;
+ HANDLE mapping = nullptr;
+ wchar_t mapping_name[32];
+ LPTHREAD_START_ROUTINE* handler = nullptr;
+ DWORD pid = 0;
+
+ OnScopeLeave cleanup([&]() {
+ if (process != nullptr) CloseHandle(process);
+ if (thread != nullptr) CloseHandle(thread);
+ if (handler != nullptr) UnmapViewOfFile(handler);
+ if (mapping != nullptr) CloseHandle(mapping);
+ });
+
+ CHECK(args[0]->IsNumber());
+ pid = args[0].As<Integer>()->Value();
+
+ process =
+ OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
+ PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
+ FALSE,
+ pid);
+ if (process == nullptr) {
+ isolate->ThrowException(
+ WinapiErrnoException(isolate, GetLastError(), "OpenProcess"));
+ return;
+ }
+
+ if (GetDebugSignalHandlerMappingName(
+ pid, mapping_name, arraysize(mapping_name)) < 0) {
+ env->ThrowErrnoException(errno, "sprintf");
+ return;
+ }
+
+ mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name);
+ if (mapping == nullptr) {
+ isolate->ThrowException(
+ WinapiErrnoException(isolate, GetLastError(), "OpenFileMappingW"));
+ return;
+ }
+
+ handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
+ MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, sizeof *handler));
+ if (handler == nullptr || *handler == nullptr) {
+ isolate->ThrowException(
+ WinapiErrnoException(isolate, GetLastError(), "MapViewOfFile"));
+ return;
+ }
+
+ thread =
+ CreateRemoteThread(process, nullptr, 0, *handler, nullptr, 0, nullptr);
+ if (thread == nullptr) {
+ isolate->ThrowException(
+ WinapiErrnoException(isolate, GetLastError(), "CreateRemoteThread"));
+ return;
+ }
+
+ // Wait for the thread to terminate
+ if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
+ isolate->ThrowException(
+ WinapiErrnoException(isolate, GetLastError(), "WaitForSingleObject"));
+ return;
+ }
+}
+#endif // _WIN32
+
+static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
+#if HAVE_INSPECTOR
+ Environment* env = Environment::GetCurrent(args);
+ if (env->inspector_agent()->IsListening()) {
+ env->inspector_agent()->Stop();
+ }
+#endif
+}
+
+static void InitializeProcessMethods(Local<Object> target,
+ Local<Value> unused,
+ Local<Context> context,
+ void* priv) {
+ Environment* env = Environment::GetCurrent(context);
+
+ // define various internal methods
+ if (env->is_main_thread()) {
+ env->SetMethod(target, "_debugProcess", DebugProcess);
+ env->SetMethod(target, "_debugEnd", DebugEnd);
+ env->SetMethod(
+ target, "_startProfilerIdleNotifier", StartProfilerIdleNotifier);
+ env->SetMethod(
+ target, "_stopProfilerIdleNotifier", StopProfilerIdleNotifier);
+ env->SetMethod(target, "abort", Abort);
+ env->SetMethod(target, "chdir", Chdir);
+ env->SetMethod(target, "umask", Umask);
+ }
+
+ env->SetMethod(target, "_rawDebug", RawDebug);
+ env->SetMethod(target, "memoryUsage", MemoryUsage);
+ env->SetMethod(target, "cpuUsage", CPUUsage);
+ env->SetMethod(target, "hrtime", Hrtime);
+ env->SetMethod(target, "hrtimeBigInt", HrtimeBigInt);
+
+ env->SetMethod(target, "_getActiveRequests", GetActiveRequests);
+ env->SetMethod(target, "_getActiveHandles", GetActiveHandles);
+ env->SetMethod(target, "_kill", Kill);
+
+ env->SetMethodNoSideEffect(target, "cwd", Cwd);
+ env->SetMethod(target, "dlopen", binding::DLOpen);
+ env->SetMethod(target, "reallyExit", Exit);
+ env->SetMethodNoSideEffect(target, "uptime", Uptime);
+
+ Local<String> should_abort_on_uncaught_toggle =
+ FIXED_ONE_BYTE_STRING(env->isolate(), "shouldAbortOnUncaughtToggle");
+ CHECK(target
+ ->Set(env->context(),
+ should_abort_on_uncaught_toggle,
+ env->should_abort_on_uncaught_toggle().GetJSArray())
+ .FromJust());
+}
} // namespace node
+
+NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods,
+ node::InitializeProcessMethods)
diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js
index 5c1693ca89..3f67144f5f 100644
--- a/test/parallel/test-bootstrap-modules.js
+++ b/test/parallel/test-bootstrap-modules.js
@@ -9,7 +9,7 @@ const common = require('../common');
const assert = require('assert');
const isMainThread = common.isMainThread;
-const kMaxModuleCount = isMainThread ? 60 : 82;
+const kMaxModuleCount = isMainThread ? 61 : 83;
assert(list.length <= kMaxModuleCount,
`Total length: ${list.length}\n` + list.join('\n')