1#include "node.h" 2#include "env-inl.h" 3#include "debug_utils-inl.h" 4 5using v8::Context; 6using v8::Function; 7using v8::Global; 8using v8::HandleScope; 9using v8::Isolate; 10using v8::Local; 11using v8::Locker; 12using v8::Maybe; 13using v8::Nothing; 14using v8::SealHandleScope; 15using v8::TryCatch; 16 17namespace node { 18 19Maybe<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 76struct 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 86CommonEnvironmentSetup::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 138CommonEnvironmentSetup::~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 169uv_loop_t* CommonEnvironmentSetup::event_loop() const { 170 return &impl_->loop; 171} 172 173std::shared_ptr<ArrayBufferAllocator> 174CommonEnvironmentSetup::array_buffer_allocator() const { 175 return impl_->allocator; 176} 177 178Isolate* CommonEnvironmentSetup::isolate() const { 179 return impl_->isolate; 180} 181 182IsolateData* CommonEnvironmentSetup::isolate_data() const { 183 return impl_->isolate_data.get(); 184} 185 186Environment* CommonEnvironmentSetup::env() const { 187 return impl_->env.get(); 188} 189 190v8::Local<v8::Context> CommonEnvironmentSetup::context() const { 191 return impl_->context.Get(impl_->isolate); 192} 193 194} // namespace node 195