From 435c9c14861591eafaf07d357ba426d7537a2cf4 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 4 Jan 2018 13:16:06 -0600 Subject: [PATCH] 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 --- atom/common/node_bindings.cc | 36 ++++++++++++++++++++++++++++++++---- atom/common/node_bindings.h | 3 +++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/atom/common/node_bindings.cc b/atom/common/node_bindings.cc index 03e96ae8a4..cc4bc554ef 100644 --- a/atom/common/node_bindings.cc +++ b/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(&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() { diff --git a/atom/common/node_bindings.h b/atom/common/node_bindings.h index 5047a9afb2..4be779e68a 100644 --- a/atom/common/node_bindings.h +++ b/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_;