Bug 1395029 - Use blockThreadedExecution for debugging (r=jimb)
authorBill McCloskey <billm@mozilla.com>
Thu, 21 Sep 2017 15:58:30 -0700
changeset 444704 d1666bcca1a5c90372b9849dda2a1fa2b9326d9f
parent 444703 41d3c1e5dacc237ee9cb67e3c867fe7901162aa6
child 444705 ece293c2e9abbf0b10c9e5f587c5f20979aefd1a
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs1395029
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1395029 - Use blockThreadedExecution for debugging (r=jimb) MozReview-Commit-ID: 2KRXZrTulwU
devtools/server/child.js
devtools/server/content-server.jsm
--- a/devtools/server/child.js
+++ b/devtools/server/child.js
@@ -30,35 +30,44 @@ try {
 
     let onConnect = DevToolsUtils.makeInfallible(function (msg) {
       removeMessageListener("debug:connect", onConnect);
 
       let mm = msg.target;
       let prefix = msg.data.prefix;
       let addonId = msg.data.addonId;
 
-      let conn = DebuggerServer.connectToParent(prefix, mm);
-      conn.parentMessageManager = mm;
-      connections.set(prefix, conn);
+      // Using the JS debugger causes problems when we're trying to
+      // schedule those zone groups across different threads. Calling
+      // blockThreadedExecution causes Gecko to switch to a simpler
+      // single-threaded model until unblockThreadedExecution is
+      // called later. We cannot start the debugger until the callback
+      // passed to blockThreadedExecution has run, signaling that
+      // we're running single-threaded.
+      Cu.blockThreadedExecution(() => {
+        let conn = DebuggerServer.connectToParent(prefix, mm);
+        conn.parentMessageManager = mm;
+        connections.set(prefix, conn);
 
-      let actor;
+        let actor;
 
-      if (addonId) {
-        const { WebExtensionChildActor } = require("devtools/server/actors/webextension");
-        actor = new WebExtensionChildActor(conn, chromeGlobal, prefix, addonId);
-      } else {
-        const { ContentActor } = require("devtools/server/actors/childtab");
-        actor = new ContentActor(conn, chromeGlobal, prefix);
-      }
+        if (addonId) {
+          const { WebExtensionChildActor } = require("devtools/server/actors/webextension");
+          actor = new WebExtensionChildActor(conn, chromeGlobal, prefix, addonId);
+        } else {
+          const { ContentActor } = require("devtools/server/actors/childtab");
+          actor = new ContentActor(conn, chromeGlobal, prefix);
+        }
 
-      let actorPool = new ActorPool(conn);
-      actorPool.addActor(actor);
-      conn.addActorPool(actorPool);
+        let actorPool = new ActorPool(conn);
+        actorPool.addActor(actor);
+        conn.addActorPool(actorPool);
 
-      sendAsyncMessage("debug:actor", {actor: actor.form(), prefix: prefix});
+        sendAsyncMessage("debug:actor", {actor: actor.form(), prefix: prefix});
+      });
     });
 
     addMessageListener("debug:connect", onConnect);
 
     // Allows executing module setup helper from the parent process.
     // See also: DebuggerServer.setupInChild()
     let onSetupInChild = DevToolsUtils.makeInfallible(msg => {
       let { module, setupChild, args } = msg.data;
@@ -95,16 +104,18 @@ try {
       let conn = connections.get(prefix);
       if (!conn) {
         // Several copies of this frame script can be running for a single frame since it
         // is loaded once for each DevTools connection to the frame.  If this disconnect
         // request doesn't match a connection known here, ignore it.
         return;
       }
 
+      Cu.unblockThreadedExecution();
+
       removeMessageListener("debug:disconnect", onDisconnect);
       // Call DebuggerServerConnection.close to destroy all child actors. It should end up
       // calling DebuggerServerConnection.onClosed that would actually cleanup all actor
       // pools.
       conn.close();
       connections.delete(prefix);
     });
     addMessageListener("debug:disconnect", onDisconnect);
--- a/devtools/server/content-server.jsm
+++ b/devtools/server/content-server.jsm
@@ -36,41 +36,52 @@ function setupServer(mm) {
   // actors, but don't need all the "browser actors" that are only useful when
   // debugging the parent process via the browser toolbox.
   DebuggerServer.registerActors({ browser: false, root: true, tab: true });
 
   // Clean up things when the client disconnects
   mm.addMessageListener("debug:content-process-destroy", function onDestroy() {
     mm.removeMessageListener("debug:content-process-destroy", onDestroy);
 
+    Cu.unblockThreadedExecution();
+
     DebuggerServer.destroy();
     gLoader.destroy();
     gLoader = null;
   });
 
   return gLoader;
 }
 
 function init(msg) {
   let mm = msg.target;
   mm.QueryInterface(Ci.nsISyncMessageSender);
   let prefix = msg.data.prefix;
 
-  // Setup a server if none started yet
-  let loader = setupServer(mm);
-
-  // Connect both parent/child processes debugger servers RDP via message
-  // managers
-  let { DebuggerServer } = loader.require("devtools/server/main");
-  let conn = DebuggerServer.connectToParent(prefix, mm);
-  conn.parentMessageManager = mm;
+  // Using the JS debugger causes problems when we're trying to
+  // schedule those zone groups across different threads. Calling
+  // blockThreadedExecution causes Gecko to switch to a simpler
+  // single-threaded model until unblockThreadedExecution is called
+  // later. We cannot start the debugger until the callback passed to
+  // blockThreadedExecution has run, signaling that we're running
+  // single-threaded.
+  Cu.blockThreadedExecution(() => {
+    // Setup a server if none started yet
+    let loader = setupServer(mm);
 
-  let { ChildProcessActor } =
-    loader.require("devtools/server/actors/child-process");
-  let { ActorPool } = loader.require("devtools/server/main");
-  let actor = new ChildProcessActor(conn);
-  let actorPool = new ActorPool(conn);
-  actorPool.addActor(actor);
-  conn.addActorPool(actorPool);
+    // Connect both parent/child processes debugger servers RDP via message
+    // managers
+    let { DebuggerServer } = loader.require("devtools/server/main");
+    let conn = DebuggerServer.connectToParent(prefix, mm);
+    conn.parentMessageManager = mm;
 
-  let response = { actor: actor.form() };
-  mm.sendAsyncMessage("debug:content-process-actor", response);
+    let { ChildProcessActor } =
+        loader.require("devtools/server/actors/child-process");
+    let { ActorPool } = loader.require("devtools/server/main");
+    let actor = new ChildProcessActor(conn);
+    let actorPool = new ActorPool(conn);
+    actorPool.addActor(actor);
+    conn.addActorPool(actorPool);
+
+    let response = { actor: actor.form() };
+    mm.sendAsyncMessage("debug:content-process-actor", response);
+  });
 }