Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
env.cc
Go to the documentation of this file.
1 #include "env.h"
2 #include "env-inl.h"
3 #include "async-wrap.h"
4 #include "v8.h"
5 #include "v8-profiler.h"
6 
7 #if defined(_MSC_VER)
8 #define getpid GetCurrentProcessId
9 #else
10 #include <unistd.h>
11 #endif
12 
13 #include <stdio.h>
14 #include <algorithm>
15 
16 namespace node {
17 
18 using v8::Context;
19 using v8::FunctionTemplate;
20 using v8::HandleScope;
21 using v8::Local;
22 using v8::Message;
23 using v8::StackFrame;
24 using v8::StackTrace;
25 
26 void Environment::Start(int argc,
27  const char* const* argv,
28  int exec_argc,
29  const char* const* exec_argv,
30  bool start_profiler_idle_notifier) {
31  HandleScope handle_scope(isolate());
32  Context::Scope context_scope(context());
33 
34  uv_check_init(event_loop(), immediate_check_handle());
35  uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
36 
37  uv_idle_init(event_loop(), immediate_idle_handle());
38 
39  // Inform V8's CPU profiler when we're idle. The profiler is sampling-based
40  // but not all samples are created equal; mark the wall clock time spent in
41  // epoll_wait() and friends so profiling tools can filter it out. The samples
42  // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
43  // TODO(bnoordhuis) Depends on a libuv implementation detail that we should
44  // probably fortify in the API contract, namely that the last started prepare
45  // or check watcher runs first. It's not 100% foolproof; if an add-on starts
46  // a prepare or check watcher after us, any samples attributed to its callback
47  // will be recorded with state=IDLE.
48  uv_prepare_init(event_loop(), &idle_prepare_handle_);
49  uv_check_init(event_loop(), &idle_check_handle_);
50  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
51  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
52 
53  uv_timer_init(event_loop(), destroy_ids_timer_handle());
54 
55  auto close_and_finish = [](Environment* env, uv_handle_t* handle, void* arg) {
56  handle->data = env;
57 
58  uv_close(handle, [](uv_handle_t* handle) {
59  static_cast<Environment*>(handle->data)->FinishHandleCleanup(handle);
60  });
61  };
62 
63  RegisterHandleCleanup(
64  reinterpret_cast<uv_handle_t*>(immediate_check_handle()),
65  close_and_finish,
66  nullptr);
67  RegisterHandleCleanup(
68  reinterpret_cast<uv_handle_t*>(immediate_idle_handle()),
69  close_and_finish,
70  nullptr);
71  RegisterHandleCleanup(
72  reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_),
73  close_and_finish,
74  nullptr);
75  RegisterHandleCleanup(
76  reinterpret_cast<uv_handle_t*>(&idle_check_handle_),
77  close_and_finish,
78  nullptr);
79  RegisterHandleCleanup(
80  reinterpret_cast<uv_handle_t*>(&destroy_ids_timer_handle_),
81  close_and_finish,
82  nullptr);
83 
84  if (start_profiler_idle_notifier) {
85  StartProfilerIdleNotifier();
86  }
87 
88  auto process_template = FunctionTemplate::New(isolate());
89  process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate(), "process"));
90 
91  auto process_object =
92  process_template->GetFunction()->NewInstance(context()).ToLocalChecked();
93  set_process_object(process_object);
94 
95  SetupProcessObject(this, argc, argv, exec_argc, exec_argv);
97 }
98 
99 void Environment::CleanupHandles() {
100  while (HandleCleanup* hc = handle_cleanup_queue_.PopFront()) {
101  handle_cleanup_waiting_++;
102  hc->cb_(this, hc->handle_, hc->arg_);
103  delete hc;
104  }
105 
106  while (handle_cleanup_waiting_ != 0)
107  uv_run(event_loop(), UV_RUN_ONCE);
108 }
109 
110 void Environment::StartProfilerIdleNotifier() {
111  uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
112  Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
113  env->isolate()->GetCpuProfiler()->SetIdle(true);
114  });
115 
116  uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
117  Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
118  env->isolate()->GetCpuProfiler()->SetIdle(false);
119  });
120 }
121 
122 void Environment::StopProfilerIdleNotifier() {
123  uv_prepare_stop(&idle_prepare_handle_);
124  uv_check_stop(&idle_check_handle_);
125 }
126 
127 void Environment::PrintSyncTrace() const {
128  if (!trace_sync_io_)
129  return;
130 
131  HandleScope handle_scope(isolate());
132  Local<v8::StackTrace> stack =
133  StackTrace::CurrentStackTrace(isolate(), 10, StackTrace::kDetailed);
134 
135  fprintf(stderr, "(node:%d) WARNING: Detected use of sync API\n", getpid());
136 
137  for (int i = 0; i < stack->GetFrameCount() - 1; i++) {
138  Local<StackFrame> stack_frame = stack->GetFrame(i);
139  node::Utf8Value fn_name_s(isolate(), stack_frame->GetFunctionName());
140  node::Utf8Value script_name(isolate(), stack_frame->GetScriptName());
141  const int line_number = stack_frame->GetLineNumber();
142  const int column = stack_frame->GetColumn();
143 
144  if (stack_frame->IsEval()) {
145  if (stack_frame->GetScriptId() == Message::kNoScriptIdInfo) {
146  fprintf(stderr, " at [eval]:%i:%i\n", line_number, column);
147  } else {
148  fprintf(stderr,
149  " at [eval] (%s:%i:%i)\n",
150  *script_name,
151  line_number,
152  column);
153  }
154  break;
155  }
156 
157  if (fn_name_s.length() == 0) {
158  fprintf(stderr, " at %s:%i:%i\n", *script_name, line_number, column);
159  } else {
160  fprintf(stderr,
161  " at %s (%s:%i:%i)\n",
162  *fn_name_s,
163  *script_name,
164  line_number,
165  column);
166  }
167  }
168  fflush(stderr);
169 }
170 
171 void Environment::RunAtExitCallbacks() {
172  for (AtExitCallback at_exit : at_exit_functions_) {
173  at_exit.cb_(at_exit.arg_);
174  }
175  at_exit_functions_.clear();
176 }
177 
178 void Environment::AtExit(void (*cb)(void* arg), void* arg) {
179  at_exit_functions_.push_back(AtExitCallback{cb, arg});
180 }
181 
183  auto it = std::find_if(
184  promise_hooks_.begin(), promise_hooks_.end(),
185  [&](const PromiseHookCallback& hook) {
186  return hook.cb_ == fn && hook.arg_ == arg;
187  });
188  if (it != promise_hooks_.end()) {
189  it->enable_count_++;
190  return;
191  }
192  promise_hooks_.push_back(PromiseHookCallback{fn, arg, 1});
193 
194  if (promise_hooks_.size() == 1) {
195  isolate_->SetPromiseHook(EnvPromiseHook);
196  }
197 }
198 
199 bool Environment::RemovePromiseHook(promise_hook_func fn, void* arg) {
200  auto it = std::find_if(
201  promise_hooks_.begin(), promise_hooks_.end(),
202  [&](const PromiseHookCallback& hook) {
203  return hook.cb_ == fn && hook.arg_ == arg;
204  });
205 
206  if (it == promise_hooks_.end()) return false;
207 
208  if (--it->enable_count_ > 0) return true;
209 
210  promise_hooks_.erase(it);
211  if (promise_hooks_.empty()) {
212  isolate_->SetPromiseHook(nullptr);
213  }
214 
215  return true;
216 }
217 
218 void Environment::EnvPromiseHook(v8::PromiseHookType type,
219  v8::Local<v8::Promise> promise,
220  v8::Local<v8::Value> parent) {
221  Environment* env = Environment::GetCurrent(promise->CreationContext());
222  for (const PromiseHookCallback& hook : env->promise_hooks_) {
223  hook.cb_(type, promise, parent, hook.arg_);
224  }
225 }
226 
227 } // namespace node
void AtExit(void(*cb)(void *arg), void *arg)
Definition: node.cc:4455
void AddPromiseHook(v8::Isolate *isolate, promise_hook_func fn, void *arg)
Definition: node.cc:1306
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
Definition: node_buffer.cc:241
void(* promise_hook_func)(v8::PromiseHookType type, v8::Local< v8::Promise > promise, v8::Local< v8::Value > parent, void *arg)
Definition: node.h:536
void SetupProcessObject(Environment *env, int argc, const char *const *argv, int exec_argc, const char *const *exec_argv)
Definition: node.cc:3167
void LoadAsyncWrapperInfo(Environment *env)
Definition: async-wrap.cc:587
int Start(Isolate *isolate, IsolateData *isolate_data, int argc, const char *const *argv, int exec_argc, const char *const *exec_argv)
Definition: node.cc:4536