Bug 1256022 - dom/network slow GC on mochitest fix r=dragana a=ritu
MozReview-Commit-ID: KiR12RBXYas
--- a/dom/network/TCPSocket.cpp
+++ b/dom/network/TCPSocket.cpp
@@ -157,16 +157,17 @@ TCPSocket::TCPSocket(nsIGlobalObject* aG
, mSsl(aSsl)
, mAsyncCopierActive(false)
, mWaitingForDrain(false)
, mInnerWindowID(0)
, mBufferedAmount(0)
, mSuspendCount(0)
, mTrackingNumber(0)
, mWaitingForStartTLS(false)
+ , mObserversActive(false)
#ifdef MOZ_WIDGET_GONK
, mTxBytes(0)
, mRxBytes(0)
, mAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID)
, mInIsolatedMozBrowser(false)
#endif
{
if (aGlobal) {
@@ -174,16 +175,23 @@ TCPSocket::TCPSocket(nsIGlobalObject* aG
if (window) {
mInnerWindowID = window->WindowID();
}
}
}
TCPSocket::~TCPSocket()
{
+ if (mObserversActive) {
+ nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1");
+ if (obs) {
+ obs->RemoveObserver(this, "inner-window-destroyed");
+ obs->RemoveObserver(this, "profile-change-net-teardown");
+ }
+ }
}
nsresult
TCPSocket::CreateStream()
{
nsresult rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(mSocketInputStream));
NS_ENSURE_SUCCESS(rv, rv);
rv = mTransport->OpenOutputStream(nsITransport::OPEN_UNBUFFERED, 0, 0, getter_AddRefs(mSocketOutputStream));
@@ -253,17 +261,19 @@ TCPSocket::InitWithUnconnectedTransport(
return NS_OK;
}
nsresult
TCPSocket::Init()
{
nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1");
if (obs) {
- obs->AddObserver(this, "inner-window-destroyed", true);
+ mObserversActive = true;
+ obs->AddObserver(this, "inner-window-destroyed", true); // weak reference
+ obs->AddObserver(this, "profile-change-net-teardown", true); // weak ref
}
if (XRE_GetProcessType() == GeckoProcessType_Content) {
mReadyState = TCPReadyState::Connecting;
mSocketBridgeChild = new TCPSocketChild(mHost, mPort);
mSocketBridgeChild->SendOpen(this, mSsl, mUseArrayBuffers);
return NS_OK;
}
@@ -371,16 +381,17 @@ CopierCallbacks::OnStartRequest(nsIReque
{
return NS_OK;
}
NS_IMETHODIMP
CopierCallbacks::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus)
{
mOwner->NotifyCopyComplete(aStatus);
+ mOwner = nullptr;
return NS_OK;
}
} // unnamed namespace
nsresult
TCPSocket::EnsureCopying()
{
if (mAsyncCopierActive) {
@@ -437,17 +448,20 @@ TCPSocket::NotifyCopyComplete(nsresult a
// If we have a connected child, we let the child decide whether
// ondrain should be dispatched.
if (mWaitingForDrain && !mSocketBridgeParent) {
mWaitingForDrain = false;
FireEvent(NS_LITERAL_STRING("drain"));
}
if (mReadyState == TCPReadyState::Closing) {
- mSocketOutputStream->Close();
+ if (mSocketOutputStream) {
+ mSocketOutputStream->Close();
+ mSocketOutputStream = nullptr;
+ }
mReadyState = TCPReadyState::Closed;
FireEvent(NS_LITERAL_STRING("close"));
}
}
void
TCPSocket::ActivateTLS()
{
@@ -629,16 +643,19 @@ TCPSocket::MaybeReportErrorAndCloseIfOpe
SaveNetworkStats(true);
#endif
// If we're closed, we've already reported the error or just don't need to
// report the error.
if (mReadyState == TCPReadyState::Closed) {
return NS_OK;
}
+
+ // go through ::Closing state and then mark ::Closed
+ Close();
mReadyState = TCPReadyState::Closed;
if (NS_FAILED(status)) {
// Convert the status code to an appropriate error message.
nsString errorType, errName;
// security module? (and this is an error)
@@ -753,21 +770,29 @@ TCPSocket::Close()
mReadyState = TCPReadyState::Closing;
if (mSocketBridgeChild) {
mSocketBridgeChild->SendClose();
return;
}
uint32_t count = 0;
- mMultiplexStream->GetCount(&count);
+ if (mMultiplexStream) {
+ mMultiplexStream->GetCount(&count);
+ }
if (!count) {
- mSocketOutputStream->Close();
+ if (mSocketOutputStream) {
+ mSocketOutputStream->Close();
+ mSocketOutputStream = nullptr;
+ }
}
- mSocketInputStream->Close();
+ if (mSocketInputStream) {
+ mSocketInputStream->Close();
+ mSocketInputStream = nullptr;
+ }
}
void
TCPSocket::SendWithTrackingNumber(const nsACString& aData,
const uint32_t& aTrackingNumber,
mozilla::ErrorResult& aRv)
{
MOZ_ASSERT(mSocketBridgeParent);
@@ -950,16 +975,19 @@ TCPSocket::Constructor(const GlobalObjec
}
return socket.forget();
}
nsresult
TCPSocket::CreateInputStreamPump()
{
+ if (!mSocketInputStream) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
nsresult rv;
mInputStreamPump = do_CreateInstance("@mozilla.org/network/input-stream-pump;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = mInputStreamPump->Init(mSocketInputStream, -1, -1, 0, 0, false);
NS_ENSURE_SUCCESS(rv, rv);
uint64_t suspendCount = mSuspendCount;
@@ -1171,23 +1199,20 @@ TCPSocket::Observe(nsISupports* aSubject
NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
uint64_t innerID;
nsresult rv = wrapper->GetData(&innerID);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (innerID == mInnerWindowID) {
- nsCOMPtr<nsIObserverService> obs = do_GetService("@mozilla.org/observer-service;1");
- if (obs) {
- obs->RemoveObserver(this, "inner-window-destroyed");
- }
-
Close();
}
+ } else if (!strcmp(aTopic, "profile-change-net-teardown")) {
+ Close();
}
return NS_OK;
}
/* static */
bool
TCPSocket::ShouldTCPSocketExist(JSContext* aCx, JSObject* aGlobal)
--- a/dom/network/TCPSocket.h
+++ b/dom/network/TCPSocket.h
@@ -230,16 +230,18 @@ private:
uint32_t mTrackingNumber;
// True if this socket has been upgraded to secure after the initial connection,
// but the actual upgrade is waiting for an in-progress copy operation to complete.
bool mWaitingForStartTLS;
// The buffered data awaiting the TLS upgrade to finish.
nsTArray<nsCOMPtr<nsIInputStream>> mPendingDataAfterStartTLS;
+ bool mObserversActive;
+
#ifdef MOZ_WIDGET_GONK
// Number of bytes sent.
uint32_t mTxBytes;
// Number of bytes received.
uint32_t mRxBytes;
// The app that owns this socket.
uint32_t mAppId;
// Was this socket created inside of an isolated browser frame?
--- a/dom/network/tests/test_tcpsocket_enabled_with_perm.html
+++ b/dom/network/tests/test_tcpsocket_enabled_with_perm.html
@@ -21,14 +21,17 @@ SpecialPowers.pushPrefEnv({"set": [['dom
SpecialPowers.pushPermissions([{type: "tcp-socket", allow: true, context: document}], runTest);
});
function runTest() {
ok('TCPSocket' in this, "TCPSocket should be accessible if dom.mozTCPSocket.enabled is true");
ok(new TCPSocket('localhost', 80), "TCPSocket constructor should work for content that has the tcp-socket permission");
ok(navigator.mozTCPSocket.open('localhost', 80), "navigator.mozTCPSocket.open should work for content that has the tcp-socket permission");
+ // This just helps the test harness clean up quickly
+ SpecialPowers.forceCC();
+ SpecialPowers.forceGC();
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>
--- a/dom/network/tests/test_tcpsocket_legacy.html
+++ b/dom/network/tests/test_tcpsocket_legacy.html
@@ -35,22 +35,31 @@ Test of legacy navigator interface for o
// test was using.
var serverPort = 8085;
var listeningServer = navigator.mozTCPSocket.listen(serverPort,
{ binaryType: 'arraybuffer' },
-1);
listeningServer.onconnect = function(ev) {
ok(true, "got server connect");
+ listeningServer.close();
+ listeningServer = null;
ev.socket.close()
}
var clientSocket = navigator.mozTCPSocket.open('127.0.0.1', serverPort,
{ binaryType: 'arraybuffer' });
clientSocket.onopen = function() { ok(true, "got client open"); }
clientSocket.onclose = function() {
ok(true, "got client close");
- SimpleTest.finish();
+ clientSocket.close();
+ clientSocket = null;
+ setTimeout(function() {
+ // This just helps the test harness clean up quickly
+ SpecialPowers.forceCC();
+ SpecialPowers.forceGC();
+ SimpleTest.finish();
+ }, 0);
}
}
</script>
</body>
</html>