From 6d2c9c76e2f4ac73071d3d092b6165ec9fd4b952 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 9 Mar 2022 00:27:31 +0900 Subject: [PATCH] fix: iocp integration when process is reused --- shell/common/node_bindings.cc | 13 ++---------- shell/common/node_bindings.h | 10 +++++----- shell/common/node_bindings_linux.cc | 18 +++++++++++++++++ shell/common/node_bindings_linux.h | 4 ++++ shell/common/node_bindings_mac.cc | 18 +++++++++++++++++ shell/common/node_bindings_mac.h | 4 ++++ shell/common/node_bindings_win.cc | 23 ++++++++++++++++++++++ shell/common/node_bindings_win.h | 6 ++++++ shell/renderer/electron_renderer_client.cc | 4 +++- 9 files changed, 83 insertions(+), 17 deletions(-) diff --git a/shell/common/node_bindings.cc b/shell/common/node_bindings.cc index 99b017dc425fe..4e5b1577b1cfa 100644 --- a/shell/common/node_bindings.cc +++ b/shell/common/node_bindings.cc @@ -462,7 +462,8 @@ node::Environment* NodeBindings::CreateEnvironment( args.insert(args.begin() + 1, init_script); - isolate_data_ = node::CreateIsolateData(isolate, uv_loop_, platform); + if (!isolate_data_) + isolate_data_ = node::CreateIsolateData(isolate, uv_loop_, platform); node::Environment* env; uint64_t flags = node::EnvironmentFlags::kDefaultFlags | @@ -573,16 +574,6 @@ void NodeBindings::LoadEnvironment(node::Environment* env) { } void NodeBindings::PrepareMessageLoop() { -#if !BUILDFLAG(IS_WIN) - int handle = uv_backend_fd(uv_loop_); - - // If the backend fd hasn't changed, don't proceed. - if (handle == handle_) - return; - - handle_ = handle; -#endif - // Add dummy handle for libuv, otherwise libuv would quit when there is // nothing to do. uv_async_init(uv_loop_, dummy_uv_handle_.get(), nullptr); diff --git a/shell/common/node_bindings.h b/shell/common/node_bindings.h index 64519d340b5a1..204cf12d5cc6c 100644 --- a/shell/common/node_bindings.h +++ b/shell/common/node_bindings.h @@ -93,11 +93,15 @@ class NodeBindings { void LoadEnvironment(node::Environment* env); // Prepare for message loop integration. - void PrepareMessageLoop(); + virtual void PrepareMessageLoop(); // Do message loop integration. virtual void RunMessageLoop(); + // Gets/sets the per isolate data. + void set_isolate_data(node::IsolateData* isolate_data) { + isolate_data_ = isolate_data; + } node::IsolateData* isolate_data() const { return isolate_data_; } // Gets/sets the environment to wrap uv loop. @@ -161,10 +165,6 @@ class NodeBindings { // Isolate data used in creating the environment node::IsolateData* isolate_data_ = nullptr; -#if !BUILDFLAG(IS_WIN) - int handle_ = -1; -#endif - base::WeakPtrFactory weak_factory_{this}; }; diff --git a/shell/common/node_bindings_linux.cc b/shell/common/node_bindings_linux.cc index 3a69fea9aafc1..d361daec953e0 100644 --- a/shell/common/node_bindings_linux.cc +++ b/shell/common/node_bindings_linux.cc @@ -19,7 +19,25 @@ NodeBindingsLinux::NodeBindingsLinux(BrowserEnvironment browser_env) NodeBindingsLinux::~NodeBindingsLinux() = default; +void NodeBindingsLinux::PrepareMessageLoop() { + int handle = uv_backend_fd(uv_loop_); + + // If the backend fd hasn't changed, don't proceed. + if (handle == handle_) + return; + + NodeBindings::PrepareMessageLoop(); +} + void NodeBindingsLinux::RunMessageLoop() { + int handle = uv_backend_fd(uv_loop_); + + // If the backend fd hasn't changed, don't proceed. + if (handle == handle_) + return; + + handle_ = handle; + // Get notified when libuv's watcher queue changes. uv_loop_->data = this; uv_loop_->on_watcher_queue_updated = OnWatcherQueueChanged; diff --git a/shell/common/node_bindings_linux.h b/shell/common/node_bindings_linux.h index aca06dd0f5952..934ed68c597b8 100644 --- a/shell/common/node_bindings_linux.h +++ b/shell/common/node_bindings_linux.h @@ -15,6 +15,7 @@ class NodeBindingsLinux : public NodeBindings { explicit NodeBindingsLinux(BrowserEnvironment browser_env); ~NodeBindingsLinux() override; + void PrepareMessageLoop() override; void RunMessageLoop() override; private: @@ -25,6 +26,9 @@ class NodeBindingsLinux : public NodeBindings { // Epoll to poll for uv's backend fd. int epoll_; + + // uv's backend fd. + int handle_ = -1; }; } // namespace electron diff --git a/shell/common/node_bindings_mac.cc b/shell/common/node_bindings_mac.cc index e5163f700615b..7107d20c11b93 100644 --- a/shell/common/node_bindings_mac.cc +++ b/shell/common/node_bindings_mac.cc @@ -19,7 +19,25 @@ NodeBindingsMac::NodeBindingsMac(BrowserEnvironment browser_env) NodeBindingsMac::~NodeBindingsMac() = default; +void NodeBindingsMac::PrepareMessageLoop() { + int handle = uv_backend_fd(uv_loop_); + + // If the backend fd hasn't changed, don't proceed. + if (handle == handle_) + return; + + NodeBindings::PrepareMessageLoop(); +} + void NodeBindingsMac::RunMessageLoop() { + int handle = uv_backend_fd(uv_loop_); + + // If the backend fd hasn't changed, don't proceed. + if (handle == handle_) + return; + + handle_ = handle; + // Get notified when libuv's watcher queue changes. uv_loop_->data = this; uv_loop_->on_watcher_queue_updated = OnWatcherQueueChanged; diff --git a/shell/common/node_bindings_mac.h b/shell/common/node_bindings_mac.h index 2e54f2fc9a214..7687f85a7b8d3 100644 --- a/shell/common/node_bindings_mac.h +++ b/shell/common/node_bindings_mac.h @@ -15,6 +15,7 @@ class NodeBindingsMac : public NodeBindings { explicit NodeBindingsMac(BrowserEnvironment browser_env); ~NodeBindingsMac() override; + void PrepareMessageLoop() override; void RunMessageLoop() override; private: @@ -22,6 +23,9 @@ class NodeBindingsMac : public NodeBindings { static void OnWatcherQueueChanged(uv_loop_t* loop); void PollEvents() override; + + // uv's backend fd. + int handle_ = -1; }; } // namespace electron diff --git a/shell/common/node_bindings_win.cc b/shell/common/node_bindings_win.cc index 2356c523e3612..1410925f195c5 100644 --- a/shell/common/node_bindings_win.cc +++ b/shell/common/node_bindings_win.cc @@ -29,6 +29,29 @@ NodeBindingsWin::NodeBindingsWin(BrowserEnvironment browser_env) NodeBindingsWin::~NodeBindingsWin() = default; +void NodeBindingsWin::PrepareMessageLoop() { + // IOCP does not change for the process until the loop is recreated, + // we ensure that there is only a single polling thread satisfying + // the concurrency limit set from CreateIoCompletionPort call by + // uv_loop_init for the lifetime of this process. + if (initialized_) + return; + + NodeBindings::PrepareMessageLoop(); +} + +void NodeBindingsWin::RunMessageLoop() { + // Avoid calling UvRunOnce if the loop is already active, + // otherwise it can lead to situations were the number of active + // threads processing on IOCP is greater than the concurrency limit. + if (initialized_) + return; + + initialized_ = true; + + NodeBindings::RunMessageLoop(); +} + void NodeBindingsWin::PollEvents() { // If there are other kinds of events pending, uv_backend_timeout will // instruct us not to wait. diff --git a/shell/common/node_bindings_win.h b/shell/common/node_bindings_win.h index 0a5eed2237ed2..59d7469b0ff75 100644 --- a/shell/common/node_bindings_win.h +++ b/shell/common/node_bindings_win.h @@ -15,8 +15,14 @@ class NodeBindingsWin : public NodeBindings { explicit NodeBindingsWin(BrowserEnvironment browser_env); ~NodeBindingsWin() override; + void PrepareMessageLoop() override; + void RunMessageLoop() override; + private: void PollEvents() override; + + // Indicates whether polling thread has been created. + bool initialized_ = false; }; } // namespace electron diff --git a/shell/renderer/electron_renderer_client.cc b/shell/renderer/electron_renderer_client.cc index 2c80080172c1f..08276425938f3 100644 --- a/shell/renderer/electron_renderer_client.cc +++ b/shell/renderer/electron_renderer_client.cc @@ -162,8 +162,10 @@ void ElectronRendererClient::WillReleaseScriptContext( isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kExplicit); node::FreeEnvironment(env); - if (env == node_bindings_->uv_env()) + if (node_bindings_->uv_env() == nullptr) { node::FreeIsolateData(node_bindings_->isolate_data()); + node_bindings_->set_isolate_data(nullptr); + } isolate->SetMicrotasksPolicy(old_policy);