Bug 921850 - Fix races in debugger client when connecting agressively r=past
authorAlexandre Poirot <poirot.alex@gmail.com>
Mon, 21 Oct 2013 01:56:00 +0300
changeset 165605 568d296995e0d806e8e7fadca1d2dfeeb2e7f301
parent 165584 4e075a69e78b7beaf61a472f3030c1602ab7b2b2
child 165606 7bdb63636763a8f41a09639f9b8570fa2f8f4ad9
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspast
bugs921850
milestone27.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 921850 - Fix races in debugger client when connecting agressively r=past
browser/devtools/framework/connect/connect.js
toolkit/devtools/client/connection-manager.js
toolkit/devtools/client/dbg-client.jsm
--- a/browser/devtools/framework/connect/connect.js
+++ b/browser/devtools/framework/connect/connect.js
@@ -49,17 +49,24 @@ function submit() {
   // Save the host/port values
   let host = document.getElementById("host").value;
   Services.prefs.setCharPref("devtools.debugger.remote-host", host);
 
   let port = document.getElementById("port").value;
   Services.prefs.setIntPref("devtools.debugger.remote-port", port);
 
   // Initiate the connection
-  let transport = debuggerSocketConnect(host, port);
+  let transport;
+  try {
+    transport = debuggerSocketConnect(host, port);
+  } catch(e) {
+    // Bug 921850: catch rare exception from debuggerSocketConnect
+    showError("unexpected");
+    return;
+  }
   gClient = new DebuggerClient(transport);
   let delay = Services.prefs.getIntPref("devtools.debugger.remote-timeout");
   gConnectionTimeout = setTimeout(handleConnectionTimeout, delay);
   gClient.connect(onConnectionReady);
 }
 
 /**
  * Connection is ready. List actors and build buttons.
--- a/toolkit/devtools/client/connection-manager.js
+++ b/toolkit/devtools/client/connection-manager.js
@@ -216,17 +216,27 @@ Connection.prototype = {
     this._setStatus(Connection.Status.DESTROYED);
   },
 
   _clientConnect: function () {
     let transport;
     if (!this.host) {
       transport = DebuggerServer.connectPipe();
     } else {
-      transport = debuggerSocketConnect(this.host, this.port);
+      try {
+        transport = debuggerSocketConnect(this.host, this.port);
+      } catch (e) {
+        // In some cases, especially on Mac, the openOutputStream call in
+        // debuggerSocketConnect may throw NS_ERROR_NOT_INITIALIZED.
+        // It occurs when we connect agressively to the simulator,
+        // and keep trying to open a socket to the server being started in
+        // the simulator.
+        this._onDisconnected();
+        return;
+      }
     }
     this._client = new DebuggerClient(transport);
     this._client.addOneTimeListener("closed", this._onDisconnected);
     this._client.connect(this._onConnected);
   },
 
   get status() {
     return this._status
@@ -239,17 +249,17 @@ Connection.prototype = {
     this.emit(value);
     this.emit(Connection.Events.STATUS_CHANGED, value);
   },
 
   _onDisconnected: function() {
     this._client = null;
 
     if (this._status == Connection.Status.CONNECTING && this.keepConnecting) {
-      setTimeout(() => this._clientConnect(), 0);
+      setTimeout(() => this._clientConnect(), 100);
       return;
     }
 
     clearTimeout(this._timeoutID);
 
     switch (this.status) {
       case Connection.Status.CONNECTED:
         this.log("disconnected (unexpected)");
--- a/toolkit/devtools/client/dbg-client.jsm
+++ b/toolkit/devtools/client/dbg-client.jsm
@@ -2195,18 +2195,34 @@ eventSource(EnvironmentClient.prototype)
  * @param aHost string
  *        The host name or IP address of the debugger server.
  * @param aPort number
  *        The port number of the debugger server.
  */
 this.debuggerSocketConnect = function debuggerSocketConnect(aHost, aPort)
 {
   let s = socketTransportService.createTransport(null, 0, aHost, aPort, null);
-  let transport = new DebuggerTransport(s.openInputStream(0, 0, 0),
-                                        s.openOutputStream(0, 0, 0));
+  // By default the CONNECT socket timeout is very long, 65535 seconds,
+  // so that if we race to be in CONNECT state while the server socket is still
+  // initializing, the connection is stuck in connecting state for 18.20 hours!
+  s.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, 2);
+
+  // openOutputStream may throw NS_ERROR_NOT_INITIALIZED if we hit some race
+  // where the nsISocketTransport gets shutdown in between its instantiation and
+  // the call to this method.
+  let transport;
+  try {
+    transport = new DebuggerTransport(s.openInputStream(0, 0, 0),
+                                      s.openOutputStream(0, 0, 0));
+  } catch(e) {
+    let msg = e + ": " + e.stack;
+    Cu.reportError(msg);
+    dumpn(msg);
+    throw e;
+  }
   return transport;
 }
 
 /**
  * Takes a pair of items and returns them as an array.
  */
 function pair(aItemOne, aItemTwo) {
   return [aItemOne, aItemTwo];