Bug 1140051 Avoid Cache shutdown assert when Manager alive, but not active. r=ehsan

This commit is contained in:
Ben Kelly 2015-03-06 13:39:05 -08:00
Родитель d1329c9051
Коммит 1fe91838f1
1 изменённых файлов: 33 добавлений и 9 удалений

42
dom/cache/Manager.cpp поставляемый
Просмотреть файл

@ -6,6 +6,7 @@
#include "mozilla/dom/cache/Manager.h" #include "mozilla/dom/cache/Manager.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/Mutex.h" #include "mozilla/Mutex.h"
#include "mozilla/StaticMutex.h" #include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h" #include "mozilla/StaticPtr.h"
@ -197,9 +198,7 @@ public:
MOZ_ALWAYS_TRUE(sFactory->mManagerList.RemoveElement(aManager)); MOZ_ALWAYS_TRUE(sFactory->mManagerList.RemoveElement(aManager));
// clean up the factory singleton if there are no more managers // clean up the factory singleton if there are no more managers
if (sFactory->mManagerList.IsEmpty()) { MaybeDestroyInstance();
DestroyInstance();
}
} }
static void static void
@ -236,6 +235,7 @@ public:
private: private:
Factory() Factory()
: mInSyncShutdown(false)
{ {
MOZ_COUNT_CTOR(cache::Manager::Factory); MOZ_COUNT_CTOR(cache::Manager::Factory);
} }
@ -244,6 +244,7 @@ private:
{ {
MOZ_COUNT_DTOR(cache::Manager::Factory); MOZ_COUNT_DTOR(cache::Manager::Factory);
MOZ_ASSERT(mManagerList.IsEmpty()); MOZ_ASSERT(mManagerList.IsEmpty());
MOZ_ASSERT(!mInSyncShutdown);
} }
static nsresult static nsresult
@ -264,7 +265,7 @@ private:
// Cannot use ClearOnShutdown() because we're on the background thread. // Cannot use ClearOnShutdown() because we're on the background thread.
// This is automatically cleared when Factory::Remove() calls // This is automatically cleared when Factory::Remove() calls
// DestroyInstance(). // MaybeDestroyInstance().
MOZ_ASSERT(!sBackgroundThread); MOZ_ASSERT(!sBackgroundThread);
sBackgroundThread = NS_GetCurrentThread(); sBackgroundThread = NS_GetCurrentThread();
} }
@ -285,11 +286,19 @@ private:
} }
static void static void
DestroyInstance() MaybeDestroyInstance()
{ {
mozilla::ipc::AssertIsOnBackgroundThread(); mozilla::ipc::AssertIsOnBackgroundThread();
MOZ_ASSERT(sFactory); MOZ_ASSERT(sFactory);
// If the factory is is still in use then we cannot delete yet. This
// could be due to managers still existing or because we are in the
// middle of shutting down. We need to be careful not to delete ourself
// synchronously during shutdown.
if (!sFactory->mManagerList.IsEmpty() || sFactory->mInSyncShutdown) {
return;
}
// Be clear about what we are locking. sFactory is bg thread only, so // Be clear about what we are locking. sFactory is bg thread only, so
// we don't need to lock it here. Just protect sBackgroundThread. // we don't need to lock it here. Just protect sBackgroundThread.
{ {
@ -320,11 +329,21 @@ private:
MOZ_ASSERT(!sFactory->mManagerList.IsEmpty()); MOZ_ASSERT(!sFactory->mManagerList.IsEmpty());
ManagerList::ForwardIterator iter(sFactory->mManagerList); {
while (iter.HasMore()) { // Note that we are synchronously calling shutdown code here. If any
nsRefPtr<Manager> manager = iter.GetNext(); // of the shutdown code synchronously decides to delete the Factory
manager->Shutdown(); // we need to delay that delete until the end of this method.
AutoRestore<bool> restore(sFactory->mInSyncShutdown);
sFactory->mInSyncShutdown = true;
ManagerList::ForwardIterator iter(sFactory->mManagerList);
while (iter.HasMore()) {
nsRefPtr<Manager> manager = iter.GetNext();
manager->Shutdown();
}
} }
MaybeDestroyInstance();
} }
class ShutdownAllRunnable MOZ_FINAL : public nsRunnable class ShutdownAllRunnable MOZ_FINAL : public nsRunnable
@ -363,6 +382,11 @@ private:
// PBackground thread only. // PBackground thread only.
typedef nsTObserverArray<Manager*> ManagerList; typedef nsTObserverArray<Manager*> ManagerList;
ManagerList mManagerList; ManagerList mManagerList;
// This flag is set when we are looping through the list and calling
// Shutdown() on each Manager. We need to be careful not to synchronously
// trigger the deletion of the factory while still executing this loop.
bool mInSyncShutdown;
}; };
// static // static