diff --git a/dom/websocket/WebSocket.cpp b/dom/websocket/WebSocket.cpp index a92ba2d5c7e0..305a6c9a7ca7 100644 --- a/dom/websocket/WebSocket.cpp +++ b/dom/websocket/WebSocket.cpp @@ -225,8 +225,6 @@ class WebSocketImpl final : public nsIInterfaceRequestor, private: ~WebSocketImpl() { - MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread() == mIsMainThread); - // If we threw during Init we never called disconnect if (!mDisconnectingOrDisconnected) { Disconnect(); @@ -234,9 +232,42 @@ class WebSocketImpl final : public nsIInterfaceRequestor, } }; -NS_IMPL_ISUPPORTS(WebSocketImpl, nsIInterfaceRequestor, nsIWebSocketListener, - nsIObserver, nsISupportsWeakReference, nsIRequest, - nsIEventTarget) +NS_IMPL_ADDREF(WebSocketImpl) +NS_IMPL_QUERY_INTERFACE(WebSocketImpl, nsIInterfaceRequestor, + nsIWebSocketListener, nsIObserver, + nsISupportsWeakReference, nsIRequest, nsIEventTarget) + +NS_IMETHODIMP_(MozExternalRefCountType) WebSocketImpl::Release(void) { + MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); + + if (!mRefCnt.isThreadSafe) { + NS_ASSERT_OWNINGTHREAD(WebSocketImpl); + } + + nsrefcnt count = mRefCnt - 1; + // If WebSocketImpl::Disconnect is not called, the last release of + // WebSocketImpl should be on the right thread. + if (count == 0 && !IsTargetThread() && !mDisconnectingOrDisconnected) { + DebugOnly rv = Dispatch(NewNonOwningRunnableMethod( + "dom::WebSocketImpl::Release", this, &WebSocketImpl::Release)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + return count; + } + + count = --mRefCnt; + NS_LOG_RELEASE(this, count, "WebSocketImpl"); + + if (count == 0) { + if (!mRefCnt.isThreadSafe) { + NS_ASSERT_OWNINGTHREAD(WebSocketImpl); + } + + mRefCnt = 1; /* stabilize */ + delete (this); + return 0; + } + return count; +} class CallDispatchConnectionCloseEvents final : public CancelableRunnable { public: @@ -541,12 +572,12 @@ class DisconnectInternalRunnable final : public WorkerMainThreadRunnable { } // namespace void WebSocketImpl::Disconnect() { - MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread() == mIsMainThread); - if (mDisconnectingOrDisconnected) { return; } + AssertIsOnTargetThread(); + // DontKeepAliveAnyMore() and DisconnectInternal() can release the object. So // hold a reference to this until the end of the method. RefPtr kungfuDeathGrip = this;