diff --git a/widget/gonk/GonkMemoryPressureMonitoring.cpp b/widget/gonk/GonkMemoryPressureMonitoring.cpp index 4119033c9f1c..133b98eb2e0f 100644 --- a/widget/gonk/GonkMemoryPressureMonitoring.cpp +++ b/widget/gonk/GonkMemoryPressureMonitoring.cpp @@ -11,7 +11,6 @@ #include "mozilla/Services.h" #include "nsIObserver.h" #include "nsIObserverService.h" -#include "nsMemoryPressure.h" #include "nsThreadUtils.h" #include #include @@ -25,6 +24,37 @@ using namespace mozilla; namespace { +class MemoryPressureRunnable : public nsRunnable +{ + const char *mTopic; + const PRUnichar *mData; +public: + MemoryPressureRunnable(const char *aTopic, const PRUnichar *aData) : + mTopic(aTopic), mData(aData) + { + } + + NS_IMETHOD Run() + { + MOZ_ASSERT(NS_IsMainThread()); + LOG("Dispatching low-memory memory-pressure event"); + + nsCOMPtr os = services::GetObserverService(); + if (os) { + os->NotifyObservers(nullptr, mTopic, mData); + } + return NS_OK; + } +}; + +static void +Dispatch(const char *aTopic, const PRUnichar *aData) +{ + nsRefPtr memoryPressureRunnable = + new MemoryPressureRunnable(aTopic, aData); + NS_DispatchToMainThread(memoryPressureRunnable); +} + /** * MemoryPressureWatcher watches sysfs from its own thread to notice when the * system is under memory pressure. When we observe memory pressure, we use @@ -156,8 +186,8 @@ public: // We use low-memory-no-forward because each process has its own watcher // and thus there is no need for the main process to forward this event. - rv = NS_DispatchMemoryPressure(MemPressure_New); - NS_ENSURE_SUCCESS(rv, rv); + Dispatch("memory-pressure", + NS_LITERAL_STRING("low-memory-no-forward").get()); // Manually check lowMemFd until we observe that memory pressure is over. // We won't fire any more low-memory events until we observe that @@ -189,8 +219,8 @@ public: NS_ENSURE_SUCCESS(rv, rv); if (memoryPressure) { - rv = NS_DispatchMemoryPressure(MemPressure_Ongoing); - NS_ENSURE_SUCCESS(rv, rv); + Dispatch("memory-pressure", + NS_LITERAL_STRING("low-memory-ongoing-no-forward").get()); continue; } } while (false); diff --git a/xpcom/base/AvailableMemoryTracker.cpp b/xpcom/base/AvailableMemoryTracker.cpp index 75f31aea9b99..7f248a06e539 100644 --- a/xpcom/base/AvailableMemoryTracker.cpp +++ b/xpcom/base/AvailableMemoryTracker.cpp @@ -15,7 +15,6 @@ #include "nsIObserverService.h" #include "nsIRunnable.h" #include "nsISupports.h" -#include "nsMemoryPressure.h" #include "nsPrintfCString.h" #include "nsThread.h" @@ -188,7 +187,7 @@ bool MaybeScheduleMemoryPressureEvent() sLastLowMemoryNotificationTime = PR_IntervalNow(); LOG("Scheduling memory pressure notification."); - NS_DispatchEventualMemoryPressure(MemPressure_New); + ScheduleMemoryPressureEvent(); return true; } @@ -213,7 +212,7 @@ void CheckMemAvailable() // so don't worry about firing this notification too often. LOG("Detected low virtual memory."); PR_ATOMIC_INCREMENT(&sNumLowVirtualMemEvents); - NS_DispatchEventualMemoryPressure(MemPressure_New); + ScheduleMemoryPressureEvent(); } else if (stat.ullAvailPageFile < sLowCommitSpaceThreshold * 1024 * 1024) { LOG("Detected low available page file space."); diff --git a/xpcom/threads/moz.build b/xpcom/threads/moz.build index f145779123de..920864bc0cbc 100644 --- a/xpcom/threads/moz.build +++ b/xpcom/threads/moz.build @@ -24,7 +24,6 @@ MODULE = 'xpcom' EXPORTS += [ 'nsEventQueue.h', - 'nsMemoryPressure.h', 'nsProcess.h', 'nsThread.h', ] @@ -41,7 +40,6 @@ CPP_SOURCES += [ 'TimerThread.cpp', 'nsEnvironment.cpp', 'nsEventQueue.cpp', - 'nsMemoryPressure.cpp', 'nsProcessCommon.cpp', 'nsThread.cpp', 'nsThreadManager.cpp', diff --git a/xpcom/threads/nsMemoryPressure.cpp b/xpcom/threads/nsMemoryPressure.cpp deleted file mode 100644 index 6cb0970a7f15..000000000000 --- a/xpcom/threads/nsMemoryPressure.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "nsMemoryPressure.h" -#include "mozilla/Assertions.h" -#include "mozilla/Atomics.h" - -#include "nsThreadUtils.h" - -using namespace mozilla; - -static Atomic sMemoryPressurePending; -MOZ_STATIC_ASSERT(MemPressure_None == 0, - "Bad static initialization with the default constructor."); - -MemoryPressureState -NS_GetPendingMemoryPressure() -{ - int32_t value = sMemoryPressurePending.exchange(MemPressure_None); - return MemoryPressureState(value); -} - -void -NS_DispatchEventualMemoryPressure(MemoryPressureState state) -{ - /* - * A new memory pressure event erases an ongoing memory pressure, but an - * existing "new" memory pressure event takes precedence over a new "ongoing" - * memory pressure event. - */ - switch (state) { - case MemPressure_None: - sMemoryPressurePending = MemPressure_None; - break; - case MemPressure_New: - sMemoryPressurePending = MemPressure_New; - break; - case MemPressure_Ongoing: - sMemoryPressurePending.compareExchange(MemPressure_None, MemPressure_Ongoing); - break; - } -} - -nsresult -NS_DispatchMemoryPressure(MemoryPressureState state) -{ - NS_DispatchEventualMemoryPressure(state); - nsCOMPtr event = new nsRunnable; - NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); - return NS_DispatchToMainThread(event); -} diff --git a/xpcom/threads/nsMemoryPressure.h b/xpcom/threads/nsMemoryPressure.h deleted file mode 100644 index cf5d60f45fb4..000000000000 --- a/xpcom/threads/nsMemoryPressure.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#ifndef nsMemoryPressure_h__ -#define nsMemoryPressure_h__ - -#include "nscore.h" - -enum MemoryPressureState { - /* - * No memory pressure. - */ - MemPressure_None = 0, - - /* - * New memory pressure deteced. - * - * On a new memory pressure, we stop everything to start cleaning - * aggresively the memory used, in order to free as much memory as - * possible. - */ - MemPressure_New, - - /* - * Repeated memory pressure. - * - * A repeated memory pressure implies to clean softly recent allocations. - * It is supposed to happen after a new memory pressure which already - * cleaned aggressivley. So there is no need to damage the reactivity of - * Gecko by stopping the world again. - * - * In case of conflict with an new memory pressue, the new memory pressure - * takes precedence over an ongoing memory pressure. The reason being - * that if no events are processed between 2 notifications (new followed - * by ongoing, or ongoing followed by a new) we want to be as aggresive as - * possible on the clean-up of the memory. After all, we are trying to - * keep Gecko alive as long as possible. - */ - MemPressure_Ongoing -}; - -/** - * Return and erase the latest state of the memory pressure event set by any of - * the corresponding dispatch function. - */ -MemoryPressureState -NS_GetPendingMemoryPressure(); - -/** - * This function causes the main thread to fire a memory pressure event - * before processing the next event, but if there are no events pending in - * the main thread's event queue, the memory pressure event would not be - * dispatched until one is enqueued. It is infallible and does not allocate - * any memory. - * - * You may call this function from any thread. - */ -void -NS_DispatchEventualMemoryPressure(MemoryPressureState state); - -/** - * This function causes the main thread to fire a memory pressure event - * before processing the next event. We wake up the main thread by adding a - * dummy event to its event loop, so, unlike with - * NS_DispatchEventualMemoryPressure, this memory-pressure event is always - * fired relatively quickly, even if the event loop is otherwise empty. - * - * You may call this function from any thread. - */ -nsresult -NS_DispatchMemoryPressure(MemoryPressureState state); - -#endif // nsMemoryPressure_h__ diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index 19eba00b0c8c..6517dd7060d4 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -5,7 +5,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/ReentrantMonitor.h" -#include "nsMemoryPressure.h" #include "nsThread.h" #include "nsThreadManager.h" #include "nsIClassInfoImpl.h" @@ -58,6 +57,23 @@ NS_DECL_CI_INTERFACE_GETTER(nsThread) nsIThreadObserver* nsThread::sMainThreadObserver = nullptr; +namespace mozilla { + +// Fun fact: Android's GCC won't convert bool* to int32_t*, so we can't +// PR_ATOMIC_SET a bool. +static int32_t sMemoryPressurePending = 0; + +/* + * It's important that this function not acquire any locks, nor do anything + * which might cause malloc to run. + */ +void ScheduleMemoryPressureEvent() +{ + PR_ATOMIC_SET(&sMemoryPressurePending, 1); +} + +} // namespace mozilla + //----------------------------------------------------------------------------- // Because we do not have our own nsIFactory, we have to implement nsIClassInfo // somewhat manually. @@ -564,20 +580,14 @@ nsThread::ProcessNextEvent(bool mayWait, bool *result) // Fire a memory pressure notification, if we're the main thread and one is // pending. if (MAIN_THREAD == mIsMainThread && !ShuttingDown()) { - MemoryPressureState mpPending = NS_GetPendingMemoryPressure(); - if (mpPending != MemPressure_None) { + bool mpPending = PR_ATOMIC_SET(&sMemoryPressurePending, 0); + if (mpPending) { nsCOMPtr os = services::GetObserverService(); - - // Use no-forward to prevent the notifications from being transferred to - // the children of this process. - NS_NAMED_LITERAL_STRING(lowMem, "low-memory-no-forward"); - NS_NAMED_LITERAL_STRING(lowMemOngoing, "low-memory-ongoing-no-forward"); - if (os) { os->NotifyObservers(nullptr, "memory-pressure", - mpPending == MemPressure_New ? lowMem.get() : - lowMemOngoing.get()); - } else { + NS_LITERAL_STRING("low-memory").get()); + } + else { NS_WARNING("Can't get observer service!"); } } diff --git a/xpcom/threads/nsThread.h b/xpcom/threads/nsThread.h index 497b829b6072..19c509216abb 100644 --- a/xpcom/threads/nsThread.h +++ b/xpcom/threads/nsThread.h @@ -128,4 +128,16 @@ private: nsresult mResult; }; +namespace mozilla { + +/** + * This function causes the main thread to fire a memory pressure event at its + * next available opportunity. + * + * You may call this function from any thread. + */ +void ScheduleMemoryPressureEvent(); + +} // namespace mozilla + #endif // nsThread_h__