@@ -40,9 +40,9 @@ static void PlatformWorkerThread(void* data) {
40
40
worker_data->platform_workers_ready ->Signal (lock);
41
41
}
42
42
43
- while (std::unique_ptr<Task> task = pending_worker_tasks->BlockingPop ()) {
43
+ while (std::unique_ptr<Task> task = pending_worker_tasks->Lock (). BlockingPop ()) {
44
44
task->Run ();
45
- pending_worker_tasks->NotifyOfCompletion ();
45
+ pending_worker_tasks->Lock (). NotifyOfCompletion ();
46
46
}
47
47
}
48
48
@@ -73,13 +73,15 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler {
73
73
}
74
74
75
75
void PostDelayedTask (std::unique_ptr<Task> task, double delay_in_seconds) {
76
- tasks_.Push (std::make_unique<ScheduleTask>(this , std::move (task),
77
- delay_in_seconds));
76
+ auto locked = tasks_.Lock ();
77
+ locked.Push (std::make_unique<ScheduleTask>(this , std::move (task),
78
+ delay_in_seconds));
78
79
uv_async_send (&flush_tasks_);
79
80
}
80
81
81
82
void Stop () {
82
- tasks_.Push (std::make_unique<StopTask>(this ));
83
+ auto locked = tasks_.Lock ();
84
+ locked.Push (std::make_unique<StopTask>(this ));
83
85
uv_async_send (&flush_tasks_);
84
86
}
85
87
@@ -100,7 +102,8 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler {
100
102
static void FlushTasks (uv_async_t * flush_tasks) {
101
103
DelayedTaskScheduler* scheduler =
102
104
ContainerOf (&DelayedTaskScheduler::loop_, flush_tasks->loop );
103
- while (std::unique_ptr<Task> task = scheduler->tasks_ .Pop ())
105
+ auto locked = scheduler->tasks_ .Lock ();
106
+ while (std::unique_ptr<Task> task = locked.Pop ())
104
107
task->Run ();
105
108
}
106
109
@@ -149,7 +152,7 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler {
149
152
static void RunTask (uv_timer_t * timer) {
150
153
DelayedTaskScheduler* scheduler =
151
154
ContainerOf (&DelayedTaskScheduler::loop_, timer->loop );
152
- scheduler->pending_worker_tasks_ ->Push (scheduler->TakeTimerTask (timer));
155
+ scheduler->pending_worker_tasks_ ->Lock (). Push (scheduler->TakeTimerTask (timer));
153
156
}
154
157
155
158
std::unique_ptr<Task> TakeTimerTask (uv_timer_t * timer) {
@@ -203,7 +206,7 @@ WorkerThreadsTaskRunner::WorkerThreadsTaskRunner(int thread_pool_size) {
203
206
}
204
207
205
208
void WorkerThreadsTaskRunner::PostTask (std::unique_ptr<Task> task) {
206
- pending_worker_tasks_.Push (std::move (task));
209
+ pending_worker_tasks_.Lock (). Push (std::move (task));
207
210
}
208
211
209
212
void WorkerThreadsTaskRunner::PostDelayedTask (std::unique_ptr<Task> task,
@@ -212,11 +215,11 @@ void WorkerThreadsTaskRunner::PostDelayedTask(std::unique_ptr<Task> task,
212
215
}
213
216
214
217
void WorkerThreadsTaskRunner::BlockingDrain () {
215
- pending_worker_tasks_.BlockingDrain ();
218
+ pending_worker_tasks_.Lock (). BlockingDrain ();
216
219
}
217
220
218
221
void WorkerThreadsTaskRunner::Shutdown () {
219
- pending_worker_tasks_.Stop ();
222
+ pending_worker_tasks_.Lock (). Stop ();
220
223
delayed_task_scheduler_->Stop ();
221
224
for (size_t i = 0 ; i < threads_.size (); i++) {
222
225
CHECK_EQ (0 , uv_thread_join (threads_[i].get ()));
@@ -253,20 +256,22 @@ void PerIsolatePlatformData::PostIdleTaskImpl(
253
256
254
257
void PerIsolatePlatformData::PostTaskImpl (std::unique_ptr<Task> task,
255
258
const v8::SourceLocation& location) {
256
- if (flush_tasks_ == nullptr ) {
259
+ // Check if flush_tasks is valid before using it
260
+ if (!flush_tasks_valid_.load ()) {
257
261
// V8 may post tasks during Isolate disposal. In that case, the only
258
262
// sensible path forward is to discard the task.
259
263
return ;
260
264
}
261
- foreground_tasks_.Push (std::move (task));
265
+ foreground_tasks_.Lock (). Push (std::move (task));
262
266
uv_async_send (flush_tasks_);
263
267
}
264
268
265
269
void PerIsolatePlatformData::PostDelayedTaskImpl (
266
270
std::unique_ptr<Task> task,
267
271
double delay_in_seconds,
268
272
const v8::SourceLocation& location) {
269
- if (flush_tasks_ == nullptr ) {
273
+ // Check if flush_tasks is valid before using it
274
+ if (!flush_tasks_valid_.load ()) {
270
275
// V8 may post tasks during Isolate disposal. In that case, the only
271
276
// sensible path forward is to discard the task.
272
277
return ;
@@ -275,7 +280,7 @@ void PerIsolatePlatformData::PostDelayedTaskImpl(
275
280
delayed->task = std::move (task);
276
281
delayed->platform_data = shared_from_this ();
277
282
delayed->timeout = delay_in_seconds;
278
- foreground_delayed_tasks_.Push (std::move (delayed));
283
+ foreground_delayed_tasks_.Lock (). Push (std::move (delayed));
279
284
uv_async_send (flush_tasks_);
280
285
}
281
286
@@ -301,15 +306,19 @@ void PerIsolatePlatformData::AddShutdownCallback(void (*callback)(void*),
301
306
}
302
307
303
308
void PerIsolatePlatformData::Shutdown () {
304
- if (flush_tasks_ == nullptr )
309
+ // First mark the flush_tasks as invalid
310
+ bool expected = true ;
311
+ if (!flush_tasks_valid_.compare_exchange_strong (expected, false )) {
312
+ // Already marked invalid
305
313
return ;
314
+ }
306
315
307
316
// While there should be no V8 tasks in the queues at this point, it is
308
317
// possible that Node.js-internal tasks from e.g. the inspector are still
309
318
// lying around. We clear these queues and ignore the return value,
310
319
// effectively deleting the tasks instead of running them.
311
- foreground_delayed_tasks_.PopAll ();
312
- foreground_tasks_.PopAll ();
320
+ foreground_delayed_tasks_.Lock (). PopAll ();
321
+ foreground_tasks_.Lock (). PopAll ();
313
322
scheduled_delayed_tasks_.clear ();
314
323
315
324
// Both destroying the scheduled_delayed_tasks_ lists and closing
@@ -472,33 +481,36 @@ void NodePlatform::DrainTasks(Isolate* isolate) {
472
481
bool PerIsolatePlatformData::FlushForegroundTasksInternal () {
473
482
bool did_work = false ;
474
483
475
- while (std::unique_ptr<DelayedTask> delayed =
476
- foreground_delayed_tasks_.Pop ()) {
477
- did_work = true ;
478
- uint64_t delay_millis = llround (delayed->timeout * 1000 );
479
-
480
- delayed->timer .data = static_cast <void *>(delayed.get ());
481
- uv_timer_init (loop_, &delayed->timer );
482
- // Timers may not guarantee queue ordering of events with the same delay if
483
- // the delay is non-zero. This should not be a problem in practice.
484
- uv_timer_start (&delayed->timer , RunForegroundTask, delay_millis, 0 );
485
- uv_unref (reinterpret_cast <uv_handle_t *>(&delayed->timer ));
486
- uv_handle_count_++;
487
-
488
- scheduled_delayed_tasks_.emplace_back (delayed.release (),
484
+ {
485
+ auto locked_tasks = foreground_delayed_tasks_.Lock ();
486
+ while (std::unique_ptr<DelayedTask> delayed = locked_tasks.Pop ()) {
487
+ did_work = true ;
488
+ uint64_t delay_millis = llround (delayed->timeout * 1000 );
489
+
490
+ delayed->timer .data = static_cast <void *>(delayed.get ());
491
+ uv_timer_init (loop_, &delayed->timer );
492
+ // Timers may not guarantee queue ordering of events with the same delay if
493
+ // the delay is non-zero. This should not be a problem in practice.
494
+ uv_timer_start (&delayed->timer , RunForegroundTask, delay_millis, 0 );
495
+ uv_unref (reinterpret_cast <uv_handle_t *>(&delayed->timer ));
496
+ uv_handle_count_++;
497
+
498
+ scheduled_delayed_tasks_.emplace_back (delayed.release (),
489
499
[](DelayedTask* delayed) {
490
- uv_close (reinterpret_cast <uv_handle_t *>(&delayed->timer ),
500
+ uv_close (reinterpret_cast <uv_handle_t *>(&delayed->timer ),
491
501
[](uv_handle_t * handle) {
492
- std::unique_ptr<DelayedTask> task {
493
- static_cast <DelayedTask*>(handle->data ) };
494
- task->platform_data ->DecreaseHandleCount ();
502
+ std::unique_ptr<DelayedTask> task {
503
+ static_cast <DelayedTask*>(handle->data ) };
504
+ task->platform_data ->DecreaseHandleCount ();
505
+ });
495
506
});
496
- });
507
+ }
497
508
}
509
+
498
510
// Move all foreground tasks into a separate queue and flush that queue.
499
511
// This way tasks that are posted while flushing the queue will be run on the
500
512
// next call of FlushForegroundTasksInternal.
501
- std::queue<std::unique_ptr<Task>> tasks = foreground_tasks_.PopAll ();
513
+ std::queue<std::unique_ptr<Task>> tasks = foreground_tasks_.Lock (). PopAll ();
502
514
while (!tasks.empty ()) {
503
515
std::unique_ptr<Task> task = std::move (tasks.front ());
504
516
tasks.pop ();
@@ -593,68 +605,4 @@ TaskQueue<T>::TaskQueue()
593
605
: lock_(), tasks_available_(), tasks_drained_(),
594
606
outstanding_tasks_(0 ), stopped_(false ), task_queue_() { }
595
607
596
- template <class T >
597
- void TaskQueue<T>::Push(std::unique_ptr<T> task) {
598
- Mutex::ScopedLock scoped_lock (lock_);
599
- outstanding_tasks_++;
600
- task_queue_.push (std::move (task));
601
- tasks_available_.Signal (scoped_lock);
602
- }
603
-
604
- template <class T >
605
- std::unique_ptr<T> TaskQueue<T>::Pop() {
606
- Mutex::ScopedLock scoped_lock (lock_);
607
- if (task_queue_.empty ()) {
608
- return std::unique_ptr<T>(nullptr );
609
- }
610
- std::unique_ptr<T> result = std::move (task_queue_.front ());
611
- task_queue_.pop ();
612
- return result;
613
- }
614
-
615
- template <class T >
616
- std::unique_ptr<T> TaskQueue<T>::BlockingPop() {
617
- Mutex::ScopedLock scoped_lock (lock_);
618
- while (task_queue_.empty () && !stopped_) {
619
- tasks_available_.Wait (scoped_lock);
620
- }
621
- if (stopped_) {
622
- return std::unique_ptr<T>(nullptr );
623
- }
624
- std::unique_ptr<T> result = std::move (task_queue_.front ());
625
- task_queue_.pop ();
626
- return result;
627
- }
628
-
629
- template <class T >
630
- void TaskQueue<T>::NotifyOfCompletion() {
631
- Mutex::ScopedLock scoped_lock (lock_);
632
- if (--outstanding_tasks_ == 0 ) {
633
- tasks_drained_.Broadcast (scoped_lock);
634
- }
635
- }
636
-
637
- template <class T >
638
- void TaskQueue<T>::BlockingDrain() {
639
- Mutex::ScopedLock scoped_lock (lock_);
640
- while (outstanding_tasks_ > 0 ) {
641
- tasks_drained_.Wait (scoped_lock);
642
- }
643
- }
644
-
645
- template <class T >
646
- void TaskQueue<T>::Stop() {
647
- Mutex::ScopedLock scoped_lock (lock_);
648
- stopped_ = true ;
649
- tasks_available_.Broadcast (scoped_lock);
650
- }
651
-
652
- template <class T >
653
- std::queue<std::unique_ptr<T>> TaskQueue<T>::PopAll() {
654
- Mutex::ScopedLock scoped_lock (lock_);
655
- std::queue<std::unique_ptr<T>> result;
656
- result.swap (task_queue_);
657
- return result;
658
- }
659
-
660
608
} // namespace node
0 commit comments