Protect the xptiWorkingSet's tables with a lock. (Bug 627985, bug 614480)

This commit is contained in:
L. David Baron 2011-04-10 17:12:52 -04:00
parent 8b31af0500
commit e1c0dab9dd
5 changed files with 72 additions and 53 deletions

View File

@ -619,7 +619,10 @@ xptiInterfaceEntry::HasAncestor(const nsIID * iid, PRBool *_retval)
nsresult
xptiInterfaceEntry::GetInterfaceInfo(xptiInterfaceInfo** info)
{
MonitorAutoEnter lock(xptiInterfaceInfoManager::GetInfoMonitor());
#ifdef DEBUG
xptiInterfaceInfoManager::GetSingleton()->GetWorkingSet()->mTableLock.
AssertCurrentThreadOwns();
#endif
LOG_INFO_MONITOR_ENTRY;
if(!mInfo)
@ -646,6 +649,19 @@ xptiInterfaceEntry::LockedInvalidateInterfaceInfo()
}
}
PRBool
xptiInterfaceInfo::BuildParent()
{
mozilla::MutexAutoLock lock(xptiInterfaceInfoManager::GetSingleton()->
GetWorkingSet()->mTableLock);
NS_ASSERTION(mEntry &&
mEntry->IsFullyResolved() &&
!mParent &&
mEntry->Parent(),
"bad BuildParent call");
return NS_SUCCEEDED(mEntry->Parent()->GetInterfaceInfo(&mParent));
}
/***************************************************************************/
NS_IMPL_QUERY_INTERFACE1(xptiInterfaceInfo, nsIInterfaceInfo)
@ -679,27 +695,35 @@ xptiInterfaceInfo::Release(void)
NS_LOG_RELEASE(this, cnt, "xptiInterfaceInfo");
if(!cnt)
{
MonitorAutoEnter lock(xptiInterfaceInfoManager::GetInfoMonitor());
LOG_INFO_MONITOR_ENTRY;
// If GetInterfaceInfo added and *released* a reference before we
// acquired the monitor then 'this' might already be dead. In that
// case we would not want to try to access any instance data. We
// would want to bail immediately. If 'this' is already dead then the
// entry will no longer have a pointer to 'this'. So, we can protect
// ourselves from danger without more aggressive locking.
if(entry && !entry->InterfaceInfoEquals(this))
return 0;
// If GetInterfaceInfo added a reference before we acquired the monitor
// then we want to bail out of here without destorying the object.
if(mRefCnt)
return 1;
if(mEntry)
// Need to exit the lock before calling |delete this|, since
// that release mParent, which can re-enter this function.
{
mEntry->LockedInterfaceInfoDeathNotification();
mEntry = nsnull;
mozilla::MutexAutoLock lock(xptiInterfaceInfoManager::
GetSingleton()->GetWorkingSet()->
mTableLock);
LOG_INFO_MONITOR_ENTRY;
// If GetInterfaceInfo added and *released* a reference
// before we acquired the monitor then 'this' might already
// be dead. In that case we would not want to try to access
// any instance data. We would want to bail immediately. If
// 'this' is already dead then the entry will no longer have
// a pointer to 'this'. So, we can protect ourselves from
// danger without more aggressive locking.
if(entry && !entry->InterfaceInfoEquals(this))
return 0;
// If GetInterfaceInfo added a reference before we acquired
// the monitor then we want to bail out of here without
// destorying the object.
if(mRefCnt)
return 1;
if(mEntry)
{
mEntry->LockedInterfaceInfoDeathNotification();
mEntry = nsnull;
}
}
delete this;

View File

@ -80,8 +80,6 @@ xptiInterfaceInfoManager::FreeInterfaceInfoManager()
xptiInterfaceInfoManager::xptiInterfaceInfoManager()
: mWorkingSet(),
mResolveLock("xptiInterfaceInfoManager.mResolveLock"),
mAutoRegLock("xptiInterfaceInfoManager.mAutoRegLock"), // FIXME: unused!
mInfoMonitor("xptiInterfaceInfoManager.mInfoMonitor"),
mAdditionalManagersLock(
"xptiInterfaceInfoManager.mAdditionalManagersLock")
{
@ -235,6 +233,7 @@ xptiInterfaceInfoManager::RegisterXPTHeader(XPTHeader* aHeader)
xptiTypelibGuts* typelib = xptiTypelibGuts::Create(aHeader);
MutexAutoLock lock(mWorkingSet.mTableLock);
for(PRUint16 k = 0; k < aHeader->num_interfaces; k++)
VerifyAndAddEntryIfNew(aHeader->interface_directory + k, k, typelib);
}
@ -255,6 +254,7 @@ xptiInterfaceInfoManager::VerifyAndAddEntryIfNew(XPTInterfaceDirectoryEntry* ifa
if (!iface->interface_descriptor)
return;
mWorkingSet.mTableLock.AssertCurrentThreadOwns();
xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(iface->iid);
if (entry) {
// XXX validate this info to find possible inconsistencies
@ -306,6 +306,7 @@ EntryToInfo(xptiInterfaceEntry* entry, nsIInterfaceInfo **_retval)
xptiInterfaceEntry*
xptiInterfaceInfoManager::GetInterfaceEntryForIID(const nsIID *iid)
{
MutexAutoLock lock(mWorkingSet.mTableLock);
return mWorkingSet.mIIDTable.Get(*iid);
}
@ -315,7 +316,8 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForIID(const nsIID * iid, nsIInte
NS_ASSERTION(iid, "bad param");
NS_ASSERTION(_retval, "bad param");
xptiInterfaceEntry* entry = GetInterfaceEntryForIID(iid);
MutexAutoLock lock(mWorkingSet.mTableLock);
xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid);
return EntryToInfo(entry, _retval);
}
@ -325,6 +327,7 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetInfoForName(const char *name, nsIInte
NS_ASSERTION(name, "bad param");
NS_ASSERTION(_retval, "bad param");
MutexAutoLock lock(mWorkingSet.mTableLock);
xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name);
return EntryToInfo(entry, _retval);
}
@ -335,7 +338,7 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetIIDForName(const char *name, nsIID *
NS_ASSERTION(name, "bad param");
NS_ASSERTION(_retval, "bad param");
MutexAutoLock lock(mWorkingSet.mTableLock);
xptiInterfaceEntry* entry = mWorkingSet.mNameTable.Get(name);
if (!entry) {
*_retval = nsnull;
@ -351,6 +354,7 @@ NS_IMETHODIMP xptiInterfaceInfoManager::GetNameForIID(const nsIID * iid, char **
NS_ASSERTION(iid, "bad param");
NS_ASSERTION(_retval, "bad param");
MutexAutoLock lock(mWorkingSet.mTableLock);
xptiInterfaceEntry* entry = mWorkingSet.mIIDTable.Get(*iid);
if (!entry) {
*_retval = nsnull;
@ -384,6 +388,7 @@ NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfaces(nsIEnumerator **_ret
if (!array)
return NS_ERROR_UNEXPECTED;
MutexAutoLock lock(mWorkingSet.mTableLock);
mWorkingSet.mNameTable.EnumerateRead(xpti_ArrayAppender, array);
return array->Enumerate(_retval);
@ -419,6 +424,7 @@ NS_IMETHODIMP xptiInterfaceInfoManager::EnumerateInterfacesWhoseNamesStartWith(c
if (!array)
return NS_ERROR_UNEXPECTED;
MutexAutoLock lock(mWorkingSet.mTableLock);
ArrayAndPrefix args = {array, prefix, PL_strlen(prefix)};
mWorkingSet.mNameTable.EnumerateRead(xpti_ArrayPrefixAppender, &args);

View File

@ -41,6 +41,8 @@
#include "xptiprivate.h"
using namespace mozilla;
// static
xptiTypelibGuts*
xptiTypelibGuts::Create(XPTHeader* aHeader)
@ -73,10 +75,13 @@ xptiTypelibGuts::GetEntryAt(PRUint16 i)
xptiWorkingSet* set =
xptiInterfaceInfoManager::GetSingleton()->GetWorkingSet();
if (iface->iid.Equals(zeroIID))
r = set->mNameTable.Get(iface->name);
else
r = set->mIIDTable.Get(iface->iid);
{
MutexAutoLock lock(set->mTableLock);
if (iface->iid.Equals(zeroIID))
r = set->mNameTable.Get(iface->name);
else
r = set->mIIDTable.Get(iface->iid);
}
if (r)
SetEntryAt(i, r);

View File

@ -48,6 +48,7 @@ using namespace mozilla;
#define XPTI_HASHTABLE_SIZE 2048
xptiWorkingSet::xptiWorkingSet()
: mTableLock("xptiWorkingSet::mTableLock")
{
MOZ_COUNT_CTOR(xptiWorkingSet);
@ -68,7 +69,7 @@ xpti_Invalidator(const char* keyname, xptiInterfaceEntry* entry, void* arg)
void
xptiWorkingSet::InvalidateInterfaceInfos()
{
MonitorAutoEnter lock(xptiInterfaceInfoManager::GetInfoMonitor());
MutexAutoLock lock(mTableLock);
mNameTable.EnumerateRead(xpti_Invalidator, NULL);
}

View File

@ -180,6 +180,11 @@ private:
public:
// XXX make these private with accessors
// mTableLock must be held across:
// * any read from or write to mIIDTable or mNameTable
// * any writing to the links between an xptiInterfaceEntry
// and its xptiInterfaceInfo (mEntry/mInfo)
mozilla::Mutex mTableLock;
nsDataHashtable<nsIDHashKey, xptiInterfaceEntry*> mIIDTable;
nsDataHashtable<nsDepCharHashKey, xptiInterfaceEntry*> mNameTable;
};
@ -406,15 +411,7 @@ private:
return mEntry && mEntry->EnsureResolved();
}
PRBool BuildParent()
{
NS_ASSERTION(mEntry &&
mEntry->IsFullyResolved() &&
!mParent &&
mEntry->Parent(),
"bad BuildParent call");
return NS_SUCCEEDED(mEntry->Parent()->GetInterfaceInfo(&mParent));
}
PRBool BuildParent();
xptiInterfaceInfo(); // not implemented
@ -451,18 +448,6 @@ public:
return self->mResolveLock;
}
static Mutex& GetAutoRegLock(xptiInterfaceInfoManager* self = nsnull)
{
self = self ? self : GetSingleton();
return self->mAutoRegLock;
}
static Monitor& GetInfoMonitor(xptiInterfaceInfoManager* self = nsnull)
{
self = self ? self : GetSingleton();
return self->mInfoMonitor;
}
xptiInterfaceEntry* GetInterfaceEntryForIID(const nsIID *iid);
private:
@ -482,8 +467,6 @@ private:
private:
xptiWorkingSet mWorkingSet;
Mutex mResolveLock;
Mutex mAutoRegLock;
Monitor mInfoMonitor;
Mutex mAdditionalManagersLock;
nsCOMArray<nsISupports> mAdditionalManagers;
};