Browse Source

fix: iocp integration when process is reused (#33207) (#33363)

Robo 3 years ago
parent
commit
45e14a5ef5

+ 2 - 12
shell/common/node_bindings.cc

@@ -462,8 +462,8 @@ node::Environment* NodeBindings::CreateEnvironment(
 
   args.insert(args.begin() + 1, init_script);
 
-  isolate_data_ =
-      node::CreateIsolateData(context->GetIsolate(), 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 +573,6 @@ void NodeBindings::LoadEnvironment(node::Environment* env) {
 }
 
 void NodeBindings::PrepareMessageLoop() {
-#if !defined(OS_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);

+ 5 - 5
shell/common/node_bindings.h

@@ -94,11 +94,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.
@@ -158,10 +162,6 @@ class NodeBindings {
   // Isolate data used in creating the environment
   node::IsolateData* isolate_data_ = nullptr;
 
-#if !defined(OS_WIN)
-  int handle_ = -1;
-#endif
-
   base::WeakPtrFactory<NodeBindings> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(NodeBindings);

+ 18 - 0
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;

+ 4 - 0
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:
@@ -26,6 +27,9 @@ class NodeBindingsLinux : public NodeBindings {
   // Epoll to poll for uv's backend fd.
   int epoll_;
 
+  // uv's backend fd.
+  int handle_ = -1;
+
   DISALLOW_COPY_AND_ASSIGN(NodeBindingsLinux);
 };
 

+ 18 - 0
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;

+ 4 - 0
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:
@@ -23,6 +24,9 @@ class NodeBindingsMac : public NodeBindings {
 
   void PollEvents() override;
 
+  // uv's backend fd.
+  int handle_ = -1;
+
   DISALLOW_COPY_AND_ASSIGN(NodeBindingsMac);
 };
 

+ 23 - 0
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.

+ 6 - 0
shell/common/node_bindings_win.h

@@ -15,9 +15,15 @@ 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;
+
   DISALLOW_COPY_AND_ASSIGN(NodeBindingsWin);
 };
 

+ 3 - 1
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);