@@ -58,6 +58,46 @@ void WaitForWorkerInspectorToStop(Environment* child) {
58
58
59
59
} // anonymous namespace
60
60
61
+ void AsyncRequest::Install (Environment* env, void * data, uv_async_cb target) {
62
+ Mutex::ScopedLock lock (mutex_);
63
+ env_ = env;
64
+ async_ = new uv_async_t ;
65
+ if (data != nullptr ) async_->data = data;
66
+ CHECK_EQ (uv_async_init (env_->event_loop (), async_, target), 0 );
67
+ }
68
+
69
+ void AsyncRequest::Uninstall () {
70
+ Mutex::ScopedLock lock (mutex_);
71
+ if (async_ != nullptr )
72
+ env_->CloseHandle (async_, [](uv_async_t * async) { delete async; });
73
+ }
74
+
75
+ void AsyncRequest::Stop () {
76
+ Mutex::ScopedLock lock (mutex_);
77
+ stop_ = true ;
78
+ if (async_ != nullptr ) uv_async_send (async_);
79
+ }
80
+
81
+ void AsyncRequest::SetStopped (bool flag) {
82
+ Mutex::ScopedLock lock (mutex_);
83
+ stop_ = flag;
84
+ }
85
+
86
+ bool AsyncRequest::IsStopped () {
87
+ Mutex::ScopedLock lock (mutex_);
88
+ return stop_;
89
+ }
90
+
91
+ uv_async_t * AsyncRequest::GetHandle () {
92
+ Mutex::ScopedLock lock (mutex_);
93
+ return async_;
94
+ }
95
+
96
+ void AsyncRequest::MemoryInfo (MemoryTracker* tracker) const {
97
+ Mutex::ScopedLock lock (mutex_);
98
+ if (async_ != nullptr ) tracker->TrackField (" async_request" , *async_);
99
+ }
100
+
61
101
Worker::Worker (Environment* env,
62
102
Local<Object> wrap,
63
103
const std::string& url,
@@ -97,9 +137,8 @@ Worker::Worker(Environment* env,
97
137
Debug (this , " Preparation for worker %llu finished" , thread_id_);
98
138
}
99
139
100
- bool Worker::is_stopped () const {
101
- Mutex::ScopedLock stopped_lock (stopped_mutex_);
102
- return stopped_;
140
+ bool Worker::is_stopped () {
141
+ return thread_stopper_.IsStopped ();
103
142
}
104
143
105
144
// This class contains data that is only relevant to the child thread itself,
@@ -207,6 +246,8 @@ void Worker::Run() {
207
246
Context::Scope context_scope (env_->context ());
208
247
if (child_port != nullptr )
209
248
child_port->Close ();
249
+ thread_stopper_.Uninstall ();
250
+ thread_stopper_.SetStopped (true );
210
251
env_->stop_sub_worker_contexts ();
211
252
env_->RunCleanup ();
212
253
RunAtExit (env_.get ());
@@ -215,10 +256,7 @@ void Worker::Run() {
215
256
WaitForWorkerInspectorToStop (env_.get ());
216
257
#endif
217
258
218
- {
219
- Mutex::ScopedLock stopped_lock (stopped_mutex_);
220
- stopped_ = true ;
221
- }
259
+ env_->RunCleanup ();
222
260
223
261
// This call needs to be made while the `Environment` is still alive
224
262
// because we assume that it is available for async tracking in the
@@ -227,11 +265,12 @@ void Worker::Run() {
227
265
}
228
266
});
229
267
268
+ if (thread_stopper_.IsStopped ()) return ;
230
269
{
231
270
HandleScope handle_scope (isolate_);
232
271
Local<Context> context = NewContext (isolate_);
233
- if (is_stopped ()) return ;
234
272
273
+ if (thread_stopper_.IsStopped ()) return ;
235
274
CHECK (!context.IsEmpty ());
236
275
Context::Scope context_scope (context);
237
276
{
@@ -253,6 +292,14 @@ void Worker::Run() {
253
292
Debug (this , " Created Environment for worker with id %llu" , thread_id_);
254
293
255
294
if (is_stopped ()) return ;
295
+ thread_stopper_.Install (env_.get (), env_.get (), [](uv_async_t * handle) {
296
+ Environment* env_ = static_cast <Environment*>(handle->data );
297
+ uv_stop (env_->event_loop ());
298
+ });
299
+ uv_unref (reinterpret_cast <uv_handle_t *>(thread_stopper_.GetHandle ()));
300
+
301
+ Debug (this , " Created Environment for worker with id %llu" , thread_id_);
302
+ if (thread_stopper_.IsStopped ()) return ;
256
303
{
257
304
HandleScope handle_scope (isolate_);
258
305
Mutex::ScopedLock lock (mutex_);
@@ -268,7 +315,7 @@ void Worker::Run() {
268
315
Debug (this , " Created message port for worker %llu" , thread_id_);
269
316
}
270
317
271
- if (is_stopped ()) return ;
318
+ if (thread_stopper_. IsStopped ()) return ;
272
319
{
273
320
#if NODE_USE_V8_PLATFORM && HAVE_INSPECTOR
274
321
StartWorkerInspector (env_.get (),
@@ -289,22 +336,21 @@ void Worker::Run() {
289
336
Debug (this , " Loaded environment for worker %llu" , thread_id_);
290
337
}
291
338
292
- if (is_stopped ()) return ;
339
+ if (thread_stopper_. IsStopped ()) return ;
293
340
{
294
341
SealHandleScope seal (isolate_);
295
342
bool more;
296
343
env_->performance_state ()->Mark (
297
344
node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
298
345
do {
299
- if (is_stopped ()) break ;
346
+ if (thread_stopper_. IsStopped ()) break ;
300
347
uv_run (&data.loop_ , UV_RUN_DEFAULT);
301
- if (is_stopped ()) break ;
348
+ if (thread_stopper_. IsStopped ()) break ;
302
349
303
350
platform_->DrainTasks (isolate_);
304
351
305
352
more = uv_loop_alive (&data.loop_ );
306
- if (more && !is_stopped ())
307
- continue ;
353
+ if (more && !thread_stopper_.IsStopped ()) continue ;
308
354
309
355
EmitBeforeExit (env_.get ());
310
356
@@ -319,7 +365,7 @@ void Worker::Run() {
319
365
320
366
{
321
367
int exit_code;
322
- bool stopped = is_stopped ();
368
+ bool stopped = thread_stopper_. IsStopped ();
323
369
if (!stopped)
324
370
exit_code = EmitExit (env_.get ());
325
371
Mutex::ScopedLock lock (mutex_);
@@ -341,34 +387,11 @@ void Worker::JoinThread() {
341
387
thread_joined_ = true ;
342
388
343
389
env ()->remove_sub_worker_context (this );
344
-
345
- if (thread_exit_async_) {
346
- env ()->CloseHandle (thread_exit_async_.release (), [](uv_async_t * async) {
347
- delete async;
348
- });
349
-
350
- if (scheduled_on_thread_stopped_)
351
- OnThreadStopped ();
352
- }
390
+ OnThreadStopped ();
391
+ on_thread_finished_.Uninstall ();
353
392
}
354
393
355
394
void Worker::OnThreadStopped () {
356
- {
357
- Mutex::ScopedLock lock (mutex_);
358
- scheduled_on_thread_stopped_ = false ;
359
-
360
- Debug (this , " Worker %llu thread stopped" , thread_id_);
361
-
362
- {
363
- Mutex::ScopedLock stopped_lock (stopped_mutex_);
364
- CHECK (stopped_);
365
- }
366
-
367
- parent_port_ = nullptr ;
368
- }
369
-
370
- JoinThread ();
371
-
372
395
{
373
396
HandleScope handle_scope (env ()->isolate ());
374
397
Context::Scope context_scope (env ()->context ());
@@ -391,7 +414,7 @@ Worker::~Worker() {
391
414
Mutex::ScopedLock lock (mutex_);
392
415
JoinThread ();
393
416
394
- CHECK (stopped_ );
417
+ CHECK (thread_stopper_. IsStopped () );
395
418
CHECK (thread_joined_);
396
419
397
420
// This has most likely already happened within the worker thread -- this
@@ -480,16 +503,15 @@ void Worker::StartThread(const FunctionCallbackInfo<Value>& args) {
480
503
Mutex::ScopedLock lock (w->mutex_ );
481
504
482
505
w->env ()->add_sub_worker_context (w);
483
- w->stopped_ = false ;
484
506
w->thread_joined_ = false ;
507
+ w->thread_stopper_ .SetStopped (false );
485
508
486
- w->thread_exit_async_ .reset (new uv_async_t );
487
- w->thread_exit_async_ ->data = w;
488
- CHECK_EQ (uv_async_init (w->env ()->event_loop (),
489
- w->thread_exit_async_ .get (),
490
- [](uv_async_t * handle) {
491
- static_cast <Worker*>(handle->data )->OnThreadStopped ();
492
- }), 0 );
509
+ w->on_thread_finished_ .Install (w->env (), w, [](uv_async_t * handle) {
510
+ Worker* w_ = static_cast <Worker*>(handle->data );
511
+ CHECK (w_->thread_stopper_ .IsStopped ());
512
+ w_->parent_port_ = nullptr ;
513
+ w_->JoinThread ();
514
+ });
493
515
494
516
uv_thread_options_t thread_options;
495
517
thread_options.flags = UV_THREAD_HAS_STACK_SIZE;
@@ -505,9 +527,7 @@ void Worker::StartThread(const FunctionCallbackInfo<Value>& args) {
505
527
w->Run ();
506
528
507
529
Mutex::ScopedLock lock (w->mutex_ );
508
- CHECK (w->thread_exit_async_ );
509
- w->scheduled_on_thread_stopped_ = true ;
510
- uv_async_send (w->thread_exit_async_ .get ());
530
+ w->on_thread_finished_ .Stop ();
511
531
}, static_cast <void *>(w)), 0 );
512
532
}
513
533
@@ -523,28 +543,23 @@ void Worker::StopThread(const FunctionCallbackInfo<Value>& args) {
523
543
void Worker::Ref (const FunctionCallbackInfo<Value>& args) {
524
544
Worker* w;
525
545
ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
526
- if (w->thread_exit_async_ )
527
- uv_ref (reinterpret_cast <uv_handle_t *>(w->thread_exit_async_ .get ()));
546
+ uv_ref (reinterpret_cast <uv_handle_t *>(w->on_thread_finished_ .GetHandle ()));
528
547
}
529
548
530
549
void Worker::Unref (const FunctionCallbackInfo<Value>& args) {
531
550
Worker* w;
532
551
ASSIGN_OR_RETURN_UNWRAP (&w, args.This ());
533
- if (w->thread_exit_async_ )
534
- uv_unref (reinterpret_cast <uv_handle_t *>(w->thread_exit_async_ .get ()));
552
+ uv_unref (reinterpret_cast <uv_handle_t *>(w->on_thread_finished_ .GetHandle ()));
535
553
}
536
554
537
555
void Worker::Exit (int code) {
538
556
Mutex::ScopedLock lock (mutex_);
539
- Mutex::ScopedLock stopped_lock (stopped_mutex_);
540
557
541
558
Debug (this , " Worker %llu called Exit(%d)" , thread_id_, code);
542
-
543
- if (!stopped_) {
544
- stopped_ = true ;
559
+ if (!thread_stopper_.IsStopped ()) {
545
560
exit_code_ = code;
546
- if (child_port_ != nullptr )
547
- child_port_-> StopEventLoop ();
561
+ Debug ( this , " Received StopEventLoop request " );
562
+ thread_stopper_. Stop ();
548
563
if (isolate_ != nullptr )
549
564
isolate_->TerminateExecution ();
550
565
}
0 commit comments