Browse Source

Force uv loop cleanup (#11465)

* ensure all uv handles are closed before ending worker's loop

* add DCHECK to test that the Worker loop is finished

* don't call deprecated uv_loop_new(), uv_loop_delete()

* make cpplint happy

* fix comment error

* empty commit for CI

* tweak DCHECK expression

* extract-method: stop_and_close_uv_loop()

* fix DCHECK oops
Charles Kerr 7 years ago
parent
commit
435c9c1486
2 changed files with 35 additions and 4 deletions
  1. 32 4
      atom/common/node_bindings.cc
  2. 3 0
      atom/common/node_bindings.h

+ 32 - 4
atom/common/node_bindings.cc

@@ -64,6 +64,29 @@ REFERENCE_MODULE(atom_renderer_ipc);
 REFERENCE_MODULE(atom_renderer_web_frame);
 #undef REFERENCE_MODULE
 
+namespace {
+
+void stop_and_close_uv_loop(uv_loop_t* loop) {
+  // Close any active handles
+  uv_stop(loop);
+  uv_walk(loop, [](uv_handle_t* handle, void*){
+    if (!uv_is_closing(handle)) {
+      uv_close(handle, nullptr);
+    }
+  }, nullptr);
+
+  // Run the loop to let it finish all the closing handles
+  // NB: after uv_stop(), uv_run(UV_RUN_DEFAULT) returns 0 when that's done
+  for (;;)
+    if (!uv_run(loop, UV_RUN_DEFAULT))
+      break;
+
+  DCHECK(!uv_loop_alive(loop));
+  uv_loop_close(loop);
+}
+
+}  // namespace
+
 namespace atom {
 
 namespace {
@@ -100,10 +123,15 @@ base::FilePath GetResourcesPath(bool is_browser) {
 
 NodeBindings::NodeBindings(BrowserEnvironment browser_env)
     : browser_env_(browser_env),
-      uv_loop_(browser_env == WORKER ? uv_loop_new() : uv_default_loop()),
       embed_closed_(false),
       uv_env_(nullptr),
       weak_factory_(this) {
+  if (browser_env == WORKER) {
+    uv_loop_init(&worker_loop_);
+    uv_loop_ = &worker_loop_;
+  } else {
+    uv_loop_ = uv_default_loop();
+  }
 }
 
 NodeBindings::~NodeBindings() {
@@ -119,9 +147,9 @@ NodeBindings::~NodeBindings() {
   uv_sem_destroy(&embed_sem_);
   uv_close(reinterpret_cast<uv_handle_t*>(&dummy_uv_handle_), nullptr);
 
-  // Destroy loop.
-  if (uv_loop_ != uv_default_loop())
-    uv_loop_delete(uv_loop_);
+  // Clean up worker loop
+  if (uv_loop_ == &worker_loop_)
+    stop_and_close_uv_loop(uv_loop_);
 }
 
 void NodeBindings::Initialize() {

+ 3 - 0
atom/common/node_bindings.h

@@ -85,6 +85,9 @@ class NodeBindings {
   // Whether the libuv loop has ended.
   bool embed_closed_;
 
+  // Loop used when constructed in WORKER mode
+  uv_loop_t worker_loop_;
+
   // Dummy handle to make uv's loop not quit.
   uv_async_t dummy_uv_handle_;