Bug 1690340 - Part 4: Insert the "Page Source" before the "Extensions for Developers...
[gecko.git] / xpcom / base / nsMemoryImpl.cpp
blob1a52f81ef70f48a4ac4370ce1149d293edb5e468
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsMemoryImpl.h"
8 #include "nsThreadUtils.h"
10 #include "nsIObserver.h"
11 #include "nsIObserverService.h"
12 #include "nsISimpleEnumerator.h"
14 #include "nsCOMPtr.h"
15 #include "mozilla/Services.h"
17 #ifdef ANDROID
18 # include <stdio.h>
20 // Minimum memory threshold for a device to be considered
21 // a low memory platform. This value has be in sync with
22 // Java's equivalent threshold, defined in
23 // mobile/android/base/util/HardwareUtils.java
24 # define LOW_MEMORY_THRESHOLD_KB (384 * 1024)
25 #endif
27 static nsMemoryImpl sGlobalMemory;
29 NS_IMPL_QUERY_INTERFACE(nsMemoryImpl, nsIMemory)
31 NS_IMETHODIMP
32 nsMemoryImpl::HeapMinimize(bool aImmediate) {
33 return FlushMemory(u"heap-minimize", aImmediate);
36 NS_IMETHODIMP
37 nsMemoryImpl::IsLowMemoryPlatform(bool* aResult) {
38 #ifdef ANDROID
39 static int sLowMemory =
40 -1; // initialize to unknown, lazily evaluate to 0 or 1
41 if (sLowMemory == -1) {
42 sLowMemory = 0; // assume "not low memory" in case file operations fail
43 *aResult = false;
45 // check if MemTotal from /proc/meminfo is less than LOW_MEMORY_THRESHOLD_KB
46 FILE* fd = fopen("/proc/meminfo", "r");
47 if (!fd) {
48 return NS_OK;
50 uint64_t mem = 0;
51 int rv = fscanf(fd, "MemTotal: %" PRIu64 " kB", &mem);
52 if (fclose(fd)) {
53 return NS_OK;
55 if (rv != 1) {
56 return NS_OK;
58 sLowMemory = (mem < LOW_MEMORY_THRESHOLD_KB) ? 1 : 0;
60 *aResult = (sLowMemory == 1);
61 #else
62 *aResult = false;
63 #endif
64 return NS_OK;
67 /*static*/
68 nsresult nsMemoryImpl::Create(nsISupports* aOuter, const nsIID& aIID,
69 void** aResult) {
70 if (NS_WARN_IF(aOuter)) {
71 return NS_ERROR_NO_AGGREGATION;
73 return sGlobalMemory.QueryInterface(aIID, aResult);
76 nsresult nsMemoryImpl::FlushMemory(const char16_t* aReason, bool aImmediate) {
77 if (aImmediate) {
78 // They've asked us to run the flusher *immediately*. We've
79 // got to be on the UI main thread for us to be able to do
80 // that...are we?
81 if (!NS_IsMainThread()) {
82 NS_ERROR("can't synchronously flush memory: not on UI thread");
83 return NS_ERROR_FAILURE;
87 bool lastVal = sIsFlushing.exchange(true);
88 if (lastVal) {
89 return NS_OK;
92 PRIntervalTime now = PR_IntervalNow();
94 // Run the flushers immediately if we can; otherwise, proxy to the
95 // UI thread and run 'em asynchronously.
96 nsresult rv = NS_OK;
97 if (aImmediate) {
98 RunFlushers(aReason);
99 } else {
100 // Don't broadcast more than once every 1000ms to avoid being noisy
101 if (PR_IntervalToMicroseconds(now - sLastFlushTime) > 1000) {
102 sFlushEvent.mReason = aReason;
103 rv = NS_DispatchToMainThread(&sFlushEvent);
107 sLastFlushTime = now;
108 return rv;
111 void nsMemoryImpl::RunFlushers(const char16_t* aReason) {
112 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
113 if (os) {
114 // Instead of:
115 // os->NotifyObservers(this, "memory-pressure", aReason);
116 // we are going to do this manually to see who/what is
117 // deallocating.
119 nsCOMPtr<nsISimpleEnumerator> e;
120 os->EnumerateObservers("memory-pressure", getter_AddRefs(e));
122 if (e) {
123 nsCOMPtr<nsIObserver> observer;
124 bool loop = true;
126 while (NS_SUCCEEDED(e->HasMoreElements(&loop)) && loop) {
127 nsCOMPtr<nsISupports> supports;
128 e->GetNext(getter_AddRefs(supports));
130 if (!supports) {
131 continue;
134 observer = do_QueryInterface(supports);
135 observer->Observe(observer, "memory-pressure", aReason);
140 sIsFlushing = false;
143 // XXX need NS_IMPL_STATIC_ADDREF/RELEASE
144 NS_IMETHODIMP_(MozExternalRefCountType)
145 nsMemoryImpl::FlushEvent::AddRef() { return 2; }
146 NS_IMETHODIMP_(MozExternalRefCountType)
147 nsMemoryImpl::FlushEvent::Release() { return 1; }
148 NS_IMPL_QUERY_INTERFACE(nsMemoryImpl::FlushEvent, nsIRunnable)
150 NS_IMETHODIMP
151 nsMemoryImpl::FlushEvent::Run() {
152 sGlobalMemory.RunFlushers(mReason);
153 return NS_OK;
156 mozilla::Atomic<bool> nsMemoryImpl::sIsFlushing;
158 PRIntervalTime nsMemoryImpl::sLastFlushTime = 0;
160 nsMemoryImpl::FlushEvent nsMemoryImpl::sFlushEvent;
162 nsresult NS_GetMemoryManager(nsIMemory** aResult) {
163 return sGlobalMemory.QueryInterface(NS_GET_IID(nsIMemory), (void**)aResult);