mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 18:25:13 +08:00
Add an ExitCode enum class and use it throughout the code base instead of hard-coding the exit codes everywhere. At the moment, the exit codes used in many places do not actually conform to what the documentation describes. With the new enums (which are also available to the JS land as constants in an internal binding) we could migrate to a more consistent usage of the codes, and eventually expose the constants to the user land when they are stable enough. PR-URL: https://github.com/nodejs/node/pull/44746 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com>
635 lines
21 KiB
C++
635 lines
21 KiB
C++
#include "async_wrap-inl.h"
|
|
#include "base_object-inl.h"
|
|
#include "debug_utils-inl.h"
|
|
#include "env-inl.h"
|
|
#include "memory_tracker-inl.h"
|
|
#include "node.h"
|
|
#include "node_errors.h"
|
|
#include "node_external_reference.h"
|
|
#include "node_internals.h"
|
|
#include "node_process-inl.h"
|
|
#include "util-inl.h"
|
|
#include "uv.h"
|
|
#include "v8-fast-api-calls.h"
|
|
#include "v8.h"
|
|
|
|
#include <vector>
|
|
|
|
#if HAVE_INSPECTOR
|
|
#include "inspector_io.h"
|
|
#endif
|
|
|
|
#include <climits> // PATH_MAX
|
|
#include <cstdio>
|
|
|
|
#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
|
|
#include <termios.h> // tcgetattr, tcsetattr
|
|
#endif
|
|
|
|
namespace node {
|
|
|
|
using v8::Array;
|
|
using v8::ArrayBuffer;
|
|
using v8::CFunction;
|
|
using v8::Context;
|
|
using v8::Float64Array;
|
|
using v8::FunctionCallbackInfo;
|
|
using v8::HeapStatistics;
|
|
using v8::Integer;
|
|
using v8::Isolate;
|
|
using v8::Local;
|
|
using v8::Maybe;
|
|
using v8::NewStringType;
|
|
using v8::Number;
|
|
using v8::Object;
|
|
using v8::String;
|
|
using v8::Uint32;
|
|
using v8::Value;
|
|
|
|
namespace per_process {
|
|
Mutex umask_mutex;
|
|
} // namespace per_process
|
|
|
|
// Microseconds in a second, as a float, used in CPUUsage() below
|
|
#define MICROS_PER_SEC 1e6
|
|
// used in Hrtime() and Uptime() below
|
|
#define NANOS_PER_SEC 1000000000
|
|
|
|
static void Abort(const FunctionCallbackInfo<Value>& args) {
|
|
Abort();
|
|
}
|
|
|
|
// For internal testing only, not exposed to userland.
|
|
static void CauseSegfault(const FunctionCallbackInfo<Value>& args) {
|
|
// This should crash hard all platforms.
|
|
volatile void** d = static_cast<volatile void**>(nullptr);
|
|
*d = nullptr;
|
|
}
|
|
|
|
static void Chdir(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
CHECK(env->owns_process_state());
|
|
|
|
CHECK_EQ(args.Length(), 1);
|
|
CHECK(args[0]->IsString());
|
|
Utf8Value path(env->isolate(), args[0]);
|
|
int err = uv_chdir(*path);
|
|
if (err) {
|
|
// Also include the original working directory, since that will usually
|
|
// be helpful information when debugging a `chdir()` failure.
|
|
char buf[PATH_MAX_BYTES];
|
|
size_t cwd_len = sizeof(buf);
|
|
uv_cwd(buf, &cwd_len);
|
|
return env->ThrowUVException(err, "chdir", nullptr, buf, *path);
|
|
}
|
|
}
|
|
|
|
inline Local<ArrayBuffer> get_fields_array_buffer(
|
|
const FunctionCallbackInfo<Value>& args,
|
|
size_t index,
|
|
size_t array_length) {
|
|
CHECK(args[index]->IsFloat64Array());
|
|
Local<Float64Array> arr = args[index].As<Float64Array>();
|
|
CHECK_EQ(arr->Length(), array_length);
|
|
return arr->Buffer();
|
|
}
|
|
|
|
// CPUUsage use libuv's uv_getrusage() this-process resource usage accessor,
|
|
// to access ru_utime (user CPU time used) and ru_stime (system CPU time used),
|
|
// 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.
|
|
static void CPUUsage(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
uv_rusage_t rusage;
|
|
|
|
// Call libuv to get the values we'll return.
|
|
int err = uv_getrusage(&rusage);
|
|
if (err)
|
|
return env->ThrowUVException(err, "uv_getrusage");
|
|
|
|
// Get the double array pointer from the Float64Array argument.
|
|
Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 2);
|
|
double* fields = static_cast<double*>(ab->Data());
|
|
|
|
// Set the Float64Array elements to be user / system values in microseconds.
|
|
fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
|
|
fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
|
|
}
|
|
|
|
static void Cwd(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
CHECK(env->has_run_bootstrapping_code());
|
|
char buf[PATH_MAX_BYTES];
|
|
size_t cwd_len = sizeof(buf);
|
|
int err = uv_cwd(buf, &cwd_len);
|
|
if (err)
|
|
return env->ThrowUVException(err, "uv_cwd");
|
|
|
|
Local<String> cwd = String::NewFromUtf8(env->isolate(),
|
|
buf,
|
|
NewStringType::kNormal,
|
|
cwd_len).ToLocalChecked();
|
|
args.GetReturnValue().Set(cwd);
|
|
}
|
|
|
|
static void Kill(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
Local<Context> context = env->context();
|
|
|
|
if (args.Length() < 2) {
|
|
THROW_ERR_MISSING_ARGS(env, "Bad argument.");
|
|
}
|
|
|
|
int pid;
|
|
if (!args[0]->Int32Value(context).To(&pid)) return;
|
|
int sig;
|
|
if (!args[1]->Int32Value(context).To(&sig)) return;
|
|
|
|
uv_pid_t own_pid = uv_os_getpid();
|
|
if (sig > 0 &&
|
|
(pid == 0 || pid == -1 || pid == own_pid || pid == -own_pid) &&
|
|
!HasSignalJSHandler(sig)) {
|
|
// This is most likely going to terminate this process.
|
|
// It's not an exact method but it might be close enough.
|
|
RunAtExit(env);
|
|
}
|
|
|
|
int err = uv_kill(pid, sig);
|
|
args.GetReturnValue().Set(err);
|
|
}
|
|
|
|
static void Rss(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
size_t rss;
|
|
int err = uv_resident_set_memory(&rss);
|
|
if (err)
|
|
return env->ThrowUVException(err, "uv_resident_set_memory");
|
|
|
|
args.GetReturnValue().Set(static_cast<double>(rss));
|
|
}
|
|
|
|
static void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
Isolate* isolate = env->isolate();
|
|
// V8 memory usage
|
|
HeapStatistics v8_heap_stats;
|
|
isolate->GetHeapStatistics(&v8_heap_stats);
|
|
|
|
NodeArrayBufferAllocator* array_buffer_allocator =
|
|
env->isolate_data()->node_allocator();
|
|
|
|
// Get the double array pointer from the Float64Array argument.
|
|
Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 5);
|
|
double* fields = static_cast<double*>(ab->Data());
|
|
|
|
size_t rss;
|
|
int err = uv_resident_set_memory(&rss);
|
|
if (err)
|
|
return env->ThrowUVException(err, "uv_resident_set_memory");
|
|
|
|
fields[0] = static_cast<double>(rss);
|
|
fields[1] = static_cast<double>(v8_heap_stats.total_heap_size());
|
|
fields[2] = static_cast<double>(v8_heap_stats.used_heap_size());
|
|
fields[3] = static_cast<double>(v8_heap_stats.external_memory());
|
|
fields[4] =
|
|
array_buffer_allocator == nullptr
|
|
? 0
|
|
: static_cast<double>(array_buffer_allocator->total_mem_usage());
|
|
}
|
|
|
|
void RawDebug(const FunctionCallbackInfo<Value>& args) {
|
|
CHECK(args.Length() == 1 && args[0]->IsString() &&
|
|
"must be called with a single string");
|
|
Utf8Value message(args.GetIsolate(), args[0]);
|
|
FPrintF(stderr, "%s\n", message);
|
|
fflush(stderr);
|
|
}
|
|
|
|
static void Umask(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
CHECK(env->has_run_bootstrapping_code());
|
|
CHECK_EQ(args.Length(), 1);
|
|
CHECK(args[0]->IsUndefined() || args[0]->IsUint32());
|
|
Mutex::ScopedLock scoped_lock(per_process::umask_mutex);
|
|
|
|
uint32_t old;
|
|
if (args[0]->IsUndefined()) {
|
|
old = umask(0);
|
|
umask(static_cast<mode_t>(old));
|
|
} else {
|
|
int oct = args[0].As<Uint32>()->Value();
|
|
old = umask(static_cast<mode_t>(oct));
|
|
}
|
|
|
|
args.GetReturnValue().Set(old);
|
|
}
|
|
|
|
static void Uptime(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
uv_update_time(env->event_loop());
|
|
double uptime =
|
|
static_cast<double>(uv_hrtime() - per_process::node_start_time);
|
|
Local<Number> result = Number::New(env->isolate(), uptime / NANOS_PER_SEC);
|
|
args.GetReturnValue().Set(result);
|
|
}
|
|
|
|
static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
std::vector<Local<Value>> request_v;
|
|
for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) {
|
|
AsyncWrap* w = req_wrap->GetAsyncWrap();
|
|
if (w->persistent().IsEmpty())
|
|
continue;
|
|
request_v.emplace_back(w->GetOwner());
|
|
}
|
|
|
|
args.GetReturnValue().Set(
|
|
Array::New(env->isolate(), request_v.data(), request_v.size()));
|
|
}
|
|
|
|
static void GetActiveRequestsInfo(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
std::vector<Local<Value>> requests_info;
|
|
for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) {
|
|
AsyncWrap* w = req_wrap->GetAsyncWrap();
|
|
if (w->persistent().IsEmpty()) continue;
|
|
requests_info.emplace_back(OneByteString(env->isolate(),
|
|
w->MemoryInfoName().c_str()));
|
|
}
|
|
|
|
args.GetReturnValue().Set(
|
|
Array::New(env->isolate(), requests_info.data(), requests_info.size()));
|
|
}
|
|
|
|
// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
|
|
// implemented here for consistency with GetActiveRequests().
|
|
void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
std::vector<Local<Value>> handle_v;
|
|
for (auto w : *env->handle_wrap_queue()) {
|
|
if (!HandleWrap::HasRef(w))
|
|
continue;
|
|
handle_v.emplace_back(w->GetOwner());
|
|
}
|
|
args.GetReturnValue().Set(
|
|
Array::New(env->isolate(), handle_v.data(), handle_v.size()));
|
|
}
|
|
|
|
void GetActiveHandlesInfo(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
std::vector<Local<Value>> handles_info;
|
|
for (HandleWrap* w : *env->handle_wrap_queue()) {
|
|
if (w->persistent().IsEmpty() || !HandleWrap::HasRef(w)) continue;
|
|
handles_info.emplace_back(OneByteString(env->isolate(),
|
|
w->MemoryInfoName().c_str()));
|
|
}
|
|
|
|
args.GetReturnValue().Set(
|
|
Array::New(env->isolate(), handles_info.data(), handles_info.size()));
|
|
}
|
|
|
|
static void ResourceUsage(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
uv_rusage_t rusage;
|
|
int err = uv_getrusage(&rusage);
|
|
if (err)
|
|
return env->ThrowUVException(err, "uv_getrusage");
|
|
|
|
Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 16);
|
|
double* fields = static_cast<double*>(ab->Data());
|
|
|
|
fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
|
|
fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
|
|
fields[2] = static_cast<double>(rusage.ru_maxrss);
|
|
fields[3] = static_cast<double>(rusage.ru_ixrss);
|
|
fields[4] = static_cast<double>(rusage.ru_idrss);
|
|
fields[5] = static_cast<double>(rusage.ru_isrss);
|
|
fields[6] = static_cast<double>(rusage.ru_minflt);
|
|
fields[7] = static_cast<double>(rusage.ru_majflt);
|
|
fields[8] = static_cast<double>(rusage.ru_nswap);
|
|
fields[9] = static_cast<double>(rusage.ru_inblock);
|
|
fields[10] = static_cast<double>(rusage.ru_oublock);
|
|
fields[11] = static_cast<double>(rusage.ru_msgsnd);
|
|
fields[12] = static_cast<double>(rusage.ru_msgrcv);
|
|
fields[13] = static_cast<double>(rusage.ru_nsignals);
|
|
fields[14] = static_cast<double>(rusage.ru_nvcsw);
|
|
fields[15] = static_cast<double>(rusage.ru_nivcsw);
|
|
}
|
|
|
|
#ifdef __POSIX__
|
|
static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
if (args.Length() < 1) {
|
|
return THROW_ERR_MISSING_ARGS(env, "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) {
|
|
return THROW_ERR_MISSING_ARGS(env, "Invalid number of arguments.");
|
|
}
|
|
|
|
HANDLE process = nullptr;
|
|
HANDLE thread = nullptr;
|
|
HANDLE mapping = nullptr;
|
|
wchar_t mapping_name[32];
|
|
LPTHREAD_START_ROUTINE* handler = nullptr;
|
|
DWORD pid = 0;
|
|
|
|
auto cleanup = OnScopeLeave([&]() {
|
|
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 = static_cast<DWORD>(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 ReallyExit(const FunctionCallbackInfo<Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
RunAtExit(env);
|
|
ExitCode code = ExitCode::kNoFailure;
|
|
Maybe<int32_t> code_int = args[0]->Int32Value(env->context());
|
|
if (!code_int.IsNothing()) {
|
|
code = static_cast<ExitCode>(code_int.FromJust());
|
|
}
|
|
env->Exit(code);
|
|
}
|
|
|
|
namespace process {
|
|
|
|
BindingData::BindingData(Environment* env, v8::Local<v8::Object> object)
|
|
: SnapshotableObject(env, object, type_int) {
|
|
Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), kBufferSize);
|
|
array_buffer_.Reset(env->isolate(), ab);
|
|
object
|
|
->Set(env->context(),
|
|
FIXED_ONE_BYTE_STRING(env->isolate(), "hrtimeBuffer"),
|
|
ab)
|
|
.ToChecked();
|
|
backing_store_ = ab->GetBackingStore();
|
|
}
|
|
|
|
v8::CFunction BindingData::fast_number_(v8::CFunction::Make(FastNumber));
|
|
v8::CFunction BindingData::fast_bigint_(v8::CFunction::Make(FastBigInt));
|
|
|
|
void BindingData::AddMethods() {
|
|
Local<Context> ctx = env()->context();
|
|
SetFastMethod(ctx, object(), "hrtime", SlowNumber, &fast_number_);
|
|
SetFastMethod(ctx, object(), "hrtimeBigInt", SlowBigInt, &fast_bigint_);
|
|
}
|
|
|
|
void BindingData::RegisterExternalReferences(
|
|
ExternalReferenceRegistry* registry) {
|
|
registry->Register(SlowNumber);
|
|
registry->Register(SlowBigInt);
|
|
registry->Register(FastNumber);
|
|
registry->Register(FastBigInt);
|
|
registry->Register(fast_number_.GetTypeInfo());
|
|
registry->Register(fast_bigint_.GetTypeInfo());
|
|
}
|
|
|
|
BindingData* BindingData::FromV8Value(Local<Value> value) {
|
|
Local<Object> v8_object = value.As<Object>();
|
|
return static_cast<BindingData*>(
|
|
v8_object->GetAlignedPointerFromInternalField(BaseObject::kSlot));
|
|
}
|
|
|
|
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
|
|
tracker->TrackField("array_buffer", array_buffer_);
|
|
}
|
|
|
|
// This is the legacy version of hrtime before BigInt was introduced in
|
|
// JavaScript.
|
|
// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
|
|
// so this function instead fills in an Uint32Array with 3 entries,
|
|
// to avoid any integer overflow possibility.
|
|
// The first two entries contain the second part of the value
|
|
// 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 BindingData::NumberImpl(BindingData* receiver) {
|
|
// Make sure we don't accidentally access buffers wiped for snapshot.
|
|
CHECK(!receiver->array_buffer_.IsEmpty());
|
|
uint64_t t = uv_hrtime();
|
|
uint32_t* fields = static_cast<uint32_t*>(receiver->backing_store_->Data());
|
|
fields[0] = (t / NANOS_PER_SEC) >> 32;
|
|
fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
|
|
fields[2] = t % NANOS_PER_SEC;
|
|
}
|
|
|
|
void BindingData::BigIntImpl(BindingData* receiver) {
|
|
// Make sure we don't accidentally access buffers wiped for snapshot.
|
|
CHECK(!receiver->array_buffer_.IsEmpty());
|
|
uint64_t t = uv_hrtime();
|
|
uint64_t* fields = static_cast<uint64_t*>(receiver->backing_store_->Data());
|
|
fields[0] = t;
|
|
}
|
|
|
|
void BindingData::SlowBigInt(const FunctionCallbackInfo<Value>& args) {
|
|
BigIntImpl(FromJSObject<BindingData>(args.Holder()));
|
|
}
|
|
|
|
void BindingData::SlowNumber(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
NumberImpl(FromJSObject<BindingData>(args.Holder()));
|
|
}
|
|
|
|
bool BindingData::PrepareForSerialization(Local<Context> context,
|
|
v8::SnapshotCreator* creator) {
|
|
// It's not worth keeping.
|
|
// Release it, we will recreate it when the instance is dehydrated.
|
|
array_buffer_.Reset();
|
|
// Return true because we need to maintain the reference to the binding from
|
|
// JS land.
|
|
return true;
|
|
}
|
|
|
|
InternalFieldInfoBase* BindingData::Serialize(int index) {
|
|
DCHECK_EQ(index, BaseObject::kEmbedderType);
|
|
InternalFieldInfo* info =
|
|
InternalFieldInfoBase::New<InternalFieldInfo>(type());
|
|
return info;
|
|
}
|
|
|
|
void BindingData::Deserialize(Local<Context> context,
|
|
Local<Object> holder,
|
|
int index,
|
|
InternalFieldInfoBase* info) {
|
|
DCHECK_EQ(index, BaseObject::kEmbedderType);
|
|
v8::HandleScope scope(context->GetIsolate());
|
|
Environment* env = Environment::GetCurrent(context);
|
|
// Recreate the buffer in the constructor.
|
|
BindingData* binding = env->AddBindingData<BindingData>(context, holder);
|
|
CHECK_NOT_NULL(binding);
|
|
}
|
|
|
|
static void Initialize(Local<Object> target,
|
|
Local<Value> unused,
|
|
Local<Context> context,
|
|
void* priv) {
|
|
Environment* env = Environment::GetCurrent(context);
|
|
BindingData* const binding_data =
|
|
env->AddBindingData<BindingData>(context, target);
|
|
if (binding_data == nullptr) return;
|
|
binding_data->AddMethods();
|
|
|
|
// define various internal methods
|
|
if (env->owns_process_state()) {
|
|
SetMethod(context, target, "_debugProcess", DebugProcess);
|
|
SetMethod(context, target, "abort", Abort);
|
|
SetMethod(context, target, "causeSegfault", CauseSegfault);
|
|
SetMethod(context, target, "chdir", Chdir);
|
|
}
|
|
|
|
SetMethod(context, target, "umask", Umask);
|
|
SetMethod(context, target, "memoryUsage", MemoryUsage);
|
|
SetMethod(context, target, "rss", Rss);
|
|
SetMethod(context, target, "cpuUsage", CPUUsage);
|
|
SetMethod(context, target, "resourceUsage", ResourceUsage);
|
|
|
|
SetMethod(context, target, "_debugEnd", DebugEnd);
|
|
SetMethod(context, target, "_getActiveRequestsInfo", GetActiveRequestsInfo);
|
|
SetMethod(context, target, "_getActiveRequests", GetActiveRequests);
|
|
SetMethod(context, target, "_getActiveHandles", GetActiveHandles);
|
|
SetMethod(context, target, "_getActiveHandlesInfo", GetActiveHandlesInfo);
|
|
SetMethod(context, target, "_kill", Kill);
|
|
SetMethod(context, target, "_rawDebug", RawDebug);
|
|
|
|
SetMethodNoSideEffect(context, target, "cwd", Cwd);
|
|
SetMethod(context, target, "dlopen", binding::DLOpen);
|
|
SetMethod(context, target, "reallyExit", ReallyExit);
|
|
SetMethodNoSideEffect(context, target, "uptime", Uptime);
|
|
SetMethod(context, target, "patchProcessObject", PatchProcessObject);
|
|
}
|
|
|
|
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
|
BindingData::RegisterExternalReferences(registry);
|
|
|
|
registry->Register(DebugProcess);
|
|
registry->Register(DebugEnd);
|
|
registry->Register(Abort);
|
|
registry->Register(CauseSegfault);
|
|
registry->Register(Chdir);
|
|
|
|
registry->Register(Umask);
|
|
registry->Register(RawDebug);
|
|
registry->Register(MemoryUsage);
|
|
registry->Register(Rss);
|
|
registry->Register(CPUUsage);
|
|
registry->Register(ResourceUsage);
|
|
|
|
registry->Register(GetActiveRequests);
|
|
registry->Register(GetActiveRequestsInfo);
|
|
registry->Register(GetActiveHandles);
|
|
registry->Register(GetActiveHandlesInfo);
|
|
registry->Register(Kill);
|
|
|
|
registry->Register(Cwd);
|
|
registry->Register(binding::DLOpen);
|
|
registry->Register(ReallyExit);
|
|
registry->Register(Uptime);
|
|
registry->Register(PatchProcessObject);
|
|
}
|
|
|
|
} // namespace process
|
|
} // namespace node
|
|
|
|
NODE_MODULE_CONTEXT_AWARE_INTERNAL(process_methods, node::process::Initialize)
|
|
NODE_MODULE_EXTERNAL_REFERENCE(process_methods,
|
|
node::process::RegisterExternalReferences)
|