Bug 1388998 - Drop final Connection reference after finishing guarded connection list mutation. r=mak

--HG--
extra : rebase_source : 1c87e01c114e50fd54f8bf93fc835bd0e58a2d68
This commit is contained in:
Andrew Sutherland 2017-10-03 01:14:22 -04:00
parent b66a653de9
commit c7ad213382

View File

@ -302,27 +302,38 @@ Service::unregisterConnection(Connection *aConnection)
// alive. So ensure that Service is destroyed only after the Connection is
// cleanly unregistered and destroyed.
RefPtr<Service> kungFuDeathGrip(this);
RefPtr<Connection> forgettingRef;
{
mRegistrationMutex.AssertNotCurrentThreadOwns();
MutexAutoLock mutex(mRegistrationMutex);
for (uint32_t i = 0 ; i < mConnections.Length(); ++i) {
if (mConnections[i] == aConnection) {
nsCOMPtr<nsIThread> thread = mConnections[i]->threadOpenedOn;
// Ensure the connection is released on its opening thread. Note, we
// must use .forget().take() so that we can manually cast to an
// unambiguous nsISupports type.
NS_ProxyRelease(
"storage::Service::mConnections", thread, mConnections[i].forget());
// Because dropping the final reference can potentially result in
// spinning a nested event loop if the connection was not properly
// shutdown, we want to do that outside this loop so that we can finish
// mutating the array and drop our mutex.
forgettingRef = mConnections[i].forget();
mConnections.RemoveElementAt(i);
return;
break;
}
}
MOZ_ASSERT_UNREACHABLE("Attempt to unregister unknown storage connection!");
}
MOZ_ASSERT(forgettingRef,
"Attempt to unregister unknown storage connection!");
// Ensure the connection is released on its opening thread. We explicitly use
// aAlwaysDispatch=false because at the time of writing this, LocalStorage's
// StorageDBThread uses a hand-rolled PRThread implementation that cannot
// handle us dispatching events at it during shutdown. However, it is
// arguably also desirable for callers to not be aware of our connection
// tracking mechanism. And by synchronously dropping the reference (when
// on the correct thread), this avoids surprises for the caller and weird
// shutdown edge cases.
nsCOMPtr<nsIThread> thread = forgettingRef->threadOpenedOn;
NS_ProxyRelease(
"storage::Service::mConnections", thread, forgettingRef.forget(), false);
}
void