• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "node.h"
2 #include "env-inl.h"
3 #include "debug_utils-inl.h"
4 
5 using v8::Context;
6 using v8::Function;
7 using v8::Global;
8 using v8::HandleScope;
9 using v8::Isolate;
10 using v8::Local;
11 using v8::Locker;
12 using v8::Maybe;
13 using v8::Nothing;
14 using v8::SealHandleScope;
15 using v8::TryCatch;
16 
17 namespace node {
18 
SpinEventLoop(Environment * env)19 Maybe<int> SpinEventLoop(Environment* env) {
20   CHECK_NOT_NULL(env);
21   MultiIsolatePlatform* platform = GetMultiIsolatePlatform(env);
22   CHECK_NOT_NULL(platform);
23 
24   Isolate* isolate = env->isolate();
25   HandleScope handle_scope(isolate);
26   Context::Scope context_scope(env->context());
27   SealHandleScope seal(isolate);
28 
29   if (env->is_stopping()) return Nothing<int>();
30 
31   env->set_trace_sync_io(env->options()->trace_sync_io);
32   {
33     bool more;
34     env->performance_state()->Mark(
35         node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
36     do {
37       if (env->is_stopping()) break;
38       uv_run(env->event_loop(), UV_RUN_DEFAULT);
39       if (env->is_stopping()) break;
40 
41       platform->DrainTasks(isolate);
42 
43       more = uv_loop_alive(env->event_loop());
44       if (more && !env->is_stopping()) continue;
45 
46       if (EmitProcessBeforeExit(env).IsNothing())
47         break;
48 
49       {
50         HandleScope handle_scope(isolate);
51         if (env->RunSnapshotSerializeCallback().IsEmpty()) {
52           break;
53         }
54       }
55 
56       // Emit `beforeExit` if the loop became alive either after emitting
57       // event, or after running some callbacks.
58       more = uv_loop_alive(env->event_loop());
59     } while (more == true && !env->is_stopping());
60     env->performance_state()->Mark(
61         node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
62   }
63   if (env->is_stopping()) return Nothing<int>();
64 
65   env->set_trace_sync_io(false);
66   // Clear the serialize callback even though the JS-land queue should
67   // be empty this point so that the deserialized instance won't
68   // attempt to call into JS again.
69   env->set_snapshot_serialize_callback(Local<Function>());
70 
71   env->PrintInfoForSnapshotIfDebug();
72   env->ForEachRealm([](Realm* realm) { realm->VerifyNoStrongBaseObjects(); });
73   return EmitProcessExit(env);
74 }
75 
76 struct CommonEnvironmentSetup::Impl {
77   MultiIsolatePlatform* platform = nullptr;
78   uv_loop_t loop;
79   std::shared_ptr<ArrayBufferAllocator> allocator;
80   Isolate* isolate = nullptr;
81   DeleteFnPtr<IsolateData, FreeIsolateData> isolate_data;
82   DeleteFnPtr<Environment, FreeEnvironment> env;
83   Global<Context> context;
84 };
85 
CommonEnvironmentSetup(MultiIsolatePlatform * platform,std::vector<std::string> * errors,std::function<Environment * (const CommonEnvironmentSetup *)> make_env)86 CommonEnvironmentSetup::CommonEnvironmentSetup(
87     MultiIsolatePlatform* platform,
88     std::vector<std::string>* errors,
89     std::function<Environment*(const CommonEnvironmentSetup*)> make_env)
90   : impl_(new Impl()) {
91   CHECK_NOT_NULL(platform);
92   CHECK_NOT_NULL(errors);
93 
94   impl_->platform = platform;
95   uv_loop_t* loop = &impl_->loop;
96   // Use `data` to tell the destructor whether the loop was initialized or not.
97   loop->data = nullptr;
98   int ret = uv_loop_init(loop);
99   if (ret != 0) {
100     errors->push_back(
101         SPrintF("Failed to initialize loop: %s", uv_err_name(ret)));
102     return;
103   }
104   loop->data = this;
105 
106   impl_->allocator = ArrayBufferAllocator::Create();
107   impl_->isolate = NewIsolate(impl_->allocator, &impl_->loop, platform);
108   Isolate* isolate = impl_->isolate;
109 
110   {
111     Locker locker(isolate);
112     Isolate::Scope isolate_scope(isolate);
113     HandleScope handle_scope(isolate);
114 
115     TryCatch bootstrapCatch(isolate);
116     auto print_Exception = OnScopeLeave([&]() {
117       if (bootstrapCatch.HasCaught()) {
118         errors->push_back(FormatCaughtException(
119             isolate, isolate->GetCurrentContext(), bootstrapCatch));
120       }
121     });
122 
123     impl_->isolate_data.reset(CreateIsolateData(
124         isolate, loop, platform, impl_->allocator.get()));
125 
126     Local<Context> context = NewContext(isolate);
127     impl_->context.Reset(isolate, context);
128     if (context.IsEmpty()) {
129       errors->push_back("Failed to initialize V8 Context");
130       return;
131     }
132 
133     Context::Scope context_scope(context);
134     impl_->env.reset(make_env(this));
135   }
136 }
137 
~CommonEnvironmentSetup()138 CommonEnvironmentSetup::~CommonEnvironmentSetup() {
139   if (impl_->isolate != nullptr) {
140     Isolate* isolate = impl_->isolate;
141     {
142       Locker locker(isolate);
143       Isolate::Scope isolate_scope(isolate);
144 
145       impl_->context.Reset();
146       impl_->env.reset();
147       impl_->isolate_data.reset();
148     }
149 
150     bool platform_finished = false;
151     impl_->platform->AddIsolateFinishedCallback(isolate, [](void* data) {
152       *static_cast<bool*>(data) = true;
153     }, &platform_finished);
154     impl_->platform->UnregisterIsolate(isolate);
155     isolate->Dispose();
156 
157     // Wait until the platform has cleaned up all relevant resources.
158     while (!platform_finished)
159       uv_run(&impl_->loop, UV_RUN_ONCE);
160   }
161 
162   if (impl_->isolate || impl_->loop.data != nullptr)
163     CheckedUvLoopClose(&impl_->loop);
164 
165   delete impl_;
166 }
167 
168 
event_loop() const169 uv_loop_t* CommonEnvironmentSetup::event_loop() const {
170   return &impl_->loop;
171 }
172 
173 std::shared_ptr<ArrayBufferAllocator>
array_buffer_allocator() const174 CommonEnvironmentSetup::array_buffer_allocator() const {
175   return impl_->allocator;
176 }
177 
isolate() const178 Isolate* CommonEnvironmentSetup::isolate() const {
179   return impl_->isolate;
180 }
181 
isolate_data() const182 IsolateData* CommonEnvironmentSetup::isolate_data() const {
183   return impl_->isolate_data.get();
184 }
185 
env() const186 Environment* CommonEnvironmentSetup::env() const {
187   return impl_->env.get();
188 }
189 
context() const190 v8::Local<v8::Context> CommonEnvironmentSetup::context() const {
191   return impl_->context.Get(impl_->isolate);
192 }
193 
194 }  // namespace node
195