зеркало из https://github.com/mozilla/gecko-dev.git
Bug 684887 part B - make a SafeMutex which should crash if you try to recursively lock it, instead of deadlocking. r=bent
--HG-- extra : rebase_source : 694c5cd571e5802ce5e5af4ea03b9edc7e6fb8d4
This commit is contained in:
Родитель
e70052ad37
Коммит
94560defeb
|
@ -203,7 +203,7 @@ namespace {
|
|||
class NS_STACK_CLASS MutexLock
|
||||
{
|
||||
public:
|
||||
MutexLock(Mutex& aMutex)
|
||||
MutexLock(SafeMutex& aMutex)
|
||||
: mMutex(aMutex)
|
||||
, mLocked(false)
|
||||
{
|
||||
|
@ -231,7 +231,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
Mutex& mMutex;
|
||||
SafeMutex& mMutex;
|
||||
bool mLocked;
|
||||
};
|
||||
|
||||
|
@ -852,7 +852,7 @@ nsFactoryEntry *
|
|||
nsComponentManagerImpl::GetFactoryEntry(const char *aContractID,
|
||||
uint32_t aContractIDLen)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
SafeMutexAutoLock lock(mLock);
|
||||
return mContractIDs.Get(nsDependentCString(aContractID, aContractIDLen));
|
||||
}
|
||||
|
||||
|
@ -860,7 +860,7 @@ nsComponentManagerImpl::GetFactoryEntry(const char *aContractID,
|
|||
nsFactoryEntry *
|
||||
nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
SafeMutexAutoLock lock(mLock);
|
||||
return mFactories.Get(aClass);
|
||||
}
|
||||
|
||||
|
@ -1220,7 +1220,7 @@ nsComponentManagerImpl::GetService(const nsCID& aClass,
|
|||
}
|
||||
|
||||
|
||||
MutexAutoUnlock unlockPending(mLock);
|
||||
SafeMutexAutoUnlock unlockPending(mLock);
|
||||
|
||||
if (!currentThread) {
|
||||
currentThread = NS_GetCurrentThread();
|
||||
|
@ -1253,7 +1253,7 @@ nsComponentManagerImpl::GetService(const nsCID& aClass,
|
|||
|
||||
nsresult rv;
|
||||
{
|
||||
MutexAutoUnlock unlock(mLock);
|
||||
SafeMutexAutoUnlock unlock(mLock);
|
||||
rv = CreateInstance(aClass, nullptr, aIID, getter_AddRefs(service));
|
||||
}
|
||||
if (NS_SUCCEEDED(rv) && !service) {
|
||||
|
@ -1310,7 +1310,7 @@ nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass,
|
|||
nsFactoryEntry* entry;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
SafeMutexAutoLock lock(mLock);
|
||||
entry = mFactories.Get(aClass);
|
||||
}
|
||||
|
||||
|
@ -1347,7 +1347,7 @@ NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const ch
|
|||
nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
|
||||
nsFactoryEntry *entry;
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
SafeMutexAutoLock lock(mLock);
|
||||
entry = mContractIDs.Get(nsDependentCString(aContractID));
|
||||
}
|
||||
|
||||
|
@ -1412,7 +1412,7 @@ nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
MutexAutoUnlock unlockPending(mLock);
|
||||
SafeMutexAutoUnlock unlockPending(mLock);
|
||||
|
||||
if (!currentThread) {
|
||||
currentThread = NS_GetCurrentThread();
|
||||
|
@ -1445,7 +1445,7 @@ nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
|
|||
|
||||
nsresult rv;
|
||||
{
|
||||
MutexAutoUnlock unlock(mLock);
|
||||
SafeMutexAutoUnlock unlock(mLock);
|
||||
rv = CreateInstanceByContractID(aContractID, nullptr, aIID,
|
||||
getter_AddRefs(service));
|
||||
}
|
||||
|
@ -1505,7 +1505,7 @@ nsComponentManagerImpl::RegisterFactory(const nsCID& aClass,
|
|||
if (!aContractID)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
MutexAutoLock lock(mLock);
|
||||
SafeMutexAutoLock lock(mLock);
|
||||
nsFactoryEntry* oldf = mFactories.Get(aClass);
|
||||
if (!oldf)
|
||||
return NS_ERROR_FACTORY_NOT_REGISTERED;
|
||||
|
@ -1516,7 +1516,7 @@ nsComponentManagerImpl::RegisterFactory(const nsCID& aClass,
|
|||
|
||||
nsAutoPtr<nsFactoryEntry> f(new nsFactoryEntry(aClass, aFactory));
|
||||
|
||||
MutexAutoLock lock(mLock);
|
||||
SafeMutexAutoLock lock(mLock);
|
||||
nsFactoryEntry* oldf = mFactories.Get(aClass);
|
||||
if (oldf)
|
||||
return NS_ERROR_FACTORY_EXISTS;
|
||||
|
@ -1539,7 +1539,7 @@ nsComponentManagerImpl::UnregisterFactory(const nsCID& aClass,
|
|||
nsCOMPtr<nsISupports> dyingServiceObject;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
SafeMutexAutoLock lock(mLock);
|
||||
nsFactoryEntry* f = mFactories.Get(aClass);
|
||||
if (!f || f->mFactory != aFactory)
|
||||
return NS_ERROR_FACTORY_NOT_REGISTERED;
|
||||
|
@ -1666,7 +1666,7 @@ nsComponentManagerImpl::ContractIDToCID(const char *aContractID,
|
|||
nsCID * *_retval)
|
||||
{
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
SafeMutexAutoLock lock(mLock);
|
||||
nsFactoryEntry* entry = mContractIDs.Get(nsDependentCString(aContractID));
|
||||
if (entry) {
|
||||
*_retval = (nsCID*) NS_Alloc(sizeof(nsCID));
|
||||
|
@ -1792,7 +1792,7 @@ nsFactoryEntry::GetFactory()
|
|||
if (!factory)
|
||||
return NULL;
|
||||
|
||||
MutexAutoLock lock(nsComponentManagerImpl::gComponentManager->mLock);
|
||||
SafeMutexAutoLock lock(nsComponentManagerImpl::gComponentManager->mLock);
|
||||
// Threads can race to set mFactory
|
||||
if (!mFactory) {
|
||||
factory.swap(mFactory);
|
||||
|
|
|
@ -64,6 +64,59 @@ extern const char staticComponentType[];
|
|||
|
||||
extern const mozilla::Module kXPCOMModule;
|
||||
|
||||
/**
|
||||
* This is a wrapper around mozilla::Mutex which provides runtime
|
||||
* checking for a deadlock where the same thread tries to lock a mutex while
|
||||
* it is already locked. This checking is present in both debug and release
|
||||
* builds.
|
||||
*/
|
||||
class SafeMutex
|
||||
{
|
||||
public:
|
||||
SafeMutex(const char* name)
|
||||
: mMutex(name)
|
||||
, mOwnerThread(nullptr)
|
||||
{ }
|
||||
~SafeMutex()
|
||||
{ }
|
||||
|
||||
void Lock()
|
||||
{
|
||||
AssertNotCurrentThreadOwns();
|
||||
mMutex.Lock();
|
||||
MOZ_ASSERT(mOwnerThread == nullptr);
|
||||
mOwnerThread = PR_GetCurrentThread();
|
||||
}
|
||||
|
||||
void Unlock()
|
||||
{
|
||||
MOZ_ASSERT(mOwnerThread == PR_GetCurrentThread());
|
||||
mOwnerThread = nullptr;
|
||||
mMutex.Unlock();
|
||||
}
|
||||
|
||||
void AssertCurrentThreadOwns() const
|
||||
{
|
||||
// This method is a debug-only check
|
||||
MOZ_ASSERT(mOwnerThread == PR_GetCurrentThread());
|
||||
}
|
||||
|
||||
MOZ_NEVER_INLINE void AssertNotCurrentThreadOwns() const
|
||||
{
|
||||
// This method is a release-mode check
|
||||
if (PR_GetCurrentThread() == mOwnerThread) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mozilla::Mutex mMutex;
|
||||
volatile PRThread* mOwnerThread;
|
||||
};
|
||||
|
||||
typedef mozilla::BaseAutoLock<SafeMutex> SafeMutexAutoLock;
|
||||
typedef mozilla::BaseAutoUnlock<SafeMutex> SafeMutexAutoUnlock;
|
||||
|
||||
class nsComponentManagerImpl MOZ_FINAL
|
||||
: public nsIComponentManager
|
||||
, public nsIServiceManager
|
||||
|
@ -112,7 +165,7 @@ public:
|
|||
nsDataHashtable<nsIDHashKey, nsFactoryEntry*> mFactories;
|
||||
nsDataHashtable<nsCStringHashKey, nsFactoryEntry*> mContractIDs;
|
||||
|
||||
mozilla::Mutex mLock;
|
||||
SafeMutex mLock;
|
||||
|
||||
static void InitializeStaticModules();
|
||||
static void InitializeModuleLocations();
|
||||
|
|
Загрузка…
Ссылка в новой задаче