diff --git a/src/env-inl.h b/src/env-inl.h index 008e5103b16c6e..97642566763029 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -260,23 +260,6 @@ inline uv_idle_t* Environment::immediate_idle_handle() { return &immediate_idle_handle_; } -inline Environment* Environment::from_idle_prepare_handle( - uv_prepare_t* handle) { - return ContainerOf(&Environment::idle_prepare_handle_, handle); -} - -inline uv_prepare_t* Environment::idle_prepare_handle() { - return &idle_prepare_handle_; -} - -inline Environment* Environment::from_idle_check_handle(uv_check_t* handle) { - return ContainerOf(&Environment::idle_check_handle_, handle); -} - -inline uv_check_t* Environment::idle_check_handle() { - return &idle_check_handle_; -} - inline void Environment::RegisterHandleCleanup(uv_handle_t* handle, HandleCleanupCb cb, void *arg) { diff --git a/src/env.cc b/src/env.cc index 12be4866aac2d2..2598e775e8e240 100644 --- a/src/env.cc +++ b/src/env.cc @@ -1,6 +1,8 @@ #include "env.h" #include "env-inl.h" +#include "async-wrap.h" #include "v8.h" +#include "v8-profiler.h" #if defined(_MSC_VER) #define getpid GetCurrentProcessId @@ -12,6 +14,8 @@ namespace node { +using v8::Context; +using v8::FunctionTemplate; using v8::HandleScope; using v8::Local; using v8::Message; @@ -19,6 +23,92 @@ using v8::StackFrame; using v8::StackTrace; using v8::Value; +void Environment::Start(int argc, + const char* const* argv, + int exec_argc, + const char* const* exec_argv, + bool start_profiler_idle_notifier) { + HandleScope handle_scope(isolate()); + Context::Scope context_scope(context()); + + isolate()->SetAutorunMicrotasks(false); + + uv_check_init(event_loop(), immediate_check_handle()); + uv_unref(reinterpret_cast(immediate_check_handle())); + + uv_idle_init(event_loop(), immediate_idle_handle()); + + // Inform V8's CPU profiler when we're idle. The profiler is sampling-based + // but not all samples are created equal; mark the wall clock time spent in + // epoll_wait() and friends so profiling tools can filter it out. The samples + // still end up in v8.log but with state=IDLE rather than state=EXTERNAL. + // TODO(bnoordhuis) Depends on a libuv implementation detail that we should + // probably fortify in the API contract, namely that the last started prepare + // or check watcher runs first. It's not 100% foolproof; if an add-on starts + // a prepare or check watcher after us, any samples attributed to its callback + // will be recorded with state=IDLE. + uv_prepare_init(event_loop(), &idle_prepare_handle_); + uv_check_init(event_loop(), &idle_check_handle_); + uv_unref(reinterpret_cast(&idle_prepare_handle_)); + uv_unref(reinterpret_cast(&idle_check_handle_)); + + auto close_and_finish = [](Environment* env, uv_handle_t* handle, void* arg) { + handle->data = env; + + uv_close(handle, [](uv_handle_t* handle) { + static_cast(handle->data)->FinishHandleCleanup(handle); + }); + }; + + RegisterHandleCleanup( + reinterpret_cast(immediate_check_handle()), + close_and_finish, + nullptr); + RegisterHandleCleanup( + reinterpret_cast(immediate_idle_handle()), + close_and_finish, + nullptr); + RegisterHandleCleanup( + reinterpret_cast(&idle_prepare_handle_), + close_and_finish, + nullptr); + RegisterHandleCleanup( + reinterpret_cast(&idle_check_handle_), + close_and_finish, + nullptr); + + if (start_profiler_idle_notifier) { + StartProfilerIdleNotifier(); + } + + auto process_template = FunctionTemplate::New(isolate()); + process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate(), "process")); + + auto process_object = + process_template->GetFunction()->NewInstance(context()).ToLocalChecked(); + set_process_object(process_object); + + SetupProcessObject(this, argc, argv, exec_argc, exec_argv); + LoadAsyncWrapperInfo(this); +} + +void Environment::StartProfilerIdleNotifier() { + uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) { + Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle); + env->isolate()->GetCpuProfiler()->SetIdle(true); + }); + + uv_check_start(&idle_check_handle_, [](uv_check_t* handle) { + Environment* env = ContainerOf(&Environment::idle_check_handle_, handle); + env->isolate()->GetCpuProfiler()->SetIdle(false); + }); +} + +void Environment::StopProfilerIdleNotifier() { + uv_prepare_stop(&idle_prepare_handle_); + uv_check_stop(&idle_check_handle_); +} + void Environment::PrintSyncTrace() const { if (!trace_sync_io_) return; diff --git a/src/env.h b/src/env.h index d252e5db6ce264..afbc505ab8caf4 100644 --- a/src/env.h +++ b/src/env.h @@ -449,11 +449,19 @@ class Environment { // See CreateEnvironment() in src/node.cc. static inline Environment* New(IsolateData* isolate_data, v8::Local context); + void Start(int argc, + const char* const* argv, + int exec_argc, + const char* const* exec_argv, + bool start_profiler_idle_notifier); inline void CleanupHandles(); inline void Dispose(); void AssignToContext(v8::Local context); + void StartProfilerIdleNotifier(); + void StopProfilerIdleNotifier(); + inline v8::Isolate* isolate() const; inline uv_loop_t* event_loop() const; inline bool async_wrap_callbacks_enabled() const; @@ -464,12 +472,6 @@ class Environment { inline uv_check_t* immediate_check_handle(); inline uv_idle_t* immediate_idle_handle(); - static inline Environment* from_idle_prepare_handle(uv_prepare_t* handle); - inline uv_prepare_t* idle_prepare_handle(); - - static inline Environment* from_idle_check_handle(uv_check_t* handle); - inline uv_check_t* idle_check_handle(); - // Register clean-up cb to be called on env->Dispose() inline void RegisterHandleCleanup(uv_handle_t* handle, HandleCleanupCb cb, diff --git a/src/node.cc b/src/node.cc index 10d67a02fc92e2..2cbc5bf3fc25f6 100644 --- a/src/node.cc +++ b/src/node.cc @@ -101,7 +101,6 @@ using v8::Exception; using v8::Float64Array; using v8::Function; using v8::FunctionCallbackInfo; -using v8::FunctionTemplate; using v8::HandleScope; using v8::HeapStatistics; using v8::Integer; @@ -2864,39 +2863,15 @@ static void NeedImmediateCallbackSetter( } -void SetIdle(uv_prepare_t* handle) { - Environment* env = Environment::from_idle_prepare_handle(handle); - env->isolate()->GetCpuProfiler()->SetIdle(true); -} - - -void ClearIdle(uv_check_t* handle) { - Environment* env = Environment::from_idle_check_handle(handle); - env->isolate()->GetCpuProfiler()->SetIdle(false); -} - - -void StartProfilerIdleNotifier(Environment* env) { - uv_prepare_start(env->idle_prepare_handle(), SetIdle); - uv_check_start(env->idle_check_handle(), ClearIdle); -} - - -void StopProfilerIdleNotifier(Environment* env) { - uv_prepare_stop(env->idle_prepare_handle()); - uv_check_stop(env->idle_check_handle()); -} - - void StartProfilerIdleNotifier(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - StartProfilerIdleNotifier(env); + env->StartProfilerIdleNotifier(); } void StopProfilerIdleNotifier(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - StopProfilerIdleNotifier(env); + env->StopProfilerIdleNotifier(); } @@ -4262,20 +4237,6 @@ int EmitExit(Environment* env) { } -static void HandleCloseCb(uv_handle_t* handle) { - Environment* env = reinterpret_cast(handle->data); - env->FinishHandleCleanup(handle); -} - - -static void HandleCleanup(Environment* env, - uv_handle_t* handle, - void* arg) { - handle->data = env; - uv_close(handle, HandleCloseCb); -} - - IsolateData* CreateIsolateData(Isolate* isolate, uv_loop_t* loop) { return new IsolateData(isolate, loop); } @@ -4294,64 +4255,9 @@ Environment* CreateEnvironment(IsolateData* isolate_data, const char* const* exec_argv) { Isolate* isolate = context->GetIsolate(); HandleScope handle_scope(isolate); - Context::Scope context_scope(context); Environment* env = Environment::New(isolate_data, context); - - isolate->SetAutorunMicrotasks(false); - - uv_check_init(env->event_loop(), env->immediate_check_handle()); - uv_unref( - reinterpret_cast(env->immediate_check_handle())); - - uv_idle_init(env->event_loop(), env->immediate_idle_handle()); - - // Inform V8's CPU profiler when we're idle. The profiler is sampling-based - // but not all samples are created equal; mark the wall clock time spent in - // epoll_wait() and friends so profiling tools can filter it out. The samples - // still end up in v8.log but with state=IDLE rather than state=EXTERNAL. - // TODO(bnoordhuis) Depends on a libuv implementation detail that we should - // probably fortify in the API contract, namely that the last started prepare - // or check watcher runs first. It's not 100% foolproof; if an add-on starts - // a prepare or check watcher after us, any samples attributed to its callback - // will be recorded with state=IDLE. - uv_prepare_init(env->event_loop(), env->idle_prepare_handle()); - uv_check_init(env->event_loop(), env->idle_check_handle()); - uv_unref(reinterpret_cast(env->idle_prepare_handle())); - uv_unref(reinterpret_cast(env->idle_check_handle())); - - // Register handle cleanups - env->RegisterHandleCleanup( - reinterpret_cast(env->immediate_check_handle()), - HandleCleanup, - nullptr); - env->RegisterHandleCleanup( - reinterpret_cast(env->immediate_idle_handle()), - HandleCleanup, - nullptr); - env->RegisterHandleCleanup( - reinterpret_cast(env->idle_prepare_handle()), - HandleCleanup, - nullptr); - env->RegisterHandleCleanup( - reinterpret_cast(env->idle_check_handle()), - HandleCleanup, - nullptr); - - if (v8_is_profiling) { - StartProfilerIdleNotifier(env); - } - - Local process_template = FunctionTemplate::New(isolate); - process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "process")); - - Local process_object = - process_template->GetFunction()->NewInstance(context).ToLocalChecked(); - env->set_process_object(process_object); - - SetupProcessObject(env, argc, argv, exec_argc, exec_argv); - LoadAsyncWrapperInfo(env); - + env->Start(argc, argv, exec_argc, exec_argv, v8_is_profiling); return env; } diff --git a/src/node_internals.h b/src/node_internals.h index 56606613ddfeb9..695a95c5bf9fb6 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -145,6 +145,12 @@ NO_RETURN void FatalError(const char* location, const char* message); v8::Local BuildStatsObject(Environment* env, const uv_stat_t* s); +void SetupProcessObject(Environment* env, + int argc, + const char* const* argv, + int exec_argc, + const char* const* exec_argv); + enum Endianness { kLittleEndian, // _Not_ LITTLE_ENDIAN, clashes with endian.h. kBigEndian