Bug 1151609 - WebSocket::CloseConnection must be thread-safe. r=smaug, a=sledru
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 08 Apr 2015 19:09:26 +0100
changeset 258405 07f2a01649a4
parent 258404 6ab02e48d0c2
child 258406 367745bbac8a
push id4659
push userryanvm@gmail.com
push date2015-04-09 15:23 +0000
treeherdermozilla-beta@58dca3f7560a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, sledru
bugs1151609
milestone38.0
Bug 1151609 - WebSocket::CloseConnection must be thread-safe. r=smaug, a=sledru
dom/base/WebSocket.cpp
--- a/dom/base/WebSocket.cpp
+++ b/dom/base/WebSocket.cpp
@@ -460,23 +460,51 @@ public:
       mImpl->Disconnect();
     }
   }
 
 private:
   WebSocketImpl* mImpl;
 };
 
+class CloseConnectionRunnable final : public nsRunnable
+{
+public:
+  CloseConnectionRunnable(WebSocketImpl* aImpl,
+                          uint16_t aReasonCode,
+                          const nsACString& aReasonString)
+    : mImpl(aImpl)
+    , mReasonCode(aReasonCode)
+    , mReasonString(aReasonString)
+  {}
+
+  NS_IMETHOD Run() override
+  {
+    return mImpl->CloseConnection(mReasonCode, mReasonString);
+  }
+
+private:
+  nsRefPtr<WebSocketImpl> mImpl;
+  uint16_t mReasonCode;
+  const nsCString mReasonString;
+};
+
 } // anonymous namespace
 
 nsresult
 WebSocketImpl::CloseConnection(uint16_t aReasonCode,
                                const nsACString& aReasonString,
                                bool aCanceling)
 {
+  if (!IsTargetThread()) {
+    nsRefPtr<nsRunnable> runnable =
+      new CloseConnectionRunnable(this, aReasonCode, aReasonString);
+    return Dispatch(runnable, NS_DISPATCH_NORMAL);
+  }
+
   AssertIsOnTargetThread();
   MOZ_ASSERT(!NS_IsMainThread() || !aCanceling);
 
   if (mDisconnectingOrDisconnected) {
     return NS_OK;
   }
 
   // If this method is called because the worker is going away, we will not
@@ -508,17 +536,16 @@ WebSocketImpl::CloseConnection(uint16_t 
 
     nsRefPtr<CloseRunnable> runnable =
       new CloseRunnable(this, aReasonCode, aReasonString);
     runnable->Dispatch(mWorkerPrivate->GetJSContext());
     return runnable->ErrorCode();
   }
 
   // No channel, but not disconnected: canceled or failed early
-  //
   MOZ_ASSERT(readyState == WebSocket::CONNECTING,
              "Should only get here for early websocket cancel/error");
 
   // Server won't be sending us a close code, so use what's passed in here.
   mCloseEventCode = aReasonCode;
   CopyUTF8toUTF16(aReasonString, mCloseEventReason);
 
   mWebSocket->SetReadyState(WebSocket::CLOSING);
@@ -659,20 +686,22 @@ WebSocketImpl::DisconnectInternal()
   nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakLoadGroup);
   if (loadGroup) {
     loadGroup->RemoveRequest(this, nullptr, NS_OK);
     // mWeakLoadGroup has to be release on main-thread because WeakReferences
     // are not thread-safe.
     mWeakLoadGroup = nullptr;
   }
 
-  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-  if (os) {
-    os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
-    os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
+  if (!mWorkerPrivate) {
+    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+    if (os) {
+      os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
+      os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
+    }
   }
 }
 
 //-----------------------------------------------------------------------------
 // WebSocketImpl::nsIWebSocketListener methods:
 //-----------------------------------------------------------------------------
 
 nsresult