Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/api
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2020-10-11 16:13:19 +0300
committerAnna Henningsen <anna@addaleax.net>2020-10-14 21:08:19 +0300
commit9fd6122659c4067b0d8bd2c590f4ba01b48c93a3 (patch)
tree89cdbb73d84f5ae87e1399f95aa0fba392b43f7f /src/api
parentef1645e2b3f609492af7f25e4468db9b7801f4aa (diff)
src: add embedding helpers to reduce boilerplate code
Provide helpers for a) spinning the event loop and b) setting up and tearing down the objects involved in a single Node.js instance, as they would typically be used. The former helper is also usable inside Node.js itself, for both Worker and main threads. PR-URL: https://github.com/nodejs/node/pull/35597 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Diffstat (limited to 'src/api')
-rw-r--r--src/api/embed_helpers.cc169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/api/embed_helpers.cc b/src/api/embed_helpers.cc
new file mode 100644
index 00000000000..998d7507fc0
--- /dev/null
+++ b/src/api/embed_helpers.cc
@@ -0,0 +1,169 @@
+#include "node.h"
+#include "env-inl.h"
+#include "debug_utils-inl.h"
+
+using v8::Context;
+using v8::Global;
+using v8::HandleScope;
+using v8::Isolate;
+using v8::Local;
+using v8::Locker;
+using v8::Maybe;
+using v8::Nothing;
+using v8::SealHandleScope;
+
+namespace node {
+
+Maybe<int> SpinEventLoop(Environment* env) {
+ CHECK_NOT_NULL(env);
+ MultiIsolatePlatform* platform = GetMultiIsolatePlatform(env);
+ CHECK_NOT_NULL(platform);
+
+ HandleScope handle_scope(env->isolate());
+ Context::Scope context_scope(env->context());
+ SealHandleScope seal(env->isolate());
+
+ if (env->is_stopping()) return Nothing<int>();
+
+ env->set_trace_sync_io(env->options()->trace_sync_io);
+ {
+ bool more;
+ env->performance_state()->Mark(
+ node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
+ do {
+ if (env->is_stopping()) break;
+ uv_run(env->event_loop(), UV_RUN_DEFAULT);
+ if (env->is_stopping()) break;
+
+ platform->DrainTasks(env->isolate());
+
+ more = uv_loop_alive(env->event_loop());
+ if (more && !env->is_stopping()) continue;
+
+ if (EmitProcessBeforeExit(env).IsNothing())
+ break;
+
+ // Emit `beforeExit` if the loop became alive either after emitting
+ // event, or after running some callbacks.
+ more = uv_loop_alive(env->event_loop());
+ } while (more == true && !env->is_stopping());
+ env->performance_state()->Mark(
+ node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
+ }
+ if (env->is_stopping()) return Nothing<int>();
+
+ env->set_trace_sync_io(false);
+ env->VerifyNoStrongBaseObjects();
+ return EmitProcessExit(env);
+}
+
+struct CommonEnvironmentSetup::Impl {
+ MultiIsolatePlatform* platform = nullptr;
+ uv_loop_t loop;
+ std::shared_ptr<ArrayBufferAllocator> allocator;
+ Isolate* isolate = nullptr;
+ DeleteFnPtr<IsolateData, FreeIsolateData> isolate_data;
+ DeleteFnPtr<Environment, FreeEnvironment> env;
+ Global<Context> context;
+};
+
+CommonEnvironmentSetup::CommonEnvironmentSetup(
+ MultiIsolatePlatform* platform,
+ std::vector<std::string>* errors,
+ std::function<Environment*(const CommonEnvironmentSetup*)> make_env)
+ : impl_(new Impl()) {
+ CHECK_NOT_NULL(platform);
+ CHECK_NOT_NULL(errors);
+
+ impl_->platform = platform;
+ uv_loop_t* loop = &impl_->loop;
+ // Use `data` to tell the destructor whether the loop was initialized or not.
+ loop->data = nullptr;
+ int ret = uv_loop_init(loop);
+ if (ret != 0) {
+ errors->push_back(
+ SPrintF("Failed to initialize loop: %s", uv_err_name(ret)));
+ return;
+ }
+ loop->data = this;
+
+ impl_->allocator = ArrayBufferAllocator::Create();
+ impl_->isolate = NewIsolate(impl_->allocator, &impl_->loop, platform);
+ Isolate* isolate = impl_->isolate;
+
+ {
+ Locker locker(isolate);
+ Isolate::Scope isolate_scope(isolate);
+ impl_->isolate_data.reset(CreateIsolateData(
+ isolate, loop, platform, impl_->allocator.get()));
+
+ HandleScope handle_scope(isolate);
+ Local<Context> context = NewContext(isolate);
+ impl_->context.Reset(isolate, context);
+ if (context.IsEmpty()) {
+ errors->push_back("Failed to initialize V8 Context");
+ return;
+ }
+
+ Context::Scope context_scope(context);
+ impl_->env.reset(make_env(this));
+ }
+}
+
+CommonEnvironmentSetup::~CommonEnvironmentSetup() {
+ if (impl_->isolate != nullptr) {
+ Isolate* isolate = impl_->isolate;
+ {
+ Locker locker(isolate);
+ Isolate::Scope isolate_scope(isolate);
+
+ impl_->context.Reset();
+ impl_->env.reset();
+ impl_->isolate_data.reset();
+ }
+
+ bool platform_finished = false;
+ impl_->platform->AddIsolateFinishedCallback(isolate, [](void* data) {
+ *static_cast<bool*>(data) = true;
+ }, &platform_finished);
+ impl_->platform->UnregisterIsolate(isolate);
+ isolate->Dispose();
+
+ // Wait until the platform has cleaned up all relevant resources.
+ while (!platform_finished)
+ uv_run(&impl_->loop, UV_RUN_ONCE);
+ }
+
+ if (impl_->isolate || impl_->loop.data != nullptr)
+ CheckedUvLoopClose(&impl_->loop);
+
+ delete impl_;
+}
+
+
+uv_loop_t* CommonEnvironmentSetup::event_loop() const {
+ return &impl_->loop;
+}
+
+std::shared_ptr<ArrayBufferAllocator>
+CommonEnvironmentSetup::array_buffer_allocator() const {
+ return impl_->allocator;
+}
+
+Isolate* CommonEnvironmentSetup::isolate() const {
+ return impl_->isolate;
+}
+
+IsolateData* CommonEnvironmentSetup::isolate_data() const {
+ return impl_->isolate_data.get();
+}
+
+Environment* CommonEnvironmentSetup::env() const {
+ return impl_->env.get();
+}
+
+v8::Local<v8::Context> CommonEnvironmentSetup::context() const {
+ return impl_->context.Get(impl_->isolate);
+}
+
+} // namespace node