Files
node/src/node_process.cc
James M Snell eaaee92d9b src: move DebugPortGetter/Setter to node_process.cc
PR-URL: https://github.com/nodejs/node/pull/22758
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Refael Ackermann <refack@gmail.com>
2018-09-14 19:02:45 +02:00

875 lines
24 KiB
C++

#include "node.h"
#include "node_internals.h"
#include "base_object.h"
#include "base_object-inl.h"
#include "env-inl.h"
#include "util-inl.h"
#include "uv.h"
#include "v8.h"
#if HAVE_INSPECTOR
#include "inspector_io.h"
#endif
#include <limits.h> // PATH_MAX
#include <stdio.h>
#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
#include <unistd.h> // setuid, getuid
#endif
#if defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__)
#include <pwd.h> // getpwnam()
#include <grp.h> // getgrnam()
#endif
#ifdef __APPLE__
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#elif !defined(_MSC_VER)
extern char **environ;
#endif
namespace node {
using v8::Array;
using v8::ArrayBuffer;
using v8::BigUint64Array;
using v8::Boolean;
using v8::Context;
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::Number;
using v8::PropertyCallbackInfo;
using v8::String;
using v8::Uint32;
using v8::Uint32Array;
using v8::Value;
Mutex process_mutex;
Mutex environ_mutex;
// Microseconds in a second, as a float, used in CPUUsage() below
#define MICROS_PER_SEC 1e6
// used in Hrtime() below
#define NANOS_PER_SEC 1000000000
#ifdef _WIN32
/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
#define CHDIR_BUFSIZE (MAX_PATH * 4)
#else
#define CHDIR_BUFSIZE (PATH_MAX)
#endif
void Abort(const FunctionCallbackInfo<Value>& args) {
Abort();
}
void Chdir(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(env->is_main_thread());
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[CHDIR_BUFSIZE];
size_t cwd_len = sizeof(buf);
uv_cwd(buf, &cwd_len);
return env->ThrowUVException(err, "chdir", nullptr, buf, *path);
}
}
// 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.
void CPUUsage(const FunctionCallbackInfo<Value>& args) {
uv_rusage_t rusage;
// Call libuv to get the values we'll return.
int err = uv_getrusage(&rusage);
if (err) {
// On error, return the strerror version of the error code.
Local<String> errmsg = OneByteString(args.GetIsolate(), uv_strerror(err));
return args.GetReturnValue().Set(errmsg);
}
// Get the double array pointer from the Float64Array argument.
CHECK(args[0]->IsFloat64Array());
Local<Float64Array> array = args[0].As<Float64Array>();
CHECK_EQ(array->Length(), 2);
Local<ArrayBuffer> ab = array->Buffer();
double* fields = static_cast<double*>(ab->GetContents().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;
}
void Cwd(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
char buf[CHDIR_BUFSIZE];
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,
v8::NewStringType::kNormal,
cwd_len).ToLocalChecked();
args.GetReturnValue().Set(cwd);
}
// Hrtime exposes libuv's uv_hrtime() high-resolution timer.
// 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 Hrtime(const FunctionCallbackInfo<Value>& args) {
uint64_t t = uv_hrtime();
Local<ArrayBuffer> ab = args[0].As<Uint32Array>()->Buffer();
uint32_t* fields = static_cast<uint32_t*>(ab->GetContents().Data());
fields[0] = (t / NANOS_PER_SEC) >> 32;
fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
fields[2] = t % NANOS_PER_SEC;
}
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) {
Environment* env = Environment::GetCurrent(args);
Local<Context> context = env->context();
if (args.Length() != 2)
return env->ThrowError("Bad argument.");
int pid;
if (!args[0]->Int32Value(context).To(&pid)) return;
int sig;
if (!args[1]->Int32Value(context).To(&sig)) return;
int err = uv_kill(pid, sig);
args.GetReturnValue().Set(err);
}
void MemoryUsage(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");
Isolate* isolate = env->isolate();
// V8 memory usage
HeapStatistics v8_heap_stats;
isolate->GetHeapStatistics(&v8_heap_stats);
// Get the double array pointer from the Float64Array argument.
CHECK(args[0]->IsFloat64Array());
Local<Float64Array> array = args[0].As<Float64Array>();
CHECK_EQ(array->Length(), 4);
Local<ArrayBuffer> ab = array->Buffer();
double* fields = static_cast<double*>(ab->GetContents().Data());
fields[0] = rss;
fields[1] = v8_heap_stats.total_heap_size();
fields[2] = v8_heap_stats.used_heap_size();
fields[3] = isolate->AdjustAmountOfExternalAllocatedMemory(0);
}
// Most of the time, it's best to use `console.error` to write
// to the process.stderr stream. However, in some cases, such as
// when debugging the stream.Writable class or the process.nextTick
// function, it is useful to bypass JavaScript entirely.
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]);
PrintErrorString("%s\n", *message);
fflush(stderr);
}
void StartProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
env->StartProfilerIdleNotifier();
}
void StopProfilerIdleNotifier(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
env->StopProfilerIdleNotifier();
}
void Umask(const FunctionCallbackInfo<Value>& args) {
uint32_t old;
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsUndefined() || args[0]->IsUint32());
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);
}
void Uptime(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
double uptime;
uv_update_time(env->event_loop());
uptime = uv_now(env->event_loop()) - prog_start_time;
args.GetReturnValue().Set(Number::New(env->isolate(), uptime / 1000));
}
#if defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__)
static const uid_t uid_not_found = static_cast<uid_t>(-1);
static const gid_t gid_not_found = static_cast<gid_t>(-1);
static uid_t uid_by_name(const char* name) {
struct passwd pwd;
struct passwd* pp;
char buf[8192];
errno = 0;
pp = nullptr;
if (getpwnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != nullptr)
return pp->pw_uid;
return uid_not_found;
}
static char* name_by_uid(uid_t uid) {
struct passwd pwd;
struct passwd* pp;
char buf[8192];
int rc;
errno = 0;
pp = nullptr;
if ((rc = getpwuid_r(uid, &pwd, buf, sizeof(buf), &pp)) == 0 &&
pp != nullptr) {
return strdup(pp->pw_name);
}
if (rc == 0)
errno = ENOENT;
return nullptr;
}
static gid_t gid_by_name(const char* name) {
struct group pwd;
struct group* pp;
char buf[8192];
errno = 0;
pp = nullptr;
if (getgrnam_r(name, &pwd, buf, sizeof(buf), &pp) == 0 && pp != nullptr)
return pp->gr_gid;
return gid_not_found;
}
#if 0 // For future use.
static const char* name_by_gid(gid_t gid) {
struct group pwd;
struct group* pp;
char buf[8192];
int rc;
errno = 0;
pp = nullptr;
if ((rc = getgrgid_r(gid, &pwd, buf, sizeof(buf), &pp)) == 0 &&
pp != nullptr) {
return strdup(pp->gr_name);
}
if (rc == 0)
errno = ENOENT;
return nullptr;
}
#endif
static uid_t uid_by_name(Isolate* isolate, Local<Value> value) {
if (value->IsUint32()) {
return static_cast<uid_t>(value.As<Uint32>()->Value());
} else {
Utf8Value name(isolate, value);
return uid_by_name(*name);
}
}
static gid_t gid_by_name(Isolate* isolate, Local<Value> value) {
if (value->IsUint32()) {
return static_cast<gid_t>(value.As<Uint32>()->Value());
} else {
Utf8Value name(isolate, value);
return gid_by_name(*name);
}
}
void GetUid(const FunctionCallbackInfo<Value>& args) {
// uid_t is an uint32_t on all supported platforms.
args.GetReturnValue().Set(static_cast<uint32_t>(getuid()));
}
void GetGid(const FunctionCallbackInfo<Value>& args) {
// gid_t is an uint32_t on all supported platforms.
args.GetReturnValue().Set(static_cast<uint32_t>(getgid()));
}
void GetEUid(const FunctionCallbackInfo<Value>& args) {
// uid_t is an uint32_t on all supported platforms.
args.GetReturnValue().Set(static_cast<uint32_t>(geteuid()));
}
void GetEGid(const FunctionCallbackInfo<Value>& args) {
// gid_t is an uint32_t on all supported platforms.
args.GetReturnValue().Set(static_cast<uint32_t>(getegid()));
}
void SetGid(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(env->is_main_thread());
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsUint32() || args[0]->IsString());
gid_t gid = gid_by_name(env->isolate(), args[0]);
if (gid == gid_not_found) {
// Tells JS to throw ERR_INVALID_CREDENTIAL
args.GetReturnValue().Set(1);
} else if (setgid(gid)) {
env->ThrowErrnoException(errno, "setgid");
} else {
args.GetReturnValue().Set(0);
}
}
void SetEGid(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(env->is_main_thread());
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsUint32() || args[0]->IsString());
gid_t gid = gid_by_name(env->isolate(), args[0]);
if (gid == gid_not_found) {
// Tells JS to throw ERR_INVALID_CREDENTIAL
args.GetReturnValue().Set(1);
} else if (setegid(gid)) {
env->ThrowErrnoException(errno, "setegid");
} else {
args.GetReturnValue().Set(0);
}
}
void SetUid(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(env->is_main_thread());
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsUint32() || args[0]->IsString());
uid_t uid = uid_by_name(env->isolate(), args[0]);
if (uid == uid_not_found) {
// Tells JS to throw ERR_INVALID_CREDENTIAL
args.GetReturnValue().Set(1);
} else if (setuid(uid)) {
env->ThrowErrnoException(errno, "setuid");
} else {
args.GetReturnValue().Set(0);
}
}
void SetEUid(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(env->is_main_thread());
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsUint32() || args[0]->IsString());
uid_t uid = uid_by_name(env->isolate(), args[0]);
if (uid == uid_not_found) {
// Tells JS to throw ERR_INVALID_CREDENTIAL
args.GetReturnValue().Set(1);
} else if (seteuid(uid)) {
env->ThrowErrnoException(errno, "seteuid");
} else {
args.GetReturnValue().Set(0);
}
}
void GetGroups(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
int ngroups = getgroups(0, nullptr);
if (ngroups == -1)
return env->ThrowErrnoException(errno, "getgroups");
gid_t* groups = new gid_t[ngroups];
ngroups = getgroups(ngroups, groups);
if (ngroups == -1) {
delete[] groups;
return env->ThrowErrnoException(errno, "getgroups");
}
Local<Array> groups_list = Array::New(env->isolate(), ngroups);
bool seen_egid = false;
gid_t egid = getegid();
for (int i = 0; i < ngroups; i++) {
groups_list->Set(i, Integer::New(env->isolate(), groups[i]));
if (groups[i] == egid)
seen_egid = true;
}
delete[] groups;
if (seen_egid == false)
groups_list->Set(ngroups, Integer::New(env->isolate(), egid));
args.GetReturnValue().Set(groups_list);
}
void SetGroups(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsArray());
Local<Array> groups_list = args[0].As<Array>();
size_t size = groups_list->Length();
gid_t* groups = new gid_t[size];
for (size_t i = 0; i < size; i++) {
gid_t gid = gid_by_name(env->isolate(), groups_list->Get(i));
if (gid == gid_not_found) {
delete[] groups;
// Tells JS to throw ERR_INVALID_CREDENTIAL
args.GetReturnValue().Set(static_cast<uint32_t>(i + 1));
return;
}
groups[i] = gid;
}
int rc = setgroups(size, groups);
delete[] groups;
if (rc == -1)
return env->ThrowErrnoException(errno, "setgroups");
args.GetReturnValue().Set(0);
}
void InitGroups(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK_EQ(args.Length(), 2);
CHECK(args[0]->IsUint32() || args[0]->IsString());
CHECK(args[1]->IsUint32() || args[1]->IsString());
Utf8Value arg0(env->isolate(), args[0]);
gid_t extra_group;
bool must_free;
char* user;
if (args[0]->IsUint32()) {
user = name_by_uid(args[0].As<Uint32>()->Value());
must_free = true;
} else {
user = *arg0;
must_free = false;
}
if (user == nullptr) {
// Tells JS to throw ERR_INVALID_CREDENTIAL
return args.GetReturnValue().Set(1);
}
extra_group = gid_by_name(env->isolate(), args[1]);
if (extra_group == gid_not_found) {
if (must_free)
free(user);
// Tells JS to throw ERR_INVALID_CREDENTIAL
return args.GetReturnValue().Set(2);
}
int rc = initgroups(user, extra_group);
if (must_free)
free(user);
if (rc)
return env->ThrowErrnoException(errno, "initgroups");
args.GetReturnValue().Set(0);
}
#endif // __POSIX__ && !defined(__ANDROID__) && !defined(__CloudABI__)
void ProcessTitleGetter(Local<Name> property,
const PropertyCallbackInfo<Value>& info) {
char buffer[512];
uv_get_process_title(buffer, sizeof(buffer));
info.GetReturnValue().Set(String::NewFromUtf8(info.GetIsolate(), buffer,
v8::NewStringType::kNormal).ToLocalChecked());
}
void ProcessTitleSetter(Local<Name> property,
Local<Value> value,
const PropertyCallbackInfo<void>& info) {
node::Utf8Value title(info.GetIsolate(), value);
TRACE_EVENT_METADATA1("__metadata", "process_name", "name",
TRACE_STR_COPY(*title));
uv_set_process_title(*title);
}
void EnvGetter(Local<Name> property,
const PropertyCallbackInfo<Value>& info) {
Isolate* isolate = info.GetIsolate();
if (property->IsSymbol()) {
return info.GetReturnValue().SetUndefined();
}
Mutex::ScopedLock lock(environ_mutex);
#ifdef __POSIX__
node::Utf8Value key(isolate, property);
const char* val = getenv(*key);
if (val) {
return info.GetReturnValue().Set(String::NewFromUtf8(isolate, val,
v8::NewStringType::kNormal).ToLocalChecked());
}
#else // _WIN32
node::TwoByteValue key(isolate, property);
WCHAR buffer[32767]; // The maximum size allowed for environment variables.
SetLastError(ERROR_SUCCESS);
DWORD result = GetEnvironmentVariableW(reinterpret_cast<WCHAR*>(*key),
buffer,
arraysize(buffer));
// If result >= sizeof buffer the buffer was too small. That should never
// happen. If result == 0 and result != ERROR_SUCCESS the variable was not
// found.
if ((result > 0 || GetLastError() == ERROR_SUCCESS) &&
result < arraysize(buffer)) {
const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(buffer);
Local<String> rc = String::NewFromTwoByte(isolate, two_byte_buffer);
return info.GetReturnValue().Set(rc);
}
#endif
}
void EnvSetter(Local<Name> property,
Local<Value> value,
const PropertyCallbackInfo<Value>& info) {
Environment* env = Environment::GetCurrent(info);
if (env->options()->pending_deprecation && env->EmitProcessEnvWarning() &&
!value->IsString() && !value->IsNumber() && !value->IsBoolean()) {
if (ProcessEmitDeprecationWarning(
env,
"Assigning any value other than a string, number, or boolean to a "
"process.env property is deprecated. Please make sure to convert the "
"value to a string before setting process.env with it.",
"DEP0104").IsNothing())
return;
}
Mutex::ScopedLock lock(environ_mutex);
#ifdef __POSIX__
node::Utf8Value key(info.GetIsolate(), property);
node::Utf8Value val(info.GetIsolate(), value);
setenv(*key, *val, 1);
#else // _WIN32
node::TwoByteValue key(info.GetIsolate(), property);
node::TwoByteValue val(info.GetIsolate(), value);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
// Environment variables that start with '=' are read-only.
if (key_ptr[0] != L'=') {
SetEnvironmentVariableW(key_ptr, reinterpret_cast<WCHAR*>(*val));
}
#endif
// Whether it worked or not, always return value.
info.GetReturnValue().Set(value);
}
void EnvQuery(Local<Name> property, const PropertyCallbackInfo<Integer>& info) {
Mutex::ScopedLock lock(environ_mutex);
int32_t rc = -1; // Not found unless proven otherwise.
if (property->IsString()) {
#ifdef __POSIX__
node::Utf8Value key(info.GetIsolate(), property);
if (getenv(*key))
rc = 0;
#else // _WIN32
node::TwoByteValue key(info.GetIsolate(), property);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
SetLastError(ERROR_SUCCESS);
if (GetEnvironmentVariableW(key_ptr, nullptr, 0) > 0 ||
GetLastError() == ERROR_SUCCESS) {
rc = 0;
if (key_ptr[0] == L'=') {
// Environment variables that start with '=' are hidden and read-only.
rc = static_cast<int32_t>(v8::ReadOnly) |
static_cast<int32_t>(v8::DontDelete) |
static_cast<int32_t>(v8::DontEnum);
}
}
#endif
}
if (rc != -1)
info.GetReturnValue().Set(rc);
}
void EnvDeleter(Local<Name> property,
const PropertyCallbackInfo<Boolean>& info) {
Mutex::ScopedLock lock(environ_mutex);
if (property->IsString()) {
#ifdef __POSIX__
node::Utf8Value key(info.GetIsolate(), property);
unsetenv(*key);
#else
node::TwoByteValue key(info.GetIsolate(), property);
WCHAR* key_ptr = reinterpret_cast<WCHAR*>(*key);
SetEnvironmentVariableW(key_ptr, nullptr);
#endif
}
// process.env never has non-configurable properties, so always
// return true like the tc39 delete operator.
info.GetReturnValue().Set(true);
}
void EnvEnumerator(const PropertyCallbackInfo<Array>& info) {
Environment* env = Environment::GetCurrent(info);
Isolate* isolate = env->isolate();
Local<Context> ctx = env->context();
Local<Function> fn = env->push_values_to_array_function();
Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
size_t idx = 0;
Mutex::ScopedLock lock(environ_mutex);
#ifdef __POSIX__
int size = 0;
while (environ[size])
size++;
Local<Array> envarr = Array::New(isolate);
for (int i = 0; i < size; ++i) {
const char* var = environ[i];
const char* s = strchr(var, '=');
const int length = s ? s - var : strlen(var);
argv[idx] = String::NewFromUtf8(isolate,
var,
v8::NewStringType::kNormal,
length).ToLocalChecked();
if (++idx >= arraysize(argv)) {
fn->Call(ctx, envarr, idx, argv).ToLocalChecked();
idx = 0;
}
}
if (idx > 0) {
fn->Call(ctx, envarr, idx, argv).ToLocalChecked();
}
#else // _WIN32
WCHAR* environment = GetEnvironmentStringsW();
if (environment == nullptr)
return; // This should not happen.
Local<Array> envarr = Array::New(isolate);
WCHAR* p = environment;
while (*p) {
WCHAR* s;
if (*p == L'=') {
// If the key starts with '=' it is a hidden environment variable.
p += wcslen(p) + 1;
continue;
} else {
s = wcschr(p, L'=');
}
if (!s) {
s = p + wcslen(p);
}
const uint16_t* two_byte_buffer = reinterpret_cast<const uint16_t*>(p);
const size_t two_byte_buffer_len = s - p;
argv[idx] = String::NewFromTwoByte(isolate,
two_byte_buffer,
String::kNormalString,
two_byte_buffer_len);
if (++idx >= arraysize(argv)) {
fn->Call(ctx, envarr, idx, argv).ToLocalChecked();
idx = 0;
}
p = s + wcslen(s) + 1;
}
if (idx > 0) {
fn->Call(ctx, envarr, idx, argv).ToLocalChecked();
}
FreeEnvironmentStringsW(environment);
#endif
info.GetReturnValue().Set(envarr);
}
void GetParentProcessId(Local<Name> property,
const PropertyCallbackInfo<Value>& info) {
info.GetReturnValue().Set(Integer::New(info.GetIsolate(), uv_os_getppid()));
}
void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Local<Array> ary = Array::New(args.GetIsolate());
Local<Context> ctx = env->context();
Local<Function> fn = env->push_values_to_array_function();
Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
size_t idx = 0;
for (auto w : *env->req_wrap_queue()) {
if (w->persistent().IsEmpty())
continue;
argv[idx] = w->GetOwner();
if (++idx >= arraysize(argv)) {
fn->Call(ctx, ary, idx, argv).ToLocalChecked();
idx = 0;
}
}
if (idx > 0) {
fn->Call(ctx, ary, idx, argv).ToLocalChecked();
}
args.GetReturnValue().Set(ary);
}
// 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);
Local<Array> ary = Array::New(env->isolate());
Local<Context> ctx = env->context();
Local<Function> fn = env->push_values_to_array_function();
Local<Value> argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
size_t idx = 0;
for (auto w : *env->handle_wrap_queue()) {
if (!HandleWrap::HasRef(w))
continue;
argv[idx] = w->GetOwner();
if (++idx >= arraysize(argv)) {
fn->Call(ctx, ary, idx, argv).ToLocalChecked();
idx = 0;
}
}
if (idx > 0) {
fn->Call(ctx, ary, idx, argv).ToLocalChecked();
}
args.GetReturnValue().Set(ary);
}
void DebugPortGetter(Local<Name> property,
const PropertyCallbackInfo<Value>& info) {
Environment* env = Environment::GetCurrent(info);
Mutex::ScopedLock lock(process_mutex);
int port = env->options()->debug_options->port();
#if HAVE_INSPECTOR
if (port == 0) {
if (auto io = env->inspector_agent()->io())
port = io->port();
}
#endif // HAVE_INSPECTOR
info.GetReturnValue().Set(port);
}
void DebugPortSetter(Local<Name> property,
Local<Value> value,
const PropertyCallbackInfo<void>& info) {
Environment* env = Environment::GetCurrent(info);
Mutex::ScopedLock lock(process_mutex);
env->options()->debug_options->host_port.port =
value->Int32Value(env->context()).FromMaybe(0);
}
} // namespace node