GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: api/embed_helpers.cc Lines: 82 92 89.1 %
Date: 2022-09-22 04:22:24 Branches: 31 48 64.6 %

Line Branch Exec Source
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
16
namespace node {
17
18
5930
Maybe<int> SpinEventLoop(Environment* env) {
19
5930
  CHECK_NOT_NULL(env);
20
5930
  MultiIsolatePlatform* platform = GetMultiIsolatePlatform(env);
21
5930
  CHECK_NOT_NULL(platform);
22
23
5930
  Isolate* isolate = env->isolate();
24
11607
  HandleScope handle_scope(isolate);
25
5930
  Context::Scope context_scope(env->context());
26
11607
  SealHandleScope seal(isolate);
27
28
5930
  if (env->is_stopping()) return Nothing<int>();
29
30
5930
  env->set_trace_sync_io(env->options()->trace_sync_io);
31
  {
32
    bool more;
33
5930
    env->performance_state()->Mark(
34
        node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
35
44
    do {
36
5974
      if (env->is_stopping()) break;
37
5974
      uv_run(env->event_loop(), UV_RUN_DEFAULT);
38
5741
      if (env->is_stopping()) break;
39
40
5415
      platform->DrainTasks(isolate);
41
42
5407
      more = uv_loop_alive(env->event_loop());
43

5407
      if (more && !env->is_stopping()) continue;
44
45
10754
      if (EmitProcessBeforeExit(env).IsNothing())
46
11
        break;
47
48
      {
49
5365
        HandleScope handle_scope(isolate);
50
10730
        if (env->RunSnapshotSerializeCallback().IsEmpty()) {
51
          break;
52
        }
53
      }
54
55
      // Emit `beforeExit` if the loop became alive either after emitting
56
      // event, or after running some callbacks.
57
5365
      more = uv_loop_alive(env->event_loop());
58

5394
    } while (more == true && !env->is_stopping());
59
5687
    env->performance_state()->Mark(
60
        node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
61
  }
62
5687
  if (env->is_stopping()) return Nothing<int>();
63
64
5330
  env->set_trace_sync_io(false);
65
  // Clear the serialize callback even though the JS-land queue should
66
  // be empty this point so that the deserialized instance won't
67
  // attempt to call into JS again.
68
10660
  env->set_snapshot_serialize_callback(Local<Function>());
69
70
5330
  env->PrintInfoForSnapshotIfDebug();
71
5330
  env->VerifyNoStrongBaseObjects();
72
5330
  return EmitProcessExit(env);
73
}
74
75
struct CommonEnvironmentSetup::Impl {
76
  MultiIsolatePlatform* platform = nullptr;
77
  uv_loop_t loop;
78
  std::shared_ptr<ArrayBufferAllocator> allocator;
79
  Isolate* isolate = nullptr;
80
  DeleteFnPtr<IsolateData, FreeIsolateData> isolate_data;
81
  DeleteFnPtr<Environment, FreeEnvironment> env;
82
  Global<Context> context;
83
};
84
85
7
CommonEnvironmentSetup::CommonEnvironmentSetup(
86
    MultiIsolatePlatform* platform,
87
    std::vector<std::string>* errors,
88
7
    std::function<Environment*(const CommonEnvironmentSetup*)> make_env)
89
7
  : impl_(new Impl()) {
90
7
  CHECK_NOT_NULL(platform);
91
7
  CHECK_NOT_NULL(errors);
92
93
7
  impl_->platform = platform;
94
7
  uv_loop_t* loop = &impl_->loop;
95
  // Use `data` to tell the destructor whether the loop was initialized or not.
96
7
  loop->data = nullptr;
97
7
  int ret = uv_loop_init(loop);
98
7
  if (ret != 0) {
99
    errors->push_back(
100
        SPrintF("Failed to initialize loop: %s", uv_err_name(ret)));
101
    return;
102
  }
103
7
  loop->data = this;
104
105
7
  impl_->allocator = ArrayBufferAllocator::Create();
106
7
  impl_->isolate = NewIsolate(impl_->allocator, &impl_->loop, platform);
107
7
  Isolate* isolate = impl_->isolate;
108
109
  {
110
    Locker locker(isolate);
111
7
    Isolate::Scope isolate_scope(isolate);
112
7
    impl_->isolate_data.reset(CreateIsolateData(
113
7
        isolate, loop, platform, impl_->allocator.get()));
114
115
7
    HandleScope handle_scope(isolate);
116
7
    Local<Context> context = NewContext(isolate);
117
7
    impl_->context.Reset(isolate, context);
118
7
    if (context.IsEmpty()) {
119
      errors->push_back("Failed to initialize V8 Context");
120
      return;
121
    }
122
123
7
    Context::Scope context_scope(context);
124
7
    impl_->env.reset(make_env(this));
125
  }
126
}
127
128
10
CommonEnvironmentSetup::~CommonEnvironmentSetup() {
129
5
  if (impl_->isolate != nullptr) {
130
5
    Isolate* isolate = impl_->isolate;
131
    {
132
5
      Locker locker(isolate);
133
10
      Isolate::Scope isolate_scope(isolate);
134
135
5
      impl_->context.Reset();
136
5
      impl_->env.reset();
137
5
      impl_->isolate_data.reset();
138
    }
139
140
5
    bool platform_finished = false;
141
5
    impl_->platform->AddIsolateFinishedCallback(isolate, [](void* data) {
142
5
      *static_cast<bool*>(data) = true;
143
5
    }, &platform_finished);
144
5
    impl_->platform->UnregisterIsolate(isolate);
145
5
    isolate->Dispose();
146
147
    // Wait until the platform has cleaned up all relevant resources.
148
10
    while (!platform_finished)
149
5
      uv_run(&impl_->loop, UV_RUN_ONCE);
150
  }
151
152

5
  if (impl_->isolate || impl_->loop.data != nullptr)
153
5
    CheckedUvLoopClose(&impl_->loop);
154
155
5
  delete impl_;
156
5
}
157
158
159
uv_loop_t* CommonEnvironmentSetup::event_loop() const {
160
  return &impl_->loop;
161
}
162
163
std::shared_ptr<ArrayBufferAllocator>
164
CommonEnvironmentSetup::array_buffer_allocator() const {
165
  return impl_->allocator;
166
}
167
168
7
Isolate* CommonEnvironmentSetup::isolate() const {
169
7
  return impl_->isolate;
170
}
171
172
7
IsolateData* CommonEnvironmentSetup::isolate_data() const {
173
7
  return impl_->isolate_data.get();
174
}
175
176
7
Environment* CommonEnvironmentSetup::env() const {
177
7
  return impl_->env.get();
178
}
179
180
14
v8::Local<v8::Context> CommonEnvironmentSetup::context() const {
181
28
  return impl_->context.Get(impl_->isolate);
182
}
183
184
}  // namespace node