Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsMemoryImpl.h"
7 #include "nsThreadUtils.h"
9 #include "nsIObserver.h"
10 #include "nsIObserverService.h"
11 #include "nsISimpleEnumerator.h"
13 #include "nsCOMPtr.h"
14 #include "mozilla/Services.h"
16 #ifdef ANDROID
17 #include <stdio.h>
19 // Minimum memory threshold for a device to be considered
20 // a low memory platform. This value has be in sync with
21 // Java's equivalent threshold, defined in
22 // mobile/android/base/util/HardwareUtils.java
23 #define LOW_MEMORY_THRESHOLD_KB (384 * 1024)
24 #endif
26 static nsMemoryImpl sGlobalMemory;
28 NS_IMPL_QUERY_INTERFACE(nsMemoryImpl, nsIMemory)
30 NS_IMETHODIMP_(void*)
31 nsMemoryImpl::Alloc(size_t size)
32 {
33 return NS_Alloc(size);
34 }
36 NS_IMETHODIMP_(void*)
37 nsMemoryImpl::Realloc(void* ptr, size_t size)
38 {
39 return NS_Realloc(ptr, size);
40 }
42 NS_IMETHODIMP_(void)
43 nsMemoryImpl::Free(void* ptr)
44 {
45 NS_Free(ptr);
46 }
48 NS_IMETHODIMP
49 nsMemoryImpl::HeapMinimize(bool aImmediate)
50 {
51 return FlushMemory(MOZ_UTF16("heap-minimize"), aImmediate);
52 }
54 NS_IMETHODIMP
55 nsMemoryImpl::IsLowMemory(bool *result)
56 {
57 NS_ERROR("IsLowMemory is deprecated. See bug 592308.");
58 *result = false;
59 return NS_OK;
60 }
62 NS_IMETHODIMP
63 nsMemoryImpl::IsLowMemoryPlatform(bool *result)
64 {
65 #ifdef ANDROID
66 static int sLowMemory = -1; // initialize to unknown, lazily evaluate to 0 or 1
67 if (sLowMemory == -1) {
68 sLowMemory = 0; // assume "not low memory" in case file operations fail
69 *result = false;
71 // check if MemTotal from /proc/meminfo is less than LOW_MEMORY_THRESHOLD_KB
72 FILE* fd = fopen("/proc/meminfo", "r");
73 if (!fd) {
74 return NS_OK;
75 }
76 uint64_t mem = 0;
77 int rv = fscanf(fd, "MemTotal: %llu kB", &mem);
78 if (fclose(fd)) {
79 return NS_OK;
80 }
81 if (rv != 1) {
82 return NS_OK;
83 }
84 sLowMemory = (mem < LOW_MEMORY_THRESHOLD_KB) ? 1 : 0;
85 }
86 *result = (sLowMemory == 1);
87 #else
88 *result = false;
89 #endif
90 return NS_OK;
91 }
93 /*static*/ nsresult
94 nsMemoryImpl::Create(nsISupports* outer, const nsIID& aIID, void **aResult)
95 {
96 if (NS_WARN_IF(outer))
97 return NS_ERROR_NO_AGGREGATION;
98 return sGlobalMemory.QueryInterface(aIID, aResult);
99 }
101 nsresult
102 nsMemoryImpl::FlushMemory(const char16_t* aReason, bool aImmediate)
103 {
104 nsresult rv = NS_OK;
106 if (aImmediate) {
107 // They've asked us to run the flusher *immediately*. We've
108 // got to be on the UI main thread for us to be able to do
109 // that...are we?
110 if (!NS_IsMainThread()) {
111 NS_ERROR("can't synchronously flush memory: not on UI thread");
112 return NS_ERROR_FAILURE;
113 }
114 }
116 bool lastVal = sIsFlushing.exchange(true);
117 if (lastVal)
118 return NS_OK;
120 PRIntervalTime now = PR_IntervalNow();
122 // Run the flushers immediately if we can; otherwise, proxy to the
123 // UI thread an run 'em asynchronously.
124 if (aImmediate) {
125 rv = RunFlushers(aReason);
126 }
127 else {
128 // Don't broadcast more than once every 1000ms to avoid being noisy
129 if (PR_IntervalToMicroseconds(now - sLastFlushTime) > 1000) {
130 sFlushEvent.mReason = aReason;
131 rv = NS_DispatchToMainThread(&sFlushEvent, NS_DISPATCH_NORMAL);
132 }
133 }
135 sLastFlushTime = now;
136 return rv;
137 }
139 nsresult
140 nsMemoryImpl::RunFlushers(const char16_t* aReason)
141 {
142 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
143 if (os) {
145 // Instead of:
146 // os->NotifyObservers(this, "memory-pressure", aReason);
147 // we are going to do this manually to see who/what is
148 // deallocating.
150 nsCOMPtr<nsISimpleEnumerator> e;
151 os->EnumerateObservers("memory-pressure", getter_AddRefs(e));
153 if ( e ) {
154 nsCOMPtr<nsIObserver> observer;
155 bool loop = true;
157 while (NS_SUCCEEDED(e->HasMoreElements(&loop)) && loop)
158 {
159 nsCOMPtr<nsISupports> supports;
160 e->GetNext(getter_AddRefs(supports));
162 if (!supports)
163 continue;
165 observer = do_QueryInterface(supports);
166 observer->Observe(observer, "memory-pressure", aReason);
167 }
168 }
169 }
171 sIsFlushing = false;
172 return NS_OK;
173 }
175 // XXX need NS_IMPL_STATIC_ADDREF/RELEASE
176 NS_IMETHODIMP_(MozExternalRefCountType) nsMemoryImpl::FlushEvent::AddRef() { return 2; }
177 NS_IMETHODIMP_(MozExternalRefCountType) nsMemoryImpl::FlushEvent::Release() { return 1; }
178 NS_IMPL_QUERY_INTERFACE(nsMemoryImpl::FlushEvent, nsIRunnable)
180 NS_IMETHODIMP
181 nsMemoryImpl::FlushEvent::Run()
182 {
183 sGlobalMemory.RunFlushers(mReason);
184 return NS_OK;
185 }
187 mozilla::Atomic<bool>
188 nsMemoryImpl::sIsFlushing;
190 PRIntervalTime
191 nsMemoryImpl::sLastFlushTime = 0;
193 nsMemoryImpl::FlushEvent
194 nsMemoryImpl::sFlushEvent;
196 XPCOM_API(void*)
197 NS_Alloc(size_t size)
198 {
199 return moz_xmalloc(size);
200 }
202 XPCOM_API(void*)
203 NS_Realloc(void* ptr, size_t size)
204 {
205 return moz_xrealloc(ptr, size);
206 }
208 XPCOM_API(void)
209 NS_Free(void* ptr)
210 {
211 moz_free(ptr);
212 }
214 nsresult
215 NS_GetMemoryManager(nsIMemory* *result)
216 {
217 return sGlobalMemory.QueryInterface(NS_GET_IID(nsIMemory), (void**) result);
218 }