зеркало из https://github.com/mozilla/gecko-dev.git
Bug 833913 - Part 3: Switch nsMemoryReporterManager to using nsTHashtable. r=khuey,njn
This makes NS_RegisterMemoryReporter() and NS_UnregisterMemoryReporter() O(1). Previously, they took time linear to the number of registered reporters.
This commit is contained in:
Родитель
5d0ac0088b
Коммит
2cf629c5cd
|
@ -7,6 +7,7 @@
|
||||||
#include "nsAtomTable.h"
|
#include "nsAtomTable.h"
|
||||||
#include "nsAutoPtr.h"
|
#include "nsAutoPtr.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsCOMArray.h"
|
||||||
#include "nsDirectoryServiceUtils.h"
|
#include "nsDirectoryServiceUtils.h"
|
||||||
#include "nsServiceManagerUtils.h"
|
#include "nsServiceManagerUtils.h"
|
||||||
#include "nsMemoryReporterManager.h"
|
#include "nsMemoryReporterManager.h"
|
||||||
|
@ -757,9 +758,72 @@ nsMemoryReporterManager::Init()
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HastableEnumerator takes an nsTHashtable<nsISupportsHashKey>& in its
|
||||||
|
* constructor and creates an nsISimpleEnumerator from its contents.
|
||||||
|
*
|
||||||
|
* The resultant enumerator works over a copy of the hashtable, so it's safe to
|
||||||
|
* mutate or destroy the hashtable after the enumerator is created.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class HashtableEnumerator MOZ_FINAL : public nsISimpleEnumerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashtableEnumerator(nsTHashtable<nsISupportsHashKey>& aHashtable)
|
||||||
|
: mIndex(0)
|
||||||
|
{
|
||||||
|
aHashtable.EnumerateEntries(EnumeratorFunc, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSISIMPLEENUMERATOR
|
||||||
|
|
||||||
|
private:
|
||||||
|
static PLDHashOperator
|
||||||
|
EnumeratorFunc(nsISupportsHashKey* aEntry, void* aData);
|
||||||
|
|
||||||
|
uint32_t mIndex;
|
||||||
|
nsCOMArray<nsISupports> mArray;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS1(HashtableEnumerator, nsISimpleEnumerator)
|
||||||
|
|
||||||
|
/* static */ PLDHashOperator
|
||||||
|
HashtableEnumerator::EnumeratorFunc(nsISupportsHashKey* aElem, void* aData)
|
||||||
|
{
|
||||||
|
HashtableEnumerator* enumerator = static_cast<HashtableEnumerator*>(aData);
|
||||||
|
enumerator->mArray.AppendObject(aElem->GetKey());
|
||||||
|
return PL_DHASH_NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP HashtableEnumerator::HasMoreElements(bool* aResult)
|
||||||
|
{
|
||||||
|
*aResult = mIndex < mArray.Count();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP HashtableEnumerator::GetNext(nsISupports** aNext)
|
||||||
|
{
|
||||||
|
if (mIndex < mArray.Count()) {
|
||||||
|
nsCOMPtr<nsISupports> next = mArray.ObjectAt(mIndex);
|
||||||
|
next.forget(aNext);
|
||||||
|
mIndex++;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aNext = nullptr;
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
nsMemoryReporterManager::nsMemoryReporterManager()
|
nsMemoryReporterManager::nsMemoryReporterManager()
|
||||||
: mMutex("nsMemoryReporterManager::mMutex")
|
: mMutex("nsMemoryReporterManager::mMutex")
|
||||||
{
|
{
|
||||||
|
mReporters.Init();
|
||||||
|
mMultiReporters.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsMemoryReporterManager::~nsMemoryReporterManager()
|
nsMemoryReporterManager::~nsMemoryReporterManager()
|
||||||
|
@ -769,60 +833,123 @@ nsMemoryReporterManager::~nsMemoryReporterManager()
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMemoryReporterManager::EnumerateReporters(nsISimpleEnumerator **result)
|
nsMemoryReporterManager::EnumerateReporters(nsISimpleEnumerator **result)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
// Memory reporters are not necessarily threadsafe, so EnumerateReporters()
|
||||||
|
// must be called from the main thread.
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
|
||||||
mozilla::MutexAutoLock autoLock(mMutex);
|
mozilla::MutexAutoLock autoLock(mMutex);
|
||||||
rv = NS_NewArrayEnumerator(result, mReporters);
|
|
||||||
return rv;
|
nsRefPtr<HashtableEnumerator> enumerator =
|
||||||
|
new HashtableEnumerator(mReporters);
|
||||||
|
enumerator.forget(result);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMemoryReporterManager::EnumerateMultiReporters(nsISimpleEnumerator **result)
|
nsMemoryReporterManager::EnumerateMultiReporters(nsISimpleEnumerator **result)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
// Memory multi-reporters are not necessarily threadsafe, so
|
||||||
|
// EnumerateMultiReporters() must be called from the main thread.
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
|
||||||
mozilla::MutexAutoLock autoLock(mMutex);
|
mozilla::MutexAutoLock autoLock(mMutex);
|
||||||
rv = NS_NewArrayEnumerator(result, mMultiReporters);
|
|
||||||
return rv;
|
nsRefPtr<HashtableEnumerator> enumerator =
|
||||||
|
new HashtableEnumerator(mMultiReporters);
|
||||||
|
enumerator.forget(result);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
DebugAssertRefcountIsNonZero(nsISupports* aObj)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
// This will probably crash if the object's refcount is 0.
|
||||||
|
uint32_t refcnt = NS_ADDREF(aObj);
|
||||||
|
MOZ_ASSERT(refcnt >= 2);
|
||||||
|
NS_RELEASE(aObj);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMemoryReporterManager::RegisterReporter(nsIMemoryReporter *reporter)
|
nsMemoryReporterManager::RegisterReporter(nsIMemoryReporter *reporter)
|
||||||
{
|
{
|
||||||
|
// This method is thread-safe.
|
||||||
mozilla::MutexAutoLock autoLock(mMutex);
|
mozilla::MutexAutoLock autoLock(mMutex);
|
||||||
if (mReporters.IndexOf(reporter) != -1)
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
mReporters.AppendObject(reporter);
|
if (mReporters.Contains(reporter)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method needs to be safe even if |reporter| has a refcnt of 0, so we
|
||||||
|
// take a kung fu death grip before calling PutEntry. Otherwise, if
|
||||||
|
// PutEntry addref'ed and released reporter before finally addref'ing it for
|
||||||
|
// good, it would free reporter!
|
||||||
|
//
|
||||||
|
// The kung fu death grip could itself be problematic if PutEntry didn't
|
||||||
|
// addref |reporter| (because then when the death grip goes out of scope, we
|
||||||
|
// would delete the reporter). In debug mode, we check that this doesn't
|
||||||
|
// happen.
|
||||||
|
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIMemoryReporter> kungFuDeathGrip = reporter;
|
||||||
|
mReporters.PutEntry(reporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugAssertRefcountIsNonZero(reporter);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMemoryReporterManager::RegisterMultiReporter(nsIMemoryMultiReporter *reporter)
|
nsMemoryReporterManager::RegisterMultiReporter(nsIMemoryMultiReporter *reporter)
|
||||||
{
|
{
|
||||||
|
// This method is thread-safe.
|
||||||
mozilla::MutexAutoLock autoLock(mMutex);
|
mozilla::MutexAutoLock autoLock(mMutex);
|
||||||
if (mMultiReporters.IndexOf(reporter) != -1)
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
mMultiReporters.AppendObject(reporter);
|
if (mMultiReporters.Contains(reporter)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIMemoryMultiReporter> kungFuDeathGrip = reporter;
|
||||||
|
mMultiReporters.PutEntry(reporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugAssertRefcountIsNonZero(reporter);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMemoryReporterManager::UnregisterReporter(nsIMemoryReporter *reporter)
|
nsMemoryReporterManager::UnregisterReporter(nsIMemoryReporter *reporter)
|
||||||
{
|
{
|
||||||
|
// This method is thread-safe.
|
||||||
mozilla::MutexAutoLock autoLock(mMutex);
|
mozilla::MutexAutoLock autoLock(mMutex);
|
||||||
if (!mReporters.RemoveObject(reporter))
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
|
if (!mReporters.Contains(reporter)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mReporters.RemoveEntry(reporter);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsMemoryReporterManager::UnregisterMultiReporter(nsIMemoryMultiReporter *reporter)
|
nsMemoryReporterManager::UnregisterMultiReporter(nsIMemoryMultiReporter *reporter)
|
||||||
{
|
{
|
||||||
|
// This method is thread-safe.
|
||||||
mozilla::MutexAutoLock autoLock(mMutex);
|
mozilla::MutexAutoLock autoLock(mMutex);
|
||||||
if (!mMultiReporters.RemoveObject(reporter))
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
|
if (!mMultiReporters.Contains(reporter)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMultiReporters.RemoveEntry(reporter);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "nsIMemoryReporter.h"
|
#include "nsIMemoryReporter.h"
|
||||||
#include "nsCOMArray.h"
|
|
||||||
#include "mozilla/Mutex.h"
|
#include "mozilla/Mutex.h"
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
#include "nsTHashtable.h"
|
||||||
|
#include "nsHashKeys.h"
|
||||||
|
|
||||||
using mozilla::Mutex;
|
using mozilla::Mutex;
|
||||||
|
|
||||||
|
@ -22,9 +23,9 @@ public:
|
||||||
virtual ~nsMemoryReporterManager();
|
virtual ~nsMemoryReporterManager();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsCOMArray<nsIMemoryReporter> mReporters;
|
nsTHashtable<nsISupportsHashKey> mReporters;
|
||||||
nsCOMArray<nsIMemoryMultiReporter> mMultiReporters;
|
nsTHashtable<nsISupportsHashKey> mMultiReporters;
|
||||||
Mutex mMutex;
|
Mutex mMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NS_MEMORY_REPORTER_MANAGER_CID \
|
#define NS_MEMORY_REPORTER_MANAGER_CID \
|
||||||
|
|
Загрузка…
Ссылка в новой задаче