Skip to content

Commit df7ebfa

Browse files
committed
worker: correct (de)initialization order
- Initialize `thread_exit_async_` only once the thread has been started. This is done since it is only triggered from the thread when it is exiting. - Move the final `uv_run` to the `Worker` destructor. This makes sure that it is always run, regardless of whether the thread is actually started or not. - Always dispose the `Isolate` before cleaning up the libuv event loop. This now matches the reverse order of initialization. Fixes: #22736 PR-URL: #22773 Reviewed-By: James M Snell <[email protected]>
1 parent 246f633 commit df7ebfa

File tree

2 files changed

+37
-13
lines changed

2 files changed

+37
-13
lines changed

src/node_worker.cc

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,6 @@ Worker::Worker(Environment* env, Local<Object> wrap)
7171
isolate_ = NewIsolate(array_buffer_allocator_.get(), &loop_);
7272
CHECK_NE(isolate_, nullptr);
7373

74-
thread_exit_async_.reset(new uv_async_t);
75-
thread_exit_async_->data = this;
76-
CHECK_EQ(uv_async_init(env->event_loop(),
77-
thread_exit_async_.get(),
78-
[](uv_async_t* handle) {
79-
static_cast<Worker*>(handle->data)->OnThreadStopped();
80-
}), 0);
81-
8274
{
8375
// Enter an environment capable of executing code in the child Isolate
8476
// (and only in it).
@@ -242,9 +234,6 @@ void Worker::Run() {
242234

243235
DisposeIsolate();
244236

245-
// Need to run the loop one more time to close the platform's uv_async_t
246-
uv_run(&loop_, UV_RUN_ONCE);
247-
248237
{
249238
Mutex::ScopedLock lock(mutex_);
250239
CHECK(thread_exit_async_);
@@ -256,6 +245,13 @@ void Worker::Run() {
256245
}
257246

258247
void Worker::DisposeIsolate() {
248+
if (env_) {
249+
CHECK_NOT_NULL(isolate_);
250+
Locker locker(isolate_);
251+
Isolate::Scope isolate_scope(isolate_);
252+
env_.reset();
253+
}
254+
259255
if (isolate_ == nullptr)
260256
return;
261257

@@ -332,12 +328,16 @@ Worker::~Worker() {
332328
CHECK(stopped_);
333329
CHECK(thread_joined_);
334330
CHECK_EQ(child_port_, nullptr);
335-
CheckedUvLoopClose(&loop_);
336331

337332
// This has most likely already happened within the worker thread -- this
338333
// is just in case Worker creation failed early.
339334
DisposeIsolate();
340335

336+
// Need to run the loop one more time to close the platform's uv_async_t
337+
uv_run(&loop_, UV_RUN_ONCE);
338+
339+
CheckedUvLoopClose(&loop_);
340+
341341
Debug(this, "Worker %llu destroyed", thread_id_);
342342
}
343343

@@ -361,10 +361,19 @@ void Worker::StartThread(const FunctionCallbackInfo<Value>& args) {
361361

362362
w->env()->add_sub_worker_context(w);
363363
w->stopped_ = false;
364+
w->thread_joined_ = false;
365+
366+
w->thread_exit_async_.reset(new uv_async_t);
367+
w->thread_exit_async_->data = w;
368+
CHECK_EQ(uv_async_init(w->env()->event_loop(),
369+
w->thread_exit_async_.get(),
370+
[](uv_async_t* handle) {
371+
static_cast<Worker*>(handle->data)->OnThreadStopped();
372+
}), 0);
373+
364374
CHECK_EQ(uv_thread_create(&w->tid_, [](void* arg) {
365375
static_cast<Worker*>(arg)->Run();
366376
}, static_cast<void*>(w)), 0);
367-
w->thread_joined_ = false;
368377
}
369378

370379
void Worker::StopThread(const FunctionCallbackInfo<Value>& args) {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Flags: --experimental-worker
2+
'use strict';
3+
require('../common');
4+
const assert = require('assert');
5+
const { Worker } = require('worker_threads');
6+
7+
// This tests verifies that failing to serialize workerData does not keep
8+
// the process alive.
9+
// Refs: https://github.com/nodejs/node/issues/22736
10+
11+
assert.throws(() => {
12+
new Worker('./worker.js', {
13+
workerData: { fn: () => {} }
14+
});
15+
}, /DataCloneError/);

0 commit comments

Comments
 (0)