From c95ca6c01ff67195f3ae0d5698fa8553eeb4b28c Mon Sep 17 00:00:00 2001 From: Gabriele Svelto Date: Tue, 11 Dec 2012 19:13:29 +0100 Subject: [PATCH] Bug 814771 - Add a cancelable runnable and use it to cancel a pending memory minimization procedure when an application is brought to the foreground r=jlebar --- dom/ipc/ProcessPriorityManager.cpp | 20 +++++++++++++++++- xpcom/base/nsIMemoryReporter.idl | 7 ++++--- xpcom/base/nsMemoryInfoDumper.cpp | 3 ++- xpcom/base/nsMemoryReporterManager.cpp | 28 ++++++++++++++++++++++--- xpcom/glue/nsThreadUtils.cpp | 18 +++++++++++++++- xpcom/glue/nsThreadUtils.h | 17 +++++++++++++++ xpcom/threads/Makefile.in | 1 + xpcom/threads/nsICancelableRunnable.idl | 24 +++++++++++++++++++++ xpcom/threads/nsIRunnable.idl | 7 +++++++ 9 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 xpcom/threads/nsICancelableRunnable.idl diff --git a/dom/ipc/ProcessPriorityManager.cpp b/dom/ipc/ProcessPriorityManager.cpp index 781cf9a42fe..6dd4f9fb521 100644 --- a/dom/ipc/ProcessPriorityManager.cpp +++ b/dom/ipc/ProcessPriorityManager.cpp @@ -113,6 +113,7 @@ private: nsTArray mWindows; nsCOMPtr mGracePeriodTimer; + nsWeakPtr mMemoryMinimizerRunnable; TimeStamp mStartupTime; }; @@ -283,6 +284,13 @@ ProcessPriorityManager::SetPriority(ProcessPriority aPriority) mGracePeriodTimer = nullptr; } + // Cancel the memory minimization procedure we might have started. + nsCOMPtr runnable = + do_QueryReferent(mMemoryMinimizerRunnable); + if (runnable) { + runnable->Cancel(); + } + LOG("Setting priority to %d.", aPriority); mProcessPriority = aPriority; hal::SetProcessPriority(getpid(), aPriority); @@ -310,7 +318,17 @@ ProcessPriorityManager::OnGracePeriodTimerFired() nsCOMPtr mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); if (mgr) { - mgr->MinimizeMemoryUsage(/* callback = */ nullptr); + nsCOMPtr runnable = + do_QueryReferent(mMemoryMinimizerRunnable); + + // Cancel the previous task if it's still pending + if (runnable) { + runnable->Cancel(); + } + + mgr->MinimizeMemoryUsage(/* callback = */ nullptr, + getter_AddRefs(runnable)); + mMemoryMinimizerRunnable = do_GetWeakReference(runnable); } } diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index af8e93c8c70..7749cf1bf95 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -7,6 +7,7 @@ interface nsISimpleEnumerator; interface nsIRunnable; +interface nsICancelableRunnable; /* * Memory reporters measure Firefox's memory usage. They are mainly used to @@ -226,7 +227,7 @@ interface nsIMemoryMultiReporter : nsISupports readonly attribute int64_t explicitNonHeap; }; -[scriptable, builtinclass, uuid(8b670411-ea2a-44c2-a36b-529db0670821)] +[scriptable, builtinclass, uuid(0baaa958-3112-4952-b557-2a0c57eabb8f)] interface nsIMemoryReporterManager : nsISupports { /* @@ -296,9 +297,9 @@ interface nsIMemoryReporterManager : nsISupports /* * Run a series of GC/CC's in an attempt to minimize the application's memory * usage. When we're finished, we invoke the given runnable if it's not - * null. + * null. Returns a reference to the runnable used for carrying out the task. */ - void minimizeMemoryUsage(in nsIRunnable callback); + nsICancelableRunnable minimizeMemoryUsage(in nsIRunnable callback); }; %{C++ diff --git a/xpcom/base/nsMemoryInfoDumper.cpp b/xpcom/base/nsMemoryInfoDumper.cpp index 33d536e1c1d..e6b44fbece9 100644 --- a/xpcom/base/nsMemoryInfoDumper.cpp +++ b/xpcom/base/nsMemoryInfoDumper.cpp @@ -336,7 +336,8 @@ nsMemoryInfoDumper::DumpMemoryReportsToFile( nsCOMPtr mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE); - mgr->MinimizeMemoryUsage(callback); + nsCOMPtr runnable; + mgr->MinimizeMemoryUsage(callback, getter_AddRefs(runnable)); return NS_OK; } diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index d78a41ec1aa..b53bebc932c 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -949,16 +949,21 @@ namespace { * When this sequence finishes, we invoke the callback function passed to the * runnable's constructor. */ -class MinimizeMemoryUsageRunnable : public nsRunnable +class MinimizeMemoryUsageRunnable : public nsCancelableRunnable { public: MinimizeMemoryUsageRunnable(nsIRunnable* aCallback) : mCallback(aCallback) , mRemainingIters(sNumIters) + , mCanceled(false) {} NS_IMETHOD Run() { + if (mCanceled) { + return NS_OK; + } + nsCOMPtr os = services::GetObserverService(); if (!os) { return NS_ERROR_FAILURE; @@ -981,6 +986,17 @@ public: return NS_OK; } + NS_IMETHOD Cancel() + { + if (mCanceled) { + return NS_ERROR_UNEXPECTED; + } + + mCanceled = true; + + return NS_OK; + } + private: // Send sNumIters heap-minimize notifications, spinning the event // loop after each notification (see bug 610166 comment 12 for an @@ -989,15 +1005,21 @@ private: nsCOMPtr mCallback; uint32_t mRemainingIters; + bool mCanceled; }; } // anonymous namespace NS_IMETHODIMP -nsMemoryReporterManager::MinimizeMemoryUsage(nsIRunnable* aCallback) +nsMemoryReporterManager::MinimizeMemoryUsage(nsIRunnable* aCallback, + nsICancelableRunnable **result) { - nsRefPtr runnable = + NS_ENSURE_ARG_POINTER(result); + + nsRefPtr runnable = new MinimizeMemoryUsageRunnable(aCallback); + NS_ADDREF(*result = runnable); + return NS_DispatchToMainThread(runnable); } diff --git a/xpcom/glue/nsThreadUtils.cpp b/xpcom/glue/nsThreadUtils.cpp index 11176a8e031..de50728d504 100644 --- a/xpcom/glue/nsThreadUtils.cpp +++ b/xpcom/glue/nsThreadUtils.cpp @@ -29,7 +29,7 @@ #ifndef XPCOM_GLUE_AVOID_NSPR NS_IMPL_THREADSAFE_ISUPPORTS1(nsRunnable, nsIRunnable) - + NS_IMETHODIMP nsRunnable::Run() { @@ -37,6 +37,22 @@ nsRunnable::Run() return NS_OK; } +NS_IMPL_THREADSAFE_ISUPPORTS1(nsCancelableRunnable, nsICancelableRunnable) + +NS_IMETHODIMP +nsCancelableRunnable::Run() +{ + // Do nothing + return NS_OK; +} + +NS_IMETHODIMP +nsCancelableRunnable::Cancel() +{ + // Do nothing + return NS_OK; +} + #endif // XPCOM_GLUE_AVOID_NSPR //----------------------------------------------------------------------------- diff --git a/xpcom/glue/nsThreadUtils.h b/xpcom/glue/nsThreadUtils.h index 8b000ab7315..7ad8409f871 100644 --- a/xpcom/glue/nsThreadUtils.h +++ b/xpcom/glue/nsThreadUtils.h @@ -12,6 +12,7 @@ #include "nsIThreadManager.h" #include "nsIThread.h" #include "nsIRunnable.h" +#include "nsICancelableRunnable.h" #include "nsStringGlue.h" #include "nsCOMPtr.h" #include "nsAutoPtr.h" @@ -263,6 +264,22 @@ protected: } }; +// This class is designed to be subclassed. +class NS_COM_GLUE nsCancelableRunnable : public nsICancelableRunnable +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + NS_DECL_NSICANCELABLERUNNABLE + + nsCancelableRunnable() { + } + +protected: + virtual ~nsCancelableRunnable() { + } +}; + #undef IMETHOD_VISIBILITY #define IMETHOD_VISIBILITY NS_VISIBILITY_HIDDEN diff --git a/xpcom/threads/Makefile.in b/xpcom/threads/Makefile.in index 35b4be77e81..754eb2c7b6d 100644 --- a/xpcom/threads/Makefile.in +++ b/xpcom/threads/Makefile.in @@ -51,6 +51,7 @@ XPIDLSRCS = \ nsIThreadPool.idl \ nsITimer.idl \ nsIRunnable.idl \ + nsICancelableRunnable.idl \ nsIEnvironment.idl \ nsIProcess.idl \ nsISupportsPriority.idl \ diff --git a/xpcom/threads/nsICancelableRunnable.idl b/xpcom/threads/nsICancelableRunnable.idl new file mode 100644 index 00000000000..44b9df477c0 --- /dev/null +++ b/xpcom/threads/nsICancelableRunnable.idl @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsIRunnable.idl" + +/** + * Represents a task which can be dispatched to a thread for execution and + * which can be cancelled if necessary. + */ + +[scriptable, uuid(de93dc4c-5eea-4eb7-b6d1-dbf1e0cef65c)] +interface nsICancelableRunnable : nsIRunnable +{ + /** + * Cancels a pending task. If the task has already been executed this will + * be a no-op. Calling this method twice is considered an error. + * + * @throws NS_ERROR_UNEXPECTED + * Indicates that the runnable has already been canceled. + */ + void cancel(); +}; diff --git a/xpcom/threads/nsIRunnable.idl b/xpcom/threads/nsIRunnable.idl index 12d99065ae5..ea976f0f204 100644 --- a/xpcom/threads/nsIRunnable.idl +++ b/xpcom/threads/nsIRunnable.idl @@ -5,8 +5,15 @@ #include "nsISupports.idl" +/** + * Represents a task which can be dispatched to a thread for execution. + */ + [scriptable, function, uuid(4a2abaf0-6886-11d3-9382-00104ba0fd40)] interface nsIRunnable : nsISupports { + /** + * The function implementing the task to be run. + */ void run(); };