From a69f1f52e75a4baa3b4b1cf9ef18c270e09e526c Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Tue, 6 Oct 2015 14:40:51 -0700 Subject: [PATCH] Backed out 7 changesets (bug 1194555) for xpcshell failures Backed out changeset e77be333f4fb (bug 1194555) Backed out changeset 11951462a37c (bug 1194555) Backed out changeset 99b27aa952c5 (bug 1194555) Backed out changeset 70a8ed3b6a45 (bug 1194555) Backed out changeset 748bfebe81e7 (bug 1194555) Backed out changeset cbaac05a2934 (bug 1194555) Backed out changeset fcbfd1379fcd (bug 1194555) --- dom/ipc/ContentChild.cpp | 35 +- image/test/mochitest/test_bug601470.html | 11 +- .../aboutmemory/tests/test_aboutmemory.xul | 24 +- .../aboutmemory/tests/test_aboutmemory2.xul | 9 +- .../tests/test_memoryReporters.xul | 161 +++---- .../tests/test_sqliteMultiReporter.xul | 13 +- xpcom/base/nsIMemoryReporter.idl | 43 +- xpcom/base/nsMemoryReporterManager.cpp | 401 ++++++++++-------- xpcom/base/nsMemoryReporterManager.h | 82 ++-- 9 files changed, 379 insertions(+), 400 deletions(-) diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index da64914f62da..d3cc35f6d481 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -895,32 +895,6 @@ NS_IMPL_ISUPPORTS( , nsIMemoryReporterCallback ) -class MemoryReportFinishedCallback final : public nsIFinishReportingCallback -{ -public: - NS_DECL_ISUPPORTS - - explicit MemoryReportFinishedCallback(MemoryReportRequestChild* aActor) - : mActor(aActor) - { - } - - NS_IMETHOD Callback(nsISupports* aUnused) override - { - bool sent = PMemoryReportRequestChild::Send__delete__(mActor); - return sent ? NS_OK : NS_ERROR_FAILURE; - } - -private: - ~MemoryReportFinishedCallback() {} - - nsRefPtr mActor; -}; -NS_IMPL_ISUPPORTS( - MemoryReportFinishedCallback -, nsIFinishReportingCallback -) - bool ContentChild::RecvPMemoryReportRequestConstructor( PMemoryReportRequestChild* aChild, @@ -957,12 +931,11 @@ NS_IMETHODIMP MemoryReportRequestChild::Run() // MemoryReport. nsRefPtr cb = new MemoryReportCallback(this, process); - nsRefPtr finished = - new MemoryReportFinishedCallback(this); + mgr->GetReportsForThisProcessExtended(cb, nullptr, mAnonymize, + FileDescriptorToFILE(mDMDFile, "wb")); - return mgr->GetReportsForThisProcessExtended(cb, nullptr, mAnonymize, - FileDescriptorToFILE(mDMDFile, "wb"), - finished, nullptr); + bool sent = Send__delete__(this); + return sent ? NS_OK : NS_ERROR_FAILURE; } bool diff --git a/image/test/mochitest/test_bug601470.html b/image/test/mochitest/test_bug601470.html index a9e1cc7880e9..fea2424b2a45 100644 --- a/image/test/mochitest/test_bug601470.html +++ b/image/test/mochitest/test_bug601470.html @@ -30,13 +30,12 @@ window.onload = function() { amount += aAmount; } - var finished = function() { - ok(amount > 0, "we should be using a nonzero amount of memory"); - ok(true, "yay, didn't crash!"); - SimpleTest.finish(); - } + mgr.getReportsForThisProcess(handleReport, null, /* anonymize = */ false); - mgr.getReports(handleReport, null, finished, null, /* anonymize = */ false); + ok(amount > 0, "we should be using a nonzero amount of memory"); + ok(true, "yay, didn't crash!"); + + SimpleTest.finish(); } diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul index bfeab4c7b415..d00e1ae1538b 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory.xul @@ -119,6 +119,21 @@ mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]); } + // mgr.explicit sums "heap-allocated" and all the appropriate NONHEAP ones: + // - "explicit/c", "explicit/cc" x 2, "explicit/d", "explicit/e" + // - but *not* "explicit/c/d" x 2 + // Check explicit now before we add the fake reporters for the fake 2nd + // and subsequent processes. + // + // Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a + // --disable-jemalloc build. Allow for that exception, but *only* that + // exception. + try { + is(mgr.explicit, 500*MB + (100 + 13 + 10)*MB + 599*KB, "mgr.explicit"); + } catch (ex) { + is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception"); + } + // The main process always comes first when we display about:memory. The // remaining processes are sorted by their |resident| values (starting with // the largest). Processes without a |resident| memory reporter are saved @@ -552,14 +567,7 @@ End of 5th\n\ SimpleTest.waitForClipboard( function(aActual) { mostRecentActual = aActual; - let rslt = aActual.trim() === aExpected.trim(); - if (!rslt) { - // Try copying again. - synthesizeKey("A", {accelKey: true}); - synthesizeKey("C", {accelKey: true}); - } - - return rslt; + return aActual.trim() === aExpected.trim(); }, function() { synthesizeKey("A", {accelKey: true}); diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul index 8cf197e6d114..e2f93d0adc4a 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory2.xul @@ -106,14 +106,7 @@ SimpleTest.waitForClipboard( function(aActual) { mostRecentActual = aActual; - let rslt = aActual.trim() === aExpected.trim(); - if (!rslt) { - // Try copying again. - synthesizeKey("A", {accelKey: true}); - synthesizeKey("C", {accelKey: true}); - } - - return rslt; + return aActual.trim() === aExpected.trim(); }, function() { synthesizeKey("A", {accelKey: true}); diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul index 035bb05ed48e..d9f1b81064e3 100644 --- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul +++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul @@ -44,8 +44,6 @@ const XUL_NS = "http:\\\\www.mozilla.org\\keymaster\\gatekeeper\\there.is.only.xul"; - SimpleTest.waitForExplicitFinish(); - let vsizeAmounts = []; let residentAmounts = []; let heapAllocatedAmounts = []; @@ -143,6 +141,21 @@ let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); + // Access the distinguished amounts (mgr.explicit et al.) just to make sure + // they don't crash. We can't check their actual values because they're + // non-deterministic. + // + // Nb: mgr.explicit will throw NS_ERROR_NOT_AVAILABLE if this is a + // --disable-jemalloc build. Allow for that exception, but *only* that + // exception. + let dummy; + let haveExplicit = true; + try { + dummy = mgr.explicit; + } catch (ex) { + is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.explicit exception"); + haveExplicit = false; + } let amounts = [ "vsize", "vsizeMaxContiguous", @@ -169,7 +182,7 @@ // aren't available on all platforms. But if the attribute simply // isn't present, that indicates the distinguished amounts have changed // and this file hasn't been updated appropriately. - let dummy = mgr[amounts[i]]; + dummy = mgr[amounts[i]]; ok(dummy !== undefined, "accessed an unknown distinguished amount: " + amounts[i]); } catch (ex) { @@ -191,33 +204,11 @@ domSize, styleSize, otherSize, totalSize, jsMilliseconds, nonJSMilliseconds); - let asyncSteps = [ - getReportsNormal, - getReportsAnonymized, - checkResults, - test_register_strong, - test_register_strong, // Make sure re-registering works - test_register_weak, - SimpleTest.finish - ]; + mgr.getReportsForThisProcess(handleReportNormal, null, + /* anonymize = */ false); - function runNext() { - setTimeout(asyncSteps.shift(), 0); - } - - function getReportsNormal() - { - mgr.getReports(handleReportNormal, null, - runNext, null, - /* anonymize = */ false); - } - - function getReportsAnonymized() - { - mgr.getReports(handleReportAnonymized, null, - runNext, null, - /* anonymize = */ true); - } + mgr.getReportsForThisProcess(handleReportAnonymized, null, + /* anonymize = */ true); function checkSizeReasonable(aName, aAmount) { @@ -235,50 +226,40 @@ } } - function checkResults() - { - try { - // Nb: mgr.heapAllocated will throw NS_ERROR_NOT_AVAILABLE if this is a - // --disable-jemalloc build. Allow for skipping this test on that - // exception, but *only* that exception. - let dummy = mgr.heapAllocated; - checkSpecialReport("heap-allocated", heapAllocatedAmounts); - } catch (ex) { - is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.heapAllocated exception"); - } - // vsize may be unreasonable if ASAN is enabled - checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true); - checkSpecialReport("resident", residentAmounts); - - for (var reporter in jsGcHeapUsedGcThings) { - ok(jsGcHeapUsedGcThings[reporter] == 1); - } - checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things", - jsGcHeapUsedGcThingsTotal); - - ok(present.jsNonWindowCompartments, "js-non-window compartments are present"); - ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present"); - ok(present.places, "places is present"); - ok(present.images, "images is present"); - ok(present.xptiWorkingSet, "xpti-working-set is present"); - ok(present.atomTablesMain, "atom-tables/main is present"); - ok(present.sandboxLocation, "sandbox locations are present"); - ok(present.bigString, "large string is present"); - ok(present.smallString1, "small string 1 is present"); - ok(present.smallString2, "small string 2 is present"); - - ok(!present.anonymizedWhenUnnecessary, - "anonymized paths are not present when unnecessary. Failed case: " + - present.anonymizedWhenUnnecessary); - ok(!present.httpWhenAnonymized, - "http URLs are anonymized when necessary. Failed case: " + - present.httpWhenAnonymized); - ok(!present.unanonymizedFilePathWhenAnonymized, - "file URLs are anonymized when necessary. Failed case: " + - present.unanonymizedFilePathWhenAnonymized); - - runNext(); + // If mgr.explicit failed, we won't have "heap-allocated" either. + if (haveExplicit) { + checkSpecialReport("heap-allocated", heapAllocatedAmounts); } + // vsize may be unreasonable if ASAN is enabled + checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true); + checkSpecialReport("resident", residentAmounts); + + for (var reporter in jsGcHeapUsedGcThings) { + ok(jsGcHeapUsedGcThings[reporter] == 1); + } + checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things", + jsGcHeapUsedGcThingsTotal); + + ok(present.jsNonWindowCompartments, "js-non-window compartments are present"); + ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present"); + ok(present.places, "places is present"); + ok(present.images, "images is present"); + ok(present.xptiWorkingSet, "xpti-working-set is present"); + ok(present.atomTablesMain, "atom-tables/main is present"); + ok(present.sandboxLocation, "sandbox locations are present"); + ok(present.bigString, "large string is present"); + ok(present.smallString1, "small string 1 is present"); + ok(present.smallString2, "small string 2 is present"); + + ok(!present.anonymizedWhenUnnecessary, + "anonymized paths are not present when unnecessary. Failed case: " + + present.anonymizedWhenUnnecessary); + ok(!present.httpWhenAnonymized, + "http URLs are anonymized when necessary. Failed case: " + + present.httpWhenAnonymized); + ok(!present.unanonymizedFilePathWhenAnonymized, + "file URLs are anonymized when necessary. Failed case: " + + present.unanonymizedFilePathWhenAnonymized); // Reporter registration tests @@ -371,28 +352,27 @@ mgr.registerStrongReporter(reporterAndCallback); // Check the generated reports. - mgr.getReports(reporterAndCallback, null, - () => { - reporterAndCallback.finish(); - window.setTimeout(test_unregister_strong, 0, reporterAndCallback); - }, null, - /* anonymize = */ false); - } + mgr.getReportsForThisProcess(reporterAndCallback, null, + /* anonymize = */ false); + reporterAndCallback.finish(); - function test_unregister_strong(aReporterAndCallback) - { - mgr.unregisterStrongReporter(aReporterAndCallback); + // Unregistration works. + mgr.unregisterStrongReporter(reporterAndCallback); // The reporter was unregistered, hence there shouldn't be any reports from // the test reporter. - mgr.getReports(aReporterAndCallback, null, - () => { - aReporterAndCallback.finish(0); - runNext(); - }, null, - /* anonymize = */ false); + mgr.getReportsForThisProcess(reporterAndCallback, null, + /* anonymize = */ false); + reporterAndCallback.finish(0); } + test_register_strong(); + + // Check strong reporters a second time, to make sure a reporter can be + // re-registered. + test_register_strong(); + + // Check that you cannot register JS components as weak reporters. function test_register_weak() { let reporterAndCallback = new MemoryReporterAndCallback(); @@ -412,12 +392,9 @@ ok(ex.message.indexOf("NS_ERROR_") >= 0, "WrappedJS reporter got rejected: " + ex); } - - runNext(); } - // Kick-off the async tests. - runNext(); + test_register_weak(); ]]> diff --git a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul index 3452bbbc7205..29c85a5c72a8 100644 --- a/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul +++ b/toolkit/components/aboutmemory/tests/test_sqliteMultiReporter.xul @@ -24,8 +24,6 @@ const Ci = Components.interfaces; const Cu = Components.utils; - SimpleTest.waitForExplicitFinish(); - // Make a fake DB file. let file = Cc["@mozilla.org/file/directory_service;1"]. getService(Ci.nsIProperties). @@ -42,12 +40,11 @@ // them. It shouldn't crash. let mgr = Cc["@mozilla.org/memory-reporter-manager;1"]. getService(Ci.nsIMemoryReporterManager); - mgr.getReports(function(){}, null, - () => { - ok(true, "didn't crash"); - SimpleTest.finish(); - }, null, - /* anonymize = */ false); + mgr.getReportsForThisProcess(function(){}, null, /* anonymize = */ false); + + // If we haven't crashed, we've passed, but the test harness requires that + // we explicitly check something. + ok(true, "didn't crash"); ]]> diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index e00f736f55c9..39e3be823b18 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -205,7 +205,7 @@ interface nsIFinishReportingCallback : nsISupports void callback(in nsISupports data); }; -[scriptable, builtinclass, uuid(61de6dc7-ed11-4104-a577-79941f22f434)] +[scriptable, builtinclass, uuid(5e4eaa5a-4808-4b97-8005-e7cdc4d73693)] interface nsIMemoryReporterManager : nsISupports { /* @@ -220,7 +220,6 @@ interface nsIMemoryReporterManager : nsISupports * unregisterStrongReporter() at any point. */ void registerStrongReporter(in nsIMemoryReporter reporter); - void registerStrongAsyncReporter(in nsIMemoryReporter reporter); /* * Like registerReporter, but the Manager service will hold a weak reference @@ -230,7 +229,6 @@ interface nsIMemoryReporterManager : nsISupports * register your JavaScript components with registerStrongReporter(). */ void registerWeakReporter(in nsIMemoryReporter reporter); - void registerWeakAsyncReporter(in nsIMemoryReporter reporter); /* * Unregister the given memory reporter, which must have been registered with @@ -291,6 +289,14 @@ interface nsIMemoryReporterManager : nsISupports in boolean minimizeMemoryUsage, in AString DMDDumpIdent); + /* + * Get memory reports in the current process only. |handleReport| is called + * for each report. + */ + void getReportsForThisProcess(in nsIMemoryReporterCallback handleReport, + in nsISupports handleReportData, + in boolean anonymize); + /* * As above, but if DMD is enabled and |DMDFile| is non-null then * write a DMD report to that file and close it. @@ -299,14 +305,7 @@ interface nsIMemoryReporterManager : nsISupports getReportsForThisProcessExtended(in nsIMemoryReporterCallback handleReport, in nsISupports handleReportData, in boolean anonymize, - in FILE DMDFile, - in nsIFinishReportingCallback finishReporting, - in nsISupports finishReportingData); - - /* - * Called by an asynchronous memory reporter upon completion. - */ - [noscript] void endReport(); + in FILE DMDFile); /* * The memory reporter manager, for the most part, treats reporters @@ -316,8 +315,9 @@ interface nsIMemoryReporterManager : nsISupports * interesting that we want external code (e.g. telemetry) to be able to rely * on them. * - * Note that these are not reporters and so getReports() does not look at - * them. However, distinguished amounts can be embedded in a reporter. + * Note that these are not reporters and so getReports() and + * getReportsForThisProcess() do not look at them. However, distinguished + * amounts can be embedded in a reporter. * * Access to these attributes can fail. In particular, some of them are not * available on all platforms. @@ -325,6 +325,11 @@ interface nsIMemoryReporterManager : nsISupports * If you add a new distinguished amount, please update * toolkit/components/aboutmemory/tests/test_memoryReporters.xul. * + * |explicit| (UNITS_BYTES) The total size of explicit memory allocations, + * both at the OS-level (eg. via mmap, VirtualAlloc) and at the heap level + * (eg. via malloc, calloc, operator new). It covers all heap allocations, + * but will miss any OS-level ones not covered by memory reporters. + * * |vsize| (UNITS_BYTES) The virtual size, i.e. the amount of address space * taken up. * @@ -373,6 +378,7 @@ interface nsIMemoryReporterManager : nsISupports * |pageFaultsHard| (UNITS_COUNT_CUMULATIVE) The number of hard (a.k.a. * major) page faults that have occurred since the process started. */ + readonly attribute int64_t explicit; readonly attribute int64_t vsize; readonly attribute int64_t vsizeMaxContiguous; readonly attribute int64_t resident; @@ -453,12 +459,10 @@ namespace mozilla { // Register a memory reporter. The manager service will hold a strong // reference to this reporter. XPCOM_API(nsresult) RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter); -XPCOM_API(nsresult) RegisterStrongAsyncMemoryReporter(nsIMemoryReporter* aReporter); // Register a memory reporter. The manager service will hold a weak reference // to this reporter. XPCOM_API(nsresult) RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter); -XPCOM_API(nsresult) RegisterWeakAsyncMemoryReporter(nsIMemoryReporter* aReporter); // Unregister a strong memory reporter. XPCOM_API(nsresult) UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter); @@ -516,6 +520,15 @@ nsresult RegisterNonJSSizeOfTab(NonJSSizeOfTabFn aSizeOfTabFn); } #if defined(MOZ_DMD) && !defined(MOZILLA_XPCOMRT_API) +namespace mozilla { +namespace dmd { +// This runs all the memory reporters in the current process but does nothing +// with the results; i.e. it does the minimal amount of work possible for DMD +// to do its thing. It does nothing with child processes. +void RunReportersForThisProcess(); +} +} + #if !defined(MOZ_MEMORY) #error "MOZ_DMD requires MOZ_MEMORY" #endif diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index eef9f403a595..4deb78839699 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1356,8 +1356,7 @@ nsMemoryReporterManager::nsMemoryReporterManager() , mSavedStrongReporters(nullptr) , mSavedWeakReporters(nullptr) , mNextGeneration(1) - , mPendingProcessesState(nullptr) - , mPendingReportersState(nullptr) + , mGetReportsState(nullptr) { } @@ -1415,11 +1414,11 @@ nsMemoryReporterManager::GetReportsExtended( uint32_t generation = mNextGeneration++; - if (mPendingProcessesState) { + if (mGetReportsState) { // A request is in flight. Don't start another one. And don't report // an error; just ignore it, and let the in-flight request finish. MEMORY_REPORTING_LOG("GetReports (gen=%u, s->gen=%u): abort\n", - generation, mPendingProcessesState->mGeneration); + generation, mGetReportsState->mGeneration); return NS_OK; } @@ -1430,15 +1429,16 @@ nsMemoryReporterManager::GetReportsExtended( if (concurrency < 1) { concurrency = 1; } - mPendingProcessesState = new PendingProcessesState(generation, - aAnonymize, - aMinimize, - concurrency, - aHandleReport, - aHandleReportData, - aFinishReporting, - aFinishReportingData, - aDMDDumpIdent); + mGetReportsState = new GetReportsState(generation, + aAnonymize, + aMinimize, + concurrency, + aHandleReport, + aHandleReportData, + aFinishReporting, + aFinishReportingData, + aDMDDumpIdent); + mGetReportsState->mChildrenPending = new nsTArray>(); if (aMinimize) { rv = MinimizeMemoryUsage(NS_NewRunnableMethod( @@ -1452,7 +1452,7 @@ nsMemoryReporterManager::GetReportsExtended( nsresult nsMemoryReporterManager::StartGettingReports() { - PendingProcessesState* s = mPendingProcessesState; + GetReportsState* s = mGetReportsState; nsresult rv; // Get reports for this process. @@ -1467,11 +1467,8 @@ nsMemoryReporterManager::StartGettingReports() } } #endif - - // This is async. GetReportsForThisProcessExtended(s->mHandleReport, s->mHandleReportData, - s->mAnonymize, parentDMDFile, - s->mFinishReporting, s->mFinishReportingData); + s->mAnonymize, parentDMDFile); nsTArray childWeakRefs; ContentParent::GetAll(childWeakRefs); @@ -1482,7 +1479,7 @@ nsMemoryReporterManager::StartGettingReports() // to be buffered and consume (possibly scarce) memory. for (size_t i = 0; i < childWeakRefs.Length(); ++i) { - s->mChildrenPending.AppendElement(childWeakRefs[i]); + s->mChildrenPending->AppendElement(childWeakRefs[i]); } nsCOMPtr timer = do_CreateInstance(NS_TIMER_CONTRACTID); @@ -1503,44 +1500,25 @@ nsMemoryReporterManager::StartGettingReports() s->mTimer.swap(timer); } + // The parent's report is done; make note of that, and start + // launching child process reports (if any). + EndProcessReport(s->mGeneration, true); return NS_OK; } -void -nsMemoryReporterManager::DispatchReporter( - nsIMemoryReporter* aReporter, bool aIsAsync, +NS_IMETHODIMP +nsMemoryReporterManager::GetReportsForThisProcess( nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - bool aAnonymize) + nsISupports* aHandleReportData, bool aAnonymize) { - MOZ_ASSERT(mPendingReportersState); - - // Grab refs to everything used in the lambda function. - nsRefPtr self = this; - nsCOMPtr reporter = aReporter; - nsCOMPtr handleReport = aHandleReport; - nsCOMPtr handleReportData = aHandleReportData; - - nsCOMPtr event = NS_NewRunnableFunction( - [self, reporter, aIsAsync, handleReport, handleReportData, aAnonymize] () { - reporter->CollectReports(handleReport, - handleReportData, - aAnonymize); - if (!aIsAsync) { - self->EndReport(); - } - }); - - NS_DispatchToMainThread(event); - mPendingReportersState->mReportsPending++; + return GetReportsForThisProcessExtended(aHandleReport, aHandleReportData, + aAnonymize, nullptr); } NS_IMETHODIMP nsMemoryReporterManager::GetReportsForThisProcessExtended( nsIHandleReportCallback* aHandleReport, nsISupports* aHandleReportData, - bool aAnonymize, FILE* aDMDFile, - nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData) + bool aAnonymize, FILE* aDMDFile) { // Memory reporters are not necessarily threadsafe, so this function must // be called from the main thread. @@ -1548,11 +1526,6 @@ nsMemoryReporterManager::GetReportsForThisProcessExtended( MOZ_CRASH(); } - if (NS_WARN_IF(mPendingReportersState)) { - // Report is already in progress. - return NS_ERROR_IN_PROGRESS; - } - #ifdef MOZ_DMD if (aDMDFile) { // Clear DMD's reportedness state before running the memory @@ -1563,58 +1536,39 @@ nsMemoryReporterManager::GetReportsForThisProcessExtended( MOZ_ASSERT(!aDMDFile); #endif - mPendingReportersState = new PendingReportersState( - aFinishReporting, aFinishReportingData, aDMDFile); - + nsCOMArray allReporters; { mozilla::MutexAutoLock autoLock(mMutex); - for (auto iter = mStrongReporters->Iter(); !iter.Done(); iter.Next()) { - DispatchReporter(iter.Key(), iter.Data(), - aHandleReport, aHandleReportData, aAnonymize); + nsRefPtrHashKey* entry = iter.Get(); + allReporters.AppendElement(entry->GetKey()); } - for (auto iter = mWeakReporters->Iter(); !iter.Done(); iter.Next()) { - nsCOMPtr reporter = iter.Key(); - DispatchReporter(reporter, iter.Data(), - aHandleReport, aHandleReportData, aAnonymize); + nsPtrHashKey* entry = iter.Get(); + allReporters.AppendElement(entry->GetKey()); } } + for (uint32_t i = 0; i < allReporters.Length(); i++) { + allReporters[i]->CollectReports(aHandleReport, aHandleReportData, + aAnonymize); + } - return NS_OK; -} - -NS_IMETHODIMP -nsMemoryReporterManager::EndReport() -{ - if (--mPendingReportersState->mReportsPending == 0) { #ifdef MOZ_DMD - if (mPendingReportersState->mDMDFile) { - nsMemoryInfoDumper::DumpDMDToFile(mPendingReportersState->mDMDFile); - } -#endif - if (mPendingProcessesState) { - // This is the parent process. - EndProcessReport(mPendingProcessesState->mGeneration, true); - } else { - mPendingReportersState->mFinishReporting->Callback( - mPendingReportersState->mFinishReportingData); - } - - delete mPendingReportersState; - mPendingReportersState = nullptr; + if (aDMDFile) { + return nsMemoryInfoDumper::DumpDMDToFile(aDMDFile); } +#endif return NS_OK; } -nsMemoryReporterManager::PendingProcessesState* +nsMemoryReporterManager::GetReportsState* nsMemoryReporterManager::GetStateForGeneration(uint32_t aGeneration) { // Memory reporting only happens on the main thread. MOZ_RELEASE_ASSERT(NS_IsMainThread()); - PendingProcessesState* s = mPendingProcessesState; + GetReportsState* s = mGetReportsState; if (!s) { // If we reach here, then: @@ -1651,7 +1605,7 @@ nsMemoryReporterManager::HandleChildReport( uint32_t aGeneration, const dom::MemoryReport& aChildReport) { - PendingProcessesState* s = GetStateForGeneration(aGeneration); + GetReportsState* s = GetStateForGeneration(aGeneration); if (!s) { return; } @@ -1671,7 +1625,7 @@ nsMemoryReporterManager::HandleChildReport( /* static */ bool nsMemoryReporterManager::StartChildReport(mozilla::dom::ContentParent* aChild, - const PendingProcessesState* aState) + const GetReportsState* aState) { #ifdef MOZ_NUWA_PROCESS if (aChild->IsNuwaProcess()) { @@ -1709,7 +1663,7 @@ nsMemoryReporterManager::StartChildReport(mozilla::dom::ContentParent* aChild, void nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) { - PendingProcessesState* s = GetStateForGeneration(aGeneration); + GetReportsState* s = GetStateForGeneration(aGeneration); if (!s) { return; } @@ -1722,29 +1676,29 @@ nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) aGeneration, s->mNumProcessesCompleted, aSuccess ? "completed" : "exited during report", s->mNumProcessesRunning, - static_cast(s->mChildrenPending.Length())); + static_cast(s->mChildrenPending->Length())); // Start pending children up to the concurrency limit. while (s->mNumProcessesRunning < s->mConcurrencyLimit && - !s->mChildrenPending.IsEmpty()) { + !s->mChildrenPending->IsEmpty()) { // Pop last element from s->mChildrenPending nsRefPtr nextChild; - nextChild.swap(s->mChildrenPending.LastElement()); - s->mChildrenPending.TruncateLength(s->mChildrenPending.Length() - 1); + nextChild.swap(s->mChildrenPending->LastElement()); + s->mChildrenPending->TruncateLength(s->mChildrenPending->Length() - 1); // Start report (if the child is still alive and not Nuwa). if (StartChildReport(nextChild, s)) { ++s->mNumProcessesRunning; MEMORY_REPORTING_LOG("HandleChildReports (aGen=%u): started child report" " (%u running, %u pending)\n", aGeneration, s->mNumProcessesRunning, - static_cast(s->mChildrenPending.Length())); + static_cast(s->mChildrenPending->Length())); } } // If all the child processes (if any) have reported, we can cancel // the timer (if started) and finish up. Otherwise, just return. if (s->mNumProcessesRunning == 0) { - MOZ_ASSERT(s->mChildrenPending.IsEmpty()); + MOZ_ASSERT(s->mChildrenPending->IsEmpty()); if (s->mTimer) { s->mTimer->Cancel(); } @@ -1756,15 +1710,15 @@ nsMemoryReporterManager::EndProcessReport(uint32_t aGeneration, bool aSuccess) nsMemoryReporterManager::TimeoutCallback(nsITimer* aTimer, void* aData) { nsMemoryReporterManager* mgr = static_cast(aData); - PendingProcessesState* s = mgr->mPendingProcessesState; + GetReportsState* s = mgr->mGetReportsState; // Release assert because: if the pointer is null we're about to // crash regardless of DEBUG, and this way the compiler doesn't // complain about unused variables. - MOZ_RELEASE_ASSERT(s, "mgr->mPendingProcessesState"); + MOZ_RELEASE_ASSERT(s, "mgr->mGetReportsState"); MEMORY_REPORTING_LOG("TimeoutCallback (s->gen=%u; %u running, %u pending)\n", s->mGeneration, s->mNumProcessesRunning, - static_cast(s->mChildrenPending.Length())); + static_cast(s->mChildrenPending->Length())); // We don't bother sending any kind of cancellation message to the child // processes that haven't reported back. @@ -1779,43 +1733,25 @@ nsMemoryReporterManager::FinishReporting() MOZ_CRASH(); } - MOZ_ASSERT(mPendingProcessesState); + MOZ_ASSERT(mGetReportsState); MEMORY_REPORTING_LOG("FinishReporting (s->gen=%u; %u processes reported)\n", - mPendingProcessesState->mGeneration, - mPendingProcessesState->mNumProcessesCompleted); + mGetReportsState->mGeneration, + mGetReportsState->mNumProcessesCompleted); - // Call this before deleting |mPendingProcessesState|. That way, if + // Call this before deleting |mGetReportsState|. That way, if // |mFinishReportData| calls GetReports(), it will silently abort, as // required. - nsresult rv = mPendingProcessesState->mFinishReporting->Callback( - mPendingProcessesState->mFinishReportingData); + nsresult rv = mGetReportsState->mFinishReporting->Callback( + mGetReportsState->mFinishReportingData); - delete mPendingProcessesState; - mPendingProcessesState = nullptr; + delete mGetReportsState; + mGetReportsState = nullptr; return rv; } -nsMemoryReporterManager::PendingProcessesState::PendingProcessesState( - uint32_t aGeneration, bool aAnonymize, bool aMinimize, - uint32_t aConcurrencyLimit, - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData, - const nsAString& aDMDDumpIdent) - : mGeneration(aGeneration) - , mAnonymize(aAnonymize) - , mMinimize(aMinimize) - , mChildrenPending() - , mNumProcessesRunning(1) // reporting starts with the parent - , mNumProcessesCompleted(0) - , mConcurrencyLimit(aConcurrencyLimit) - , mHandleReport(aHandleReport) - , mHandleReportData(aHandleReportData) - , mFinishReporting(aFinishReporting) - , mFinishReportingData(aFinishReportingData) - , mDMDDumpIdent(aDMDDumpIdent) +nsMemoryReporterManager::GetReportsState::~GetReportsState() { + delete mChildrenPending; } static void @@ -1831,7 +1767,7 @@ CrashIfRefcountIsZero(nsISupports* aObj) nsresult nsMemoryReporterManager::RegisterReporterHelper( - nsIMemoryReporter* aReporter, bool aForce, bool aStrong, bool aIsAsync) + nsIMemoryReporter* aReporter, bool aForce, bool aStrong) { // This method is thread-safe. mozilla::MutexAutoLock autoLock(mMutex); @@ -1858,7 +1794,7 @@ nsMemoryReporterManager::RegisterReporterHelper( // if (aStrong) { nsCOMPtr kungFuDeathGrip = aReporter; - mStrongReporters->Put(aReporter, aIsAsync); + mStrongReporters->PutEntry(aReporter); CrashIfRefcountIsZero(aReporter); } else { CrashIfRefcountIsZero(aReporter); @@ -1871,7 +1807,7 @@ nsMemoryReporterManager::RegisterReporterHelper( // CollectReports(). return NS_ERROR_XPC_BAD_CONVERT_JS; } - mWeakReporters->Put(aReporter, aIsAsync); + mWeakReporters->PutEntry(aReporter); } return NS_OK; @@ -1881,32 +1817,14 @@ NS_IMETHODIMP nsMemoryReporterManager::RegisterStrongReporter(nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ true, - /* async = */ false); -} - -NS_IMETHODIMP -nsMemoryReporterManager::RegisterStrongAsyncReporter(nsIMemoryReporter* aReporter) -{ - return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ true, - /* async = */ true); + /* strong = */ true); } NS_IMETHODIMP nsMemoryReporterManager::RegisterWeakReporter(nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ false, - /* async = */ false); -} - -NS_IMETHODIMP -nsMemoryReporterManager::RegisterWeakAsyncReporter(nsIMemoryReporter* aReporter) -{ - return RegisterReporterHelper(aReporter, /* force = */ false, - /* strong = */ false, - /* async = */ true); + /* strong = */ false); } NS_IMETHODIMP @@ -1914,8 +1832,7 @@ nsMemoryReporterManager::RegisterStrongReporterEvenIfBlocked( nsIMemoryReporter* aReporter) { return RegisterReporterHelper(aReporter, /* force = */ true, - /* strong = */ true, - /* async = */ false); + /* strong = */ true); } NS_IMETHODIMP @@ -1927,7 +1844,7 @@ nsMemoryReporterManager::UnregisterStrongReporter(nsIMemoryReporter* aReporter) MOZ_ASSERT(!mWeakReporters->Contains(aReporter)); if (mStrongReporters->Contains(aReporter)) { - mStrongReporters->Remove(aReporter); + mStrongReporters->RemoveEntry(aReporter); return NS_OK; } @@ -1936,7 +1853,7 @@ nsMemoryReporterManager::UnregisterStrongReporter(nsIMemoryReporter* aReporter) // references that these reporters aren't expecting (which can keep them // alive longer than intended). if (mSavedStrongReporters && mSavedStrongReporters->Contains(aReporter)) { - mSavedStrongReporters->Remove(aReporter); + mSavedStrongReporters->RemoveEntry(aReporter); return NS_OK; } @@ -1952,7 +1869,7 @@ nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter) MOZ_ASSERT(!mStrongReporters->Contains(aReporter)); if (mWeakReporters->Contains(aReporter)) { - mWeakReporters->Remove(aReporter); + mWeakReporters->RemoveEntry(aReporter); return NS_OK; } @@ -1961,7 +1878,7 @@ nsMemoryReporterManager::UnregisterWeakReporter(nsIMemoryReporter* aReporter) // references that the old reporters aren't expecting (which can end up as // dangling pointers that lead to use-after-frees). if (mSavedWeakReporters && mSavedWeakReporters->Contains(aReporter)) { - mSavedWeakReporters->Remove(aReporter); + mSavedWeakReporters->RemoveEntry(aReporter); return NS_OK; } @@ -2010,6 +1927,84 @@ nsMemoryReporterManager::UnblockRegistrationAndRestoreOriginalReporters() return NS_OK; } +// This is just a wrapper for int64_t that implements nsISupports, so it can be +// passed to nsIMemoryReporter::CollectReports. +class Int64Wrapper final : public nsISupports +{ + ~Int64Wrapper() {} + +public: + NS_DECL_ISUPPORTS + Int64Wrapper() : mValue(0) + { + } + int64_t mValue; +}; + +NS_IMPL_ISUPPORTS0(Int64Wrapper) + +class ExplicitCallback final : public nsIHandleReportCallback +{ + ~ExplicitCallback() {} + +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath, + int32_t aKind, int32_t aUnits, int64_t aAmount, + const nsACString& aDescription, + nsISupports* aWrappedExplicit) override + { + // Using the "heap-allocated" reporter here instead of + // nsMemoryReporterManager.heapAllocated goes against the usual + // pattern. But it's for a good reason: in tests, we can easily + // create artificial (i.e. deterministic) reporters -- which allows us + // to precisely test nsMemoryReporterManager.explicit -- but we can't + // do that for distinguished amounts. + if (aPath.EqualsLiteral("heap-allocated") || + (aKind == nsIMemoryReporter::KIND_NONHEAP && + PromiseFlatCString(aPath).Find("explicit") == 0)) { + Int64Wrapper* wrappedInt64 = static_cast(aWrappedExplicit); + wrappedInt64->mValue += aAmount; + } + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS(ExplicitCallback, nsIHandleReportCallback) + +NS_IMETHODIMP +nsMemoryReporterManager::GetExplicit(int64_t* aAmount) +{ + if (NS_WARN_IF(!aAmount)) { + return NS_ERROR_INVALID_ARG; + } + *aAmount = 0; +#ifndef HAVE_JEMALLOC_STATS + return NS_ERROR_NOT_AVAILABLE; +#else + + // For each reporter we call CollectReports and filter out the + // non-explicit, non-NONHEAP measurements (except for "heap-allocated"). + // That's lots of wasted work, and we used to have a GetExplicitNonHeap() + // method which did this more efficiently, but it ended up being more + // trouble than it was worth. + + nsRefPtr handleReport = new ExplicitCallback(); + nsRefPtr wrappedExplicitSize = new Int64Wrapper(); + + // Anonymization doesn't matter here, because we're only summing all the + // reported values. Enable it anyway because it's slightly faster, since it + // doesn't have to get URLs, find notable strings, etc. + GetReportsForThisProcess(handleReport, wrappedExplicitSize, + /* anonymize = */ true); + + *aAmount = wrappedExplicitSize->mValue; + + return NS_OK; +#endif // HAVE_JEMALLOC_STATS +} + NS_IMETHODIMP nsMemoryReporterManager::GetVsize(int64_t* aVsize) { @@ -2378,61 +2373,61 @@ nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow, namespace mozilla { -#define GET_MEMORY_REPORTER_MANAGER(mgr) \ - nsRefPtr mgr = \ - nsMemoryReporterManager::GetOrCreate(); \ - if (!mgr) { \ - return NS_ERROR_FAILURE; \ - } - nsresult RegisterStrongMemoryReporter(nsIMemoryReporter* aReporter) { // Hold a strong reference to the argument to make sure it gets released if // we return early below. nsCOMPtr reporter = aReporter; - GET_MEMORY_REPORTER_MANAGER(mgr) - return mgr->RegisterStrongReporter(reporter); -} -nsresult -RegisterStrongAsyncMemoryReporter(nsIMemoryReporter* aReporter) -{ - // Hold a strong reference to the argument to make sure it gets released if - // we return early below. - nsCOMPtr reporter = aReporter; - GET_MEMORY_REPORTER_MANAGER(mgr) - return mgr->RegisterStrongAsyncReporter(reporter); + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } + return mgr->RegisterStrongReporter(reporter); } nsresult RegisterWeakMemoryReporter(nsIMemoryReporter* aReporter) { - GET_MEMORY_REPORTER_MANAGER(mgr) + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } return mgr->RegisterWeakReporter(aReporter); } -nsresult -RegisterWeakAsyncMemoryReporter(nsIMemoryReporter* aReporter) -{ - GET_MEMORY_REPORTER_MANAGER(mgr) - return mgr->RegisterWeakAsyncReporter(aReporter); -} - nsresult UnregisterStrongMemoryReporter(nsIMemoryReporter* aReporter) { - GET_MEMORY_REPORTER_MANAGER(mgr) + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } return mgr->UnregisterStrongReporter(aReporter); } nsresult UnregisterWeakMemoryReporter(nsIMemoryReporter* aReporter) { - GET_MEMORY_REPORTER_MANAGER(mgr) + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + if (!mgr) { + return NS_ERROR_FAILURE; + } return mgr->UnregisterWeakReporter(aReporter); } +#define GET_MEMORY_REPORTER_MANAGER(mgr) \ + nsRefPtr mgr = \ + nsMemoryReporterManager::GetOrCreate(); \ + if (!mgr) { \ + return NS_ERROR_FAILURE; \ + } + // Macro for generating functions that register distinguished amount functions // with the memory reporter manager. #define DEFINE_REGISTER_DISTINGUISHED_AMOUNT(kind, name) \ @@ -2488,3 +2483,45 @@ DEFINE_REGISTER_SIZE_OF_TAB(NonJS); #undef GET_MEMORY_REPORTER_MANAGER } // namespace mozilla + +#if defined(MOZ_DMD) + +namespace mozilla { +namespace dmd { + +class DoNothingCallback final : public nsIHandleReportCallback +{ +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Callback(const nsACString& aProcess, const nsACString& aPath, + int32_t aKind, int32_t aUnits, int64_t aAmount, + const nsACString& aDescription, + nsISupports* aData) override + { + // Do nothing; the reporter has already reported to DMD. + return NS_OK; + } + +private: + ~DoNothingCallback() {} +}; + +NS_IMPL_ISUPPORTS(DoNothingCallback, nsIHandleReportCallback) + +void +RunReportersForThisProcess() +{ + nsCOMPtr mgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + + nsRefPtr doNothing = new DoNothingCallback(); + + mgr->GetReportsForThisProcess(doNothing, nullptr, /* anonymize = */ false); +} + +} // namespace dmd +} // namespace mozilla + +#endif // defined(MOZ_DMD) + diff --git a/xpcom/base/nsMemoryReporterManager.h b/xpcom/base/nsMemoryReporterManager.h index 16af7b53f240..152e83a69b13 100644 --- a/xpcom/base/nsMemoryReporterManager.h +++ b/xpcom/base/nsMemoryReporterManager.h @@ -41,14 +41,14 @@ public: return static_cast(imgr.get()); } - typedef nsDataHashtable, bool> StrongReportersTable; - typedef nsDataHashtable, bool> WeakReportersTable; + typedef nsTHashtable> StrongReportersTable; + typedef nsTHashtable> WeakReportersTable; // Inter-process memory reporting proceeds as follows. // // - GetReports() (declared within NS_DECL_NSIMEMORYREPORTERMANAGER) // synchronously gets memory reports for the current process, sets up some - // state (mPendingProcessesState) for when child processes report back -- + // state (mGetReportsState) for when child processes report back -- // including a timer -- and starts telling child processes to get memory // reports. Control then returns to the main event loop. // @@ -108,7 +108,7 @@ public: // is incomplete. // // Now, what what happens if a child process is created/destroyed in the - // middle of a request? Well, PendingProcessesState is initialized with an array + // middle of a request? Well, GetReportsState is initialized with an array // of child process actors as of when the report started. So... // // - If a process is created after reporting starts, it won't be sent a @@ -184,15 +184,10 @@ public: private: nsresult RegisterReporterHelper(nsIMemoryReporter* aReporter, - bool aForce, bool aStrongRef, bool aIsAsync); + bool aForce, bool aStrongRef); nsresult StartGettingReports(); nsresult FinishReporting(); - void DispatchReporter(nsIMemoryReporter* aReporter, bool aIsAsync, - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - bool aAnonymize); - static void TimeoutCallback(nsITimer* aTimer, void* aData); // Note: this timeout needs to be long enough to allow for the // possibility of DMD reports and/or running on a low-end phone. @@ -210,16 +205,16 @@ private: uint32_t mNextGeneration; - // Used to keep track of state of which processes are currently running and - // waiting to run memory reports. Holds references to parameters needed when - // requesting a memory report and finishing reporting. - struct PendingProcessesState + struct GetReportsState { uint32_t mGeneration; bool mAnonymize; bool mMinimize; nsCOMPtr mTimer; - nsTArray> mChildrenPending; + // This is a pointer to an nsTArray because otherwise C++ is + // unhappy unless this header includes ContentParent.h, which not + // everything that includes this header knows how to find. + nsTArray>* mChildrenPending; uint32_t mNumProcessesRunning; uint32_t mNumProcessesCompleted; uint32_t mConcurrencyLimit; @@ -229,52 +224,39 @@ private: nsCOMPtr mFinishReportingData; nsString mDMDDumpIdent; - PendingProcessesState(uint32_t aGeneration, bool aAnonymize, bool aMinimize, - uint32_t aConcurrencyLimit, - nsIHandleReportCallback* aHandleReport, - nsISupports* aHandleReportData, - nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData, - const nsAString& aDMDDumpIdent); - }; - - // Used to keep track of the state of the asynchronously run memory - // reporters. The callback and file handle used when all memory reporters - // have finished are also stored here. - struct PendingReportersState - { - // Number of memory reporters currently running. - uint32_t mReportsPending; - - // Callback for when all memory reporters have completed. - nsCOMPtr mFinishReporting; - nsCOMPtr mFinishReportingData; - - // File handle to write a DMD report to if requested. - FILE* mDMDFile; - - PendingReportersState(nsIFinishReportingCallback* aFinishReporting, - nsISupports* aFinishReportingData, - FILE* aDMDFile) - : mReportsPending(0) + GetReportsState(uint32_t aGeneration, bool aAnonymize, bool aMinimize, + uint32_t aConcurrencyLimit, + nsIHandleReportCallback* aHandleReport, + nsISupports* aHandleReportData, + nsIFinishReportingCallback* aFinishReporting, + nsISupports* aFinishReportingData, + const nsAString& aDMDDumpIdent) + : mGeneration(aGeneration) + , mAnonymize(aAnonymize) + , mMinimize(aMinimize) + , mChildrenPending(nullptr) + , mNumProcessesRunning(1) // reporting starts with the parent + , mNumProcessesCompleted(0) + , mConcurrencyLimit(aConcurrencyLimit) + , mHandleReport(aHandleReport) + , mHandleReportData(aHandleReportData) , mFinishReporting(aFinishReporting) , mFinishReportingData(aFinishReportingData) - , mDMDFile(aDMDFile) + , mDMDDumpIdent(aDMDDumpIdent) { } + + ~GetReportsState(); }; // When this is non-null, a request is in flight. Note: We use manual // new/delete for this because its lifetime doesn't match block scope or // anything like that. - PendingProcessesState* mPendingProcessesState; + GetReportsState* mGetReportsState; - // This is reinitialized each time a call to GetReports is initiated. - PendingReportersState* mPendingReportersState; - - PendingProcessesState* GetStateForGeneration(uint32_t aGeneration); + GetReportsState* GetStateForGeneration(uint32_t aGeneration); static bool StartChildReport(mozilla::dom::ContentParent* aChild, - const PendingProcessesState* aState); + const GetReportsState* aState); }; #define NS_MEMORY_REPORTER_MANAGER_CID \