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