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