@@ -285,22 +285,33 @@ void PerIsolatePlatformData::Shutdown() {
285285 // effectively deleting the tasks instead of running them.
286286 foreground_delayed_tasks_.PopAll ();
287287 foreground_tasks_.PopAll ();
288+ scheduled_delayed_tasks_.clear ();
288289
289- CancelPendingDelayedTasks ();
290-
291- ShutdownCbList* copy = new ShutdownCbList (std::move (shutdown_callbacks_));
292- flush_tasks_->data = copy;
290+ // Both destroying the scheduled_delayed_tasks_ lists and closing
291+ // flush_tasks_ handle add tasks to the event loop. We keep a count of all
292+ // non-closed handles, and when that reaches zero, we inform any shutdown
293+ // callbacks that the platform is done as far as this Isolate is concerned.
294+ self_reference_ = shared_from_this ();
293295 uv_close (reinterpret_cast <uv_handle_t *>(flush_tasks_),
294296 [](uv_handle_t * handle) {
295- std::unique_ptr<ShutdownCbList> callbacks (
296- static_cast <ShutdownCbList*>(handle->data ));
297- for (const auto & callback : *callbacks)
298- callback.cb (callback.data );
299- delete reinterpret_cast <uv_async_t *>(handle);
297+ std::unique_ptr<uv_async_t > flush_tasks {
298+ reinterpret_cast <uv_async_t *>(handle) };
299+ PerIsolatePlatformData* platform_data =
300+ static_cast <PerIsolatePlatformData*>(flush_tasks->data );
301+ platform_data->DecreaseHandleCount ();
302+ platform_data->self_reference_ .reset ();
300303 });
301304 flush_tasks_ = nullptr ;
302305}
303306
307+ void PerIsolatePlatformData::DecreaseHandleCount () {
308+ CHECK_GE (uv_handle_count_, 1 );
309+ if (--uv_handle_count_ == 0 ) {
310+ for (const auto & callback : shutdown_callbacks_)
311+ callback.cb (callback.data );
312+ }
313+ }
314+
304315NodePlatform::NodePlatform (int thread_pool_size,
305316 TracingController* tracing_controller) {
306317 if (tracing_controller) {
@@ -382,10 +393,6 @@ void PerIsolatePlatformData::RunForegroundTask(uv_timer_t* handle) {
382393 delayed->platform_data ->DeleteFromScheduledTasks (delayed);
383394}
384395
385- void PerIsolatePlatformData::CancelPendingDelayedTasks () {
386- scheduled_delayed_tasks_.clear ();
387- }
388-
389396void NodePlatform::DrainTasks (Isolate* isolate) {
390397 std::shared_ptr<PerIsolatePlatformData> per_isolate = ForIsolate (isolate);
391398
@@ -409,12 +416,15 @@ bool PerIsolatePlatformData::FlushForegroundTasksInternal() {
409416 // the delay is non-zero. This should not be a problem in practice.
410417 uv_timer_start (&delayed->timer , RunForegroundTask, delay_millis, 0 );
411418 uv_unref (reinterpret_cast <uv_handle_t *>(&delayed->timer ));
419+ uv_handle_count_++;
412420
413421 scheduled_delayed_tasks_.emplace_back (delayed.release (),
414422 [](DelayedTask* delayed) {
415423 uv_close (reinterpret_cast <uv_handle_t *>(&delayed->timer ),
416424 [](uv_handle_t * handle) {
417- delete static_cast <DelayedTask*>(handle->data );
425+ std::unique_ptr<DelayedTask> task {
426+ static_cast <DelayedTask*>(handle->data ) };
427+ task->platform_data ->DecreaseHandleCount ();
418428 });
419429 });
420430 }
@@ -454,10 +464,6 @@ bool NodePlatform::FlushForegroundTasks(Isolate* isolate) {
454464 return ForIsolate (isolate)->FlushForegroundTasksInternal ();
455465}
456466
457- void NodePlatform::CancelPendingDelayedTasks (Isolate* isolate) {
458- ForIsolate (isolate)->CancelPendingDelayedTasks ();
459- }
460-
461467bool NodePlatform::IdleTasksEnabled (Isolate* isolate) { return false ; }
462468
463469std::shared_ptr<v8::TaskRunner>
@@ -548,4 +554,6 @@ std::queue<std::unique_ptr<T>> TaskQueue<T>::PopAll() {
548554 return result;
549555}
550556
557+ void MultiIsolatePlatform::CancelPendingDelayedTasks (Isolate* isolate) {}
558+
551559} // namespace node
0 commit comments