1#include "async_wrap-inl.h"
2#include "base_object-inl.h"
3#include "debug_utils-inl.h"
4#include "env-inl.h"
5#include "memory_tracker-inl.h"
6#include "node.h"
7#include "node_errors.h"
8#include "node_external_reference.h"
9#include "node_internals.h"
10#include "node_process-inl.h"
11#include "util-inl.h"
12#include "uv.h"
13#include "v8-fast-api-calls.h"
14#include "v8.h"
15
16#include <vector>
17
18#if HAVE_INSPECTOR
19#include "inspector_io.h"
20#endif
21
22#include <climits>  // PATH_MAX
23#include <cstdio>
24
25#if defined(_MSC_VER)
26#include <direct.h>
27#include <io.h>
28#define umask _umask
29typedef int mode_t;
30#else
31#include <pthread.h>
32#include <sys/resource.h>  // getrlimit, setrlimit
33#include <termios.h>  // tcgetattr, tcsetattr
34#endif
35
36namespace node {
37
38using v8::Array;
39using v8::ArrayBuffer;
40using v8::CFunction;
41using v8::Context;
42using v8::Float64Array;
43using v8::FunctionCallbackInfo;
44using v8::HeapStatistics;
45using v8::Integer;
46using v8::Isolate;
47using v8::Local;
48using v8::NewStringType;
49using v8::Number;
50using v8::Object;
51using v8::String;
52using v8::Uint32;
53using v8::Value;
54
55namespace per_process {
56Mutex umask_mutex;
57}   // namespace per_process
58
59// Microseconds in a second, as a float, used in CPUUsage() below
60#define MICROS_PER_SEC 1e6
61// used in Hrtime() and Uptime() below
62#define NANOS_PER_SEC 1000000000
63
64static void Abort(const FunctionCallbackInfo<Value>& args) {
65  Abort();
66}
67
68// For internal testing only, not exposed to userland.
69static void CauseSegfault(const FunctionCallbackInfo<Value>& args) {
70  // This should crash hard all platforms.
71  volatile void** d = static_cast<volatile void**>(nullptr);
72  *d = nullptr;
73}
74
75static void Chdir(const FunctionCallbackInfo<Value>& args) {
76  Environment* env = Environment::GetCurrent(args);
77  CHECK(env->owns_process_state());
78
79  CHECK_EQ(args.Length(), 1);
80  CHECK(args[0]->IsString());
81  Utf8Value path(env->isolate(), args[0]);
82  int err = uv_chdir(*path);
83  if (err) {
84    // Also include the original working directory, since that will usually
85    // be helpful information when debugging a `chdir()` failure.
86    char buf[PATH_MAX_BYTES];
87    size_t cwd_len = sizeof(buf);
88    uv_cwd(buf, &cwd_len);
89    return env->ThrowUVException(err, "chdir", nullptr, buf, *path);
90  }
91}
92
93inline Local<ArrayBuffer> get_fields_array_buffer(
94    const FunctionCallbackInfo<Value>& args,
95    size_t index,
96    size_t array_length) {
97  CHECK(args[index]->IsFloat64Array());
98  Local<Float64Array> arr = args[index].As<Float64Array>();
99  CHECK_EQ(arr->Length(), array_length);
100  return arr->Buffer();
101}
102
103// CPUUsage use libuv's uv_getrusage() this-process resource usage accessor,
104// to access ru_utime (user CPU time used) and ru_stime (system CPU time used),
105// which are uv_timeval_t structs (long tv_sec, long tv_usec).
106// Returns those values as Float64 microseconds in the elements of the array
107// passed to the function.
108static void CPUUsage(const FunctionCallbackInfo<Value>& args) {
109  Environment* env = Environment::GetCurrent(args);
110  uv_rusage_t rusage;
111
112  // Call libuv to get the values we'll return.
113  int err = uv_getrusage(&rusage);
114  if (err)
115    return env->ThrowUVException(err, "uv_getrusage");
116
117  // Get the double array pointer from the Float64Array argument.
118  Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 2);
119  double* fields = static_cast<double*>(ab->Data());
120
121  // Set the Float64Array elements to be user / system values in microseconds.
122  fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
123  fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
124}
125
126static void Cwd(const FunctionCallbackInfo<Value>& args) {
127  Environment* env = Environment::GetCurrent(args);
128  CHECK(env->has_run_bootstrapping_code());
129  char buf[PATH_MAX_BYTES];
130  size_t cwd_len = sizeof(buf);
131  int err = uv_cwd(buf, &cwd_len);
132  if (err)
133    return env->ThrowUVException(err, "uv_cwd");
134
135  Local<String> cwd = String::NewFromUtf8(env->isolate(),
136                                          buf,
137                                          NewStringType::kNormal,
138                                          cwd_len).ToLocalChecked();
139  args.GetReturnValue().Set(cwd);
140}
141
142static void Kill(const FunctionCallbackInfo<Value>& args) {
143  Environment* env = Environment::GetCurrent(args);
144  Local<Context> context = env->context();
145
146  if (args.Length() < 2) {
147    THROW_ERR_MISSING_ARGS(env, "Bad argument.");
148  }
149
150  int pid;
151  if (!args[0]->Int32Value(context).To(&pid)) return;
152  int sig;
153  if (!args[1]->Int32Value(context).To(&sig)) return;
154
155  uv_pid_t own_pid = uv_os_getpid();
156  if (sig > 0 &&
157      (pid == 0 || pid == -1 || pid == own_pid || pid == -own_pid) &&
158      !HasSignalJSHandler(sig)) {
159    // This is most likely going to terminate this process.
160    // It's not an exact method but it might be close enough.
161    RunAtExit(env);
162  }
163
164  int err = uv_kill(pid, sig);
165  args.GetReturnValue().Set(err);
166}
167
168static void Rss(const FunctionCallbackInfo<Value>& args) {
169  Environment* env = Environment::GetCurrent(args);
170
171  size_t rss;
172  int err = uv_resident_set_memory(&rss);
173  if (err)
174    return env->ThrowUVException(err, "uv_resident_set_memory");
175
176  args.GetReturnValue().Set(static_cast<double>(rss));
177}
178
179static void MemoryUsage(const FunctionCallbackInfo<Value>& args) {
180  Environment* env = Environment::GetCurrent(args);
181
182  Isolate* isolate = env->isolate();
183  // V8 memory usage
184  HeapStatistics v8_heap_stats;
185  isolate->GetHeapStatistics(&v8_heap_stats);
186
187  NodeArrayBufferAllocator* array_buffer_allocator =
188      env->isolate_data()->node_allocator();
189
190  // Get the double array pointer from the Float64Array argument.
191  Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 5);
192  double* fields = static_cast<double*>(ab->Data());
193
194  size_t rss;
195  int err = uv_resident_set_memory(&rss);
196  if (err)
197    return env->ThrowUVException(err, "uv_resident_set_memory");
198
199  fields[0] = static_cast<double>(rss);
200  fields[1] = static_cast<double>(v8_heap_stats.total_heap_size());
201  fields[2] = static_cast<double>(v8_heap_stats.used_heap_size());
202  fields[3] = static_cast<double>(v8_heap_stats.external_memory());
203  fields[4] =
204      array_buffer_allocator == nullptr
205          ? 0
206          : static_cast<double>(array_buffer_allocator->total_mem_usage());
207}
208
209static void GetConstrainedMemory(const FunctionCallbackInfo<Value>& args) {
210  uint64_t value = uv_get_constrained_memory();
211  if (value != 0) {
212    args.GetReturnValue().Set(static_cast<double>(value));
213  }
214}
215
216void RawDebug(const FunctionCallbackInfo<Value>& args) {
217  CHECK(args.Length() == 1 && args[0]->IsString() &&
218        "must be called with a single string");
219  Utf8Value message(args.GetIsolate(), args[0]);
220  FPrintF(stderr, "%s\n", message);
221  fflush(stderr);
222}
223
224static void Umask(const FunctionCallbackInfo<Value>& args) {
225  Environment* env = Environment::GetCurrent(args);
226  CHECK(env->has_run_bootstrapping_code());
227  CHECK_EQ(args.Length(), 1);
228  CHECK(args[0]->IsUndefined() || args[0]->IsUint32());
229  Mutex::ScopedLock scoped_lock(per_process::umask_mutex);
230
231  uint32_t old;
232  if (args[0]->IsUndefined()) {
233    old = umask(0);
234    umask(static_cast<mode_t>(old));
235  } else {
236    int oct = args[0].As<Uint32>()->Value();
237    old = umask(static_cast<mode_t>(oct));
238  }
239
240  args.GetReturnValue().Set(old);
241}
242
243static void Uptime(const FunctionCallbackInfo<Value>& args) {
244  Environment* env = Environment::GetCurrent(args);
245
246  uv_update_time(env->event_loop());
247  double uptime =
248      static_cast<double>(uv_hrtime() - per_process::node_start_time);
249  Local<Number> result = Number::New(env->isolate(), uptime / NANOS_PER_SEC);
250  args.GetReturnValue().Set(result);
251}
252
253static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
254  Environment* env = Environment::GetCurrent(args);
255
256  std::vector<Local<Value>> request_v;
257  for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) {
258    AsyncWrap* w = req_wrap->GetAsyncWrap();
259    if (w->persistent().IsEmpty())
260      continue;
261    request_v.emplace_back(w->GetOwner());
262  }
263
264  args.GetReturnValue().Set(
265      Array::New(env->isolate(), request_v.data(), request_v.size()));
266}
267
268// Non-static, friend of HandleWrap. Could have been a HandleWrap method but
269// implemented here for consistency with GetActiveRequests().
270void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
271  Environment* env = Environment::GetCurrent(args);
272
273  std::vector<Local<Value>> handle_v;
274  for (auto w : *env->handle_wrap_queue()) {
275    if (!HandleWrap::HasRef(w))
276      continue;
277    handle_v.emplace_back(w->GetOwner());
278  }
279  args.GetReturnValue().Set(
280      Array::New(env->isolate(), handle_v.data(), handle_v.size()));
281}
282
283static void GetActiveResourcesInfo(const FunctionCallbackInfo<Value>& args) {
284  Environment* env = Environment::GetCurrent(args);
285  std::vector<Local<Value>> resources_info;
286
287  // Active requests
288  for (ReqWrapBase* req_wrap : *env->req_wrap_queue()) {
289    AsyncWrap* w = req_wrap->GetAsyncWrap();
290    if (w->persistent().IsEmpty()) continue;
291    resources_info.emplace_back(
292        OneByteString(env->isolate(), w->MemoryInfoName()));
293  }
294
295  // Active handles
296  for (HandleWrap* w : *env->handle_wrap_queue()) {
297    if (w->persistent().IsEmpty() || !HandleWrap::HasRef(w)) continue;
298    resources_info.emplace_back(
299        OneByteString(env->isolate(), w->MemoryInfoName()));
300  }
301
302  // Active timeouts
303  resources_info.insert(resources_info.end(),
304                        env->timeout_info()[0],
305                        OneByteString(env->isolate(), "Timeout"));
306
307  // Active immediates
308  resources_info.insert(resources_info.end(),
309                        env->immediate_info()->ref_count(),
310                        OneByteString(env->isolate(), "Immediate"));
311
312  args.GetReturnValue().Set(
313      Array::New(env->isolate(), resources_info.data(), resources_info.size()));
314}
315
316static void ResourceUsage(const FunctionCallbackInfo<Value>& args) {
317  Environment* env = Environment::GetCurrent(args);
318
319  uv_rusage_t rusage;
320  int err = uv_getrusage(&rusage);
321  if (err)
322    return env->ThrowUVException(err, "uv_getrusage");
323
324  Local<ArrayBuffer> ab = get_fields_array_buffer(args, 0, 16);
325  double* fields = static_cast<double*>(ab->Data());
326
327  fields[0] = MICROS_PER_SEC * rusage.ru_utime.tv_sec + rusage.ru_utime.tv_usec;
328  fields[1] = MICROS_PER_SEC * rusage.ru_stime.tv_sec + rusage.ru_stime.tv_usec;
329  fields[2] = static_cast<double>(rusage.ru_maxrss);
330  fields[3] = static_cast<double>(rusage.ru_ixrss);
331  fields[4] = static_cast<double>(rusage.ru_idrss);
332  fields[5] = static_cast<double>(rusage.ru_isrss);
333  fields[6] = static_cast<double>(rusage.ru_minflt);
334  fields[7] = static_cast<double>(rusage.ru_majflt);
335  fields[8] = static_cast<double>(rusage.ru_nswap);
336  fields[9] = static_cast<double>(rusage.ru_inblock);
337  fields[10] = static_cast<double>(rusage.ru_oublock);
338  fields[11] = static_cast<double>(rusage.ru_msgsnd);
339  fields[12] = static_cast<double>(rusage.ru_msgrcv);
340  fields[13] = static_cast<double>(rusage.ru_nsignals);
341  fields[14] = static_cast<double>(rusage.ru_nvcsw);
342  fields[15] = static_cast<double>(rusage.ru_nivcsw);
343}
344
345#ifdef __POSIX__
346static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
347  Environment* env = Environment::GetCurrent(args);
348
349  if (args.Length() < 1) {
350    return THROW_ERR_MISSING_ARGS(env, "Invalid number of arguments.");
351  }
352
353  CHECK(args[0]->IsNumber());
354  pid_t pid = args[0].As<Integer>()->Value();
355  int r = kill(pid, SIGUSR1);
356
357  if (r != 0) {
358    return env->ThrowErrnoException(errno, "kill");
359  }
360}
361#endif  // __POSIX__
362
363#ifdef _WIN32
364static int GetDebugSignalHandlerMappingName(DWORD pid,
365                                            wchar_t* buf,
366                                            size_t buf_len) {
367  return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
368}
369
370static void DebugProcess(const FunctionCallbackInfo<Value>& args) {
371  Environment* env = Environment::GetCurrent(args);
372  Isolate* isolate = args.GetIsolate();
373
374  if (args.Length() < 1) {
375    return THROW_ERR_MISSING_ARGS(env, "Invalid number of arguments.");
376  }
377
378  HANDLE process = nullptr;
379  HANDLE thread = nullptr;
380  HANDLE mapping = nullptr;
381  wchar_t mapping_name[32];
382  LPTHREAD_START_ROUTINE* handler = nullptr;
383  DWORD pid = 0;
384
385  auto cleanup = OnScopeLeave([&]() {
386    if (process != nullptr) CloseHandle(process);
387    if (thread != nullptr) CloseHandle(thread);
388    if (handler != nullptr) UnmapViewOfFile(handler);
389    if (mapping != nullptr) CloseHandle(mapping);
390  });
391
392  CHECK(args[0]->IsNumber());
393  pid = static_cast<DWORD>(args[0].As<Integer>()->Value());
394
395  process =
396      OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
397                      PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
398                  FALSE,
399                  pid);
400  if (process == nullptr) {
401    isolate->ThrowException(
402        WinapiErrnoException(isolate, GetLastError(), "OpenProcess"));
403    return;
404  }
405
406  if (GetDebugSignalHandlerMappingName(
407          pid, mapping_name, arraysize(mapping_name)) < 0) {
408    env->ThrowErrnoException(errno, "sprintf");
409    return;
410  }
411
412  mapping = OpenFileMappingW(FILE_MAP_READ, FALSE, mapping_name);
413  if (mapping == nullptr) {
414    isolate->ThrowException(
415        WinapiErrnoException(isolate, GetLastError(), "OpenFileMappingW"));
416    return;
417  }
418
419  handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
420      MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, sizeof *handler));
421  if (handler == nullptr || *handler == nullptr) {
422    isolate->ThrowException(
423        WinapiErrnoException(isolate, GetLastError(), "MapViewOfFile"));
424    return;
425  }
426
427  thread =
428      CreateRemoteThread(process, nullptr, 0, *handler, nullptr, 0, nullptr);
429  if (thread == nullptr) {
430    isolate->ThrowException(
431        WinapiErrnoException(isolate, GetLastError(), "CreateRemoteThread"));
432    return;
433  }
434
435  // Wait for the thread to terminate
436  if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
437    isolate->ThrowException(
438        WinapiErrnoException(isolate, GetLastError(), "WaitForSingleObject"));
439    return;
440  }
441}
442#endif  // _WIN32
443
444static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
445#if HAVE_INSPECTOR
446  Environment* env = Environment::GetCurrent(args);
447  if (env->inspector_agent()->IsListening()) {
448    env->inspector_agent()->Stop();
449  }
450#endif
451}
452
453static void ReallyExit(const FunctionCallbackInfo<Value>& args) {
454  Environment* env = Environment::GetCurrent(args);
455  RunAtExit(env);
456  int code = args[0]->Int32Value(env->context()).FromMaybe(0);
457  env->Exit(code);
458}
459
460namespace process {
461
462BindingData::BindingData(Realm* realm, v8::Local<v8::Object> object)
463    : SnapshotableObject(realm, object, type_int) {
464  Isolate* isolate = realm->isolate();
465  Local<Context> context = realm->context();
466  Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, kBufferSize);
467  array_buffer_.Reset(isolate, ab);
468  object->Set(context, FIXED_ONE_BYTE_STRING(isolate, "hrtimeBuffer"), ab)
469      .ToChecked();
470  backing_store_ = ab->GetBackingStore();
471}
472
473v8::CFunction BindingData::fast_number_(v8::CFunction::Make(FastNumber));
474v8::CFunction BindingData::fast_bigint_(v8::CFunction::Make(FastBigInt));
475
476void BindingData::AddMethods() {
477  Local<Context> ctx = env()->context();
478  SetFastMethodNoSideEffect(ctx, object(), "hrtime", SlowNumber, &fast_number_);
479  SetFastMethodNoSideEffect(
480      ctx, object(), "hrtimeBigInt", SlowBigInt, &fast_bigint_);
481}
482
483void BindingData::RegisterExternalReferences(
484    ExternalReferenceRegistry* registry) {
485  registry->Register(SlowNumber);
486  registry->Register(SlowBigInt);
487  registry->Register(FastNumber);
488  registry->Register(FastBigInt);
489  registry->Register(fast_number_.GetTypeInfo());
490  registry->Register(fast_bigint_.GetTypeInfo());
491}
492
493BindingData* BindingData::FromV8Value(Local<Value> value) {
494  Local<Object> v8_object = value.As<Object>();
495  return static_cast<BindingData*>(
496      v8_object->GetAlignedPointerFromInternalField(BaseObject::kSlot));
497}
498
499void BindingData::MemoryInfo(MemoryTracker* tracker) const {
500  tracker->TrackField("array_buffer", array_buffer_);
501}
502
503// This is the legacy version of hrtime before BigInt was introduced in
504// JavaScript.
505// The value returned by uv_hrtime() is a 64-bit int representing nanoseconds,
506// so this function instead fills in an Uint32Array with 3 entries,
507// to avoid any integer overflow possibility.
508// The first two entries contain the second part of the value
509// broken into the upper/lower 32 bits to be converted back in JS,
510// because there is no Uint64Array in JS.
511// The third entry contains the remaining nanosecond part of the value.
512void BindingData::NumberImpl(BindingData* receiver) {
513  // Make sure we don't accidentally access buffers wiped for snapshot.
514  CHECK(!receiver->array_buffer_.IsEmpty());
515  uint64_t t = uv_hrtime();
516  uint32_t* fields = static_cast<uint32_t*>(receiver->backing_store_->Data());
517  fields[0] = (t / NANOS_PER_SEC) >> 32;
518  fields[1] = (t / NANOS_PER_SEC) & 0xffffffff;
519  fields[2] = t % NANOS_PER_SEC;
520}
521
522void BindingData::BigIntImpl(BindingData* receiver) {
523  // Make sure we don't accidentally access buffers wiped for snapshot.
524  CHECK(!receiver->array_buffer_.IsEmpty());
525  uint64_t t = uv_hrtime();
526  uint64_t* fields = static_cast<uint64_t*>(receiver->backing_store_->Data());
527  fields[0] = t;
528}
529
530void BindingData::SlowBigInt(const FunctionCallbackInfo<Value>& args) {
531  BigIntImpl(FromJSObject<BindingData>(args.Holder()));
532}
533
534void BindingData::SlowNumber(const v8::FunctionCallbackInfo<v8::Value>& args) {
535  NumberImpl(FromJSObject<BindingData>(args.Holder()));
536}
537
538bool BindingData::PrepareForSerialization(Local<Context> context,
539                                          v8::SnapshotCreator* creator) {
540  // It's not worth keeping.
541  // Release it, we will recreate it when the instance is dehydrated.
542  array_buffer_.Reset();
543  // Return true because we need to maintain the reference to the binding from
544  // JS land.
545  return true;
546}
547
548InternalFieldInfoBase* BindingData::Serialize(int index) {
549  DCHECK_EQ(index, BaseObject::kEmbedderType);
550  InternalFieldInfo* info =
551      InternalFieldInfoBase::New<InternalFieldInfo>(type());
552  return info;
553}
554
555void BindingData::Deserialize(Local<Context> context,
556                              Local<Object> holder,
557                              int index,
558                              InternalFieldInfoBase* info) {
559  DCHECK_EQ(index, BaseObject::kEmbedderType);
560  v8::HandleScope scope(context->GetIsolate());
561  Realm* realm = Realm::GetCurrent(context);
562  // Recreate the buffer in the constructor.
563  BindingData* binding = realm->AddBindingData<BindingData>(context, holder);
564  CHECK_NOT_NULL(binding);
565}
566
567static void Initialize(Local<Object> target,
568                       Local<Value> unused,
569                       Local<Context> context,
570                       void* priv) {
571  Realm* realm = Realm::GetCurrent(context);
572  Environment* env = realm->env();
573  BindingData* const binding_data =
574      realm->AddBindingData<BindingData>(context, target);
575  if (binding_data == nullptr) return;
576  binding_data->AddMethods();
577
578  // define various internal methods
579  if (env->owns_process_state()) {
580    SetMethod(context, target, "_debugProcess", DebugProcess);
581    SetMethod(context, target, "abort", Abort);
582    SetMethod(context, target, "causeSegfault", CauseSegfault);
583    SetMethod(context, target, "chdir", Chdir);
584  }
585
586  SetMethod(context, target, "umask", Umask);
587  SetMethod(context, target, "memoryUsage", MemoryUsage);
588  SetMethod(context, target, "constrainedMemory", GetConstrainedMemory);
589  SetMethod(context, target, "rss", Rss);
590  SetMethod(context, target, "cpuUsage", CPUUsage);
591  SetMethod(context, target, "resourceUsage", ResourceUsage);
592
593  SetMethod(context, target, "_debugEnd", DebugEnd);
594  SetMethod(context, target, "_getActiveRequests", GetActiveRequests);
595  SetMethod(context, target, "_getActiveHandles", GetActiveHandles);
596  SetMethod(context, target, "getActiveResourcesInfo", GetActiveResourcesInfo);
597  SetMethod(context, target, "_kill", Kill);
598  SetMethod(context, target, "_rawDebug", RawDebug);
599
600  SetMethodNoSideEffect(context, target, "cwd", Cwd);
601  SetMethod(context, target, "dlopen", binding::DLOpen);
602  SetMethod(context, target, "reallyExit", ReallyExit);
603  SetMethodNoSideEffect(context, target, "uptime", Uptime);
604  SetMethod(context, target, "patchProcessObject", PatchProcessObject);
605}
606
607void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
608  BindingData::RegisterExternalReferences(registry);
609
610  registry->Register(DebugProcess);
611  registry->Register(DebugEnd);
612  registry->Register(Abort);
613  registry->Register(CauseSegfault);
614  registry->Register(Chdir);
615
616  registry->Register(Umask);
617  registry->Register(RawDebug);
618  registry->Register(MemoryUsage);
619  registry->Register(GetConstrainedMemory);
620  registry->Register(Rss);
621  registry->Register(CPUUsage);
622  registry->Register(ResourceUsage);
623
624  registry->Register(GetActiveRequests);
625  registry->Register(GetActiveHandles);
626  registry->Register(GetActiveResourcesInfo);
627  registry->Register(Kill);
628
629  registry->Register(Cwd);
630  registry->Register(binding::DLOpen);
631  registry->Register(ReallyExit);
632  registry->Register(Uptime);
633  registry->Register(PatchProcessObject);
634}
635
636}  // namespace process
637}  // namespace node
638
639NODE_BINDING_CONTEXT_AWARE_INTERNAL(process_methods, node::process::Initialize)
640NODE_BINDING_EXTERNAL_REFERENCE(process_methods,
641                                node::process::RegisterExternalReferences)
642