summaryrefslogtreecommitdiff
path: root/base/memory/memory_pressure_listener.cc
diff options
context:
space:
mode:
Diffstat (limited to 'base/memory/memory_pressure_listener.cc')
-rw-r--r--base/memory/memory_pressure_listener.cc129
1 files changed, 129 insertions, 0 deletions
diff --git a/base/memory/memory_pressure_listener.cc b/base/memory/memory_pressure_listener.cc
new file mode 100644
index 0000000000..669fb17b7a
--- /dev/null
+++ b/base/memory/memory_pressure_listener.cc
@@ -0,0 +1,129 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/memory_pressure_listener.h"
+
+#include "base/observer_list_threadsafe.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+
+namespace {
+
+// This class is thread safe and internally synchronized.
+class MemoryPressureObserver {
+ public:
+ // There is at most one MemoryPressureObserver and it is never deleted.
+ ~MemoryPressureObserver() = delete;
+
+ void AddObserver(MemoryPressureListener* listener, bool sync) {
+ async_observers_->AddObserver(listener);
+ if (sync) {
+ AutoLock lock(sync_observers_lock_);
+ sync_observers_.AddObserver(listener);
+ }
+ }
+
+ void RemoveObserver(MemoryPressureListener* listener) {
+ async_observers_->RemoveObserver(listener);
+ AutoLock lock(sync_observers_lock_);
+ sync_observers_.RemoveObserver(listener);
+ }
+
+ void Notify(
+ MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ async_observers_->Notify(FROM_HERE, &MemoryPressureListener::Notify,
+ memory_pressure_level);
+ AutoLock lock(sync_observers_lock_);
+ for (auto& observer : sync_observers_)
+ observer.SyncNotify(memory_pressure_level);
+ }
+
+ private:
+ const scoped_refptr<ObserverListThreadSafe<MemoryPressureListener>>
+ async_observers_ = base::MakeRefCounted<
+ ObserverListThreadSafe<MemoryPressureListener>>();
+ ObserverList<MemoryPressureListener> sync_observers_;
+ Lock sync_observers_lock_;
+};
+
+// Gets the shared MemoryPressureObserver singleton instance.
+MemoryPressureObserver* GetMemoryPressureObserver() {
+ static auto* const observer = new MemoryPressureObserver();
+ return observer;
+}
+
+subtle::Atomic32 g_notifications_suppressed = 0;
+
+} // namespace
+
+MemoryPressureListener::MemoryPressureListener(
+ const MemoryPressureListener::MemoryPressureCallback& callback)
+ : callback_(callback) {
+ GetMemoryPressureObserver()->AddObserver(this, false);
+}
+
+MemoryPressureListener::MemoryPressureListener(
+ const MemoryPressureListener::MemoryPressureCallback& callback,
+ const MemoryPressureListener::SyncMemoryPressureCallback&
+ sync_memory_pressure_callback)
+ : callback_(callback),
+ sync_memory_pressure_callback_(sync_memory_pressure_callback) {
+ GetMemoryPressureObserver()->AddObserver(this, true);
+}
+
+MemoryPressureListener::~MemoryPressureListener() {
+ GetMemoryPressureObserver()->RemoveObserver(this);
+}
+
+void MemoryPressureListener::Notify(MemoryPressureLevel memory_pressure_level) {
+ callback_.Run(memory_pressure_level);
+}
+
+void MemoryPressureListener::SyncNotify(
+ MemoryPressureLevel memory_pressure_level) {
+ if (!sync_memory_pressure_callback_.is_null()) {
+ sync_memory_pressure_callback_.Run(memory_pressure_level);
+ }
+}
+
+// static
+void MemoryPressureListener::NotifyMemoryPressure(
+ MemoryPressureLevel memory_pressure_level) {
+ DCHECK_NE(memory_pressure_level, MEMORY_PRESSURE_LEVEL_NONE);
+ TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("memory-infra"),
+ "MemoryPressureListener::NotifyMemoryPressure",
+ TRACE_EVENT_SCOPE_THREAD, "level",
+ memory_pressure_level);
+ if (AreNotificationsSuppressed())
+ return;
+ DoNotifyMemoryPressure(memory_pressure_level);
+}
+
+// static
+bool MemoryPressureListener::AreNotificationsSuppressed() {
+ return subtle::Acquire_Load(&g_notifications_suppressed) == 1;
+}
+
+// static
+void MemoryPressureListener::SetNotificationsSuppressed(bool suppress) {
+ subtle::Release_Store(&g_notifications_suppressed, suppress ? 1 : 0);
+}
+
+// static
+void MemoryPressureListener::SimulatePressureNotification(
+ MemoryPressureLevel memory_pressure_level) {
+ // Notify all listeners even if regular pressure notifications are suppressed.
+ DoNotifyMemoryPressure(memory_pressure_level);
+}
+
+// static
+void MemoryPressureListener::DoNotifyMemoryPressure(
+ MemoryPressureLevel memory_pressure_level) {
+ DCHECK_NE(memory_pressure_level, MEMORY_PRESSURE_LEVEL_NONE);
+
+ GetMemoryPressureObserver()->Notify(memory_pressure_level);
+}
+
+} // namespace base