@@ -67,6 +67,13 @@ int main(int argc, char** argv) {
67
67
```
68
68
69
69
### Per-instance state
70
+ <!-- YAML
71
+ changes:
72
+ - version: REPLACEME
73
+ pr-url: https://github.com/nodejs/node/pull/35597
74
+ description:
75
+ The `CommonEnvironmentSetup` and `SpinEventLoop` utilities were added.
76
+ -->
70
77
71
78
Node.js has a concept of a “Node.js instance”, that is commonly being referred
72
79
to as `node::Environment`. Each `node::Environment` is associated with:
@@ -99,52 +106,26 @@ int RunNodeInstance(MultiIsolatePlatform* platform,
99
106
const std::vector<std::string>& args,
100
107
const std::vector<std::string>& exec_args) {
101
108
int exit_code = 0;
102
- // Set up a libuv event loop.
103
- uv_loop_t loop;
104
- int ret = uv_loop_init(&loop);
105
- if (ret != 0) {
106
- fprintf(stderr, "%s: Failed to initialize loop: %s\n",
107
- args[0].c_str(),
108
- uv_err_name(ret));
109
- return 1;
110
- }
111
109
112
- std::shared_ptr<ArrayBufferAllocator> allocator =
113
- ArrayBufferAllocator::Create();
114
-
115
- Isolate* isolate = NewIsolate(allocator, &loop, platform);
116
- if (isolate == nullptr) {
117
- fprintf(stderr, "%s: Failed to initialize V8 Isolate\n", args[0].c_str());
110
+ // Setup up a libuv event loop, v8::Isolate, and Node.js Environment.
111
+ std::vector<std::string> errors;
112
+ std::unique_ptr<CommonEnvironmentSetup> setup =
113
+ CommonEnvironmentSetup::Create(platform, &errors, args, exec_args);
114
+ if (!setup) {
115
+ for (const std::string& err : errors)
116
+ fprintf(stderr, "%s: %s\n", args[0].c_str(), err.c_str());
118
117
return 1;
119
118
}
120
119
120
+ Isolate* isolate = setup->isolate();
121
+ Environment* env = setup->env();
122
+
121
123
{
122
124
Locker locker(isolate);
123
125
Isolate::Scope isolate_scope(isolate);
124
-
125
- // Create a node::IsolateData instance that will later be released using
126
- // node::FreeIsolateData().
127
- std::unique_ptr<IsolateData, decltype(&node::FreeIsolateData)> isolate_data(
128
- node::CreateIsolateData(isolate, &loop, platform, allocator.get()),
129
- node::FreeIsolateData);
130
-
131
- // Set up a new v8::Context.
132
- HandleScope handle_scope(isolate);
133
- Local<Context> context = node::NewContext(isolate);
134
- if (context.IsEmpty()) {
135
- fprintf(stderr, "%s: Failed to initialize V8 Context\n", args[0].c_str());
136
- return 1;
137
- }
138
-
139
126
// The v8::Context needs to be entered when node::CreateEnvironment() and
140
127
// node::LoadEnvironment() are being called.
141
- Context::Scope context_scope(context);
142
-
143
- // Create a node::Environment instance that will later be released using
144
- // node::FreeEnvironment().
145
- std::unique_ptr<Environment, decltype(&node::FreeEnvironment)> env(
146
- node::CreateEnvironment(isolate_data.get(), context, args, exec_args),
147
- node::FreeEnvironment);
128
+ Context::Scope context_scope(setup->context());
148
129
149
130
// Set up the Node.js instance for execution, and run code inside of it.
150
131
// There is also a variant that takes a callback and provides it with
@@ -156,7 +137,7 @@ int RunNodeInstance(MultiIsolatePlatform* platform,
156
137
// load files from the disk, and uses the standard CommonJS file loader
157
138
// instead of the internal-only `require` function.
158
139
MaybeLocal<Value> loadenv_ret = node::LoadEnvironment(
159
- env.get() ,
140
+ env,
160
141
"const publicRequire ="
161
142
" require('module').createRequire(process.cwd() + '/');"
162
143
"globalThis.require = publicRequire;"
@@ -165,58 +146,14 @@ int RunNodeInstance(MultiIsolatePlatform* platform,
165
146
if (loadenv_ret.IsEmpty()) // There has been a JS exception.
166
147
return 1;
167
148
168
- {
169
- // SealHandleScope protects against handle leaks from callbacks.
170
- SealHandleScope seal(isolate);
171
- bool more;
172
- do {
173
- uv_run(&loop, UV_RUN_DEFAULT);
174
-
175
- // V8 tasks on background threads may end up scheduling new tasks in the
176
- // foreground, which in turn can keep the event loop going. For example,
177
- // WebAssembly.compile() may do so.
178
- platform->DrainTasks(isolate);
179
-
180
- // If there are new tasks, continue.
181
- more = uv_loop_alive(&loop);
182
- if (more) continue;
183
-
184
- // node::EmitProcessBeforeExit() is used to emit the 'beforeExit' event
185
- // on the `process` object.
186
- if (node::EmitProcessBeforeExit(env.get()).IsNothing())
187
- break;
188
-
189
- // 'beforeExit' can also schedule new work that keeps the event loop
190
- // running.
191
- more = uv_loop_alive(&loop);
192
- } while (more == true);
193
- }
194
-
195
- // node::EmitProcessExit() returns the current exit code.
196
- exit_code = node::EmitProcessExit(env.get()).FromMaybe(1);
149
+ exit_code = node::SpinEventLoop(env).FromMaybe(1);
197
150
198
151
// node::Stop() can be used to explicitly stop the event loop and keep
199
152
// further JavaScript from running. It can be called from any thread,
200
153
// and will act like worker.terminate() if called from another thread.
201
- node::Stop(env.get() );
154
+ node::Stop(env);
202
155
}
203
156
204
- // Unregister the Isolate with the platform and add a listener that is called
205
- // when the Platform is done cleaning up any state it had associated with
206
- // the Isolate.
207
- bool platform_finished = false;
208
- platform->AddIsolateFinishedCallback(isolate, [](void* data) {
209
- *static_cast<bool*>(data) = true;
210
- }, &platform_finished);
211
- platform->UnregisterIsolate(isolate);
212
- isolate->Dispose();
213
-
214
- // Wait until the platform has cleaned up all relevant resources.
215
- while (!platform_finished)
216
- uv_run(&loop, UV_RUN_ONCE);
217
- int err = uv_loop_close(&loop);
218
- assert(err == 0);
219
-
220
157
return exit_code;
221
158
}
222
159
```
0 commit comments