Bumping manifests a=b2g-bump
[gecko.git] / xpcom / base / nsMemoryImpl.cpp
blob778ee297025acf37a893325082f58d8b368bc7e2
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_(void*)
32 nsMemoryImpl::Alloc(size_t aSize)
34 return NS_Alloc(aSize);
37 NS_IMETHODIMP_(void*)
38 nsMemoryImpl::Realloc(void* aPtr, size_t aSize)
40 return NS_Realloc(aPtr, aSize);
43 NS_IMETHODIMP_(void)
44 nsMemoryImpl::Free(void* aPtr)
46 NS_Free(aPtr);
49 NS_IMETHODIMP
50 nsMemoryImpl::HeapMinimize(bool aImmediate)
52 return FlushMemory(MOZ_UTF16("heap-minimize"), aImmediate);
55 NS_IMETHODIMP
56 nsMemoryImpl::IsLowMemory(bool* aResult)
58 NS_ERROR("IsLowMemory is deprecated. See bug 592308.");
59 *aResult = false;
60 return NS_OK;
63 NS_IMETHODIMP
64 nsMemoryImpl::IsLowMemoryPlatform(bool* aResult)
66 #ifdef ANDROID
67 static int sLowMemory = -1; // initialize to unknown, lazily evaluate to 0 or 1
68 if (sLowMemory == -1) {
69 sLowMemory = 0; // assume "not low memory" in case file operations fail
70 *aResult = false;
72 // check if MemTotal from /proc/meminfo is less than LOW_MEMORY_THRESHOLD_KB
73 FILE* fd = fopen("/proc/meminfo", "r");
74 if (!fd) {
75 return NS_OK;
77 uint64_t mem = 0;
78 int rv = fscanf(fd, "MemTotal: %llu kB", &mem);
79 if (fclose(fd)) {
80 return NS_OK;
82 if (rv != 1) {
83 return NS_OK;
85 sLowMemory = (mem < LOW_MEMORY_THRESHOLD_KB) ? 1 : 0;
87 *aResult = (sLowMemory == 1);
88 #else
89 *aResult = false;
90 #endif
91 return NS_OK;
94 /*static*/ nsresult
95 nsMemoryImpl::Create(nsISupports* aOuter, const nsIID& aIID, void** aResult)
97 if (NS_WARN_IF(aOuter)) {
98 return NS_ERROR_NO_AGGREGATION;
100 return sGlobalMemory.QueryInterface(aIID, aResult);
103 nsresult
104 nsMemoryImpl::FlushMemory(const char16_t* aReason, bool aImmediate)
106 nsresult rv = NS_OK;
108 if (aImmediate) {
109 // They've asked us to run the flusher *immediately*. We've
110 // got to be on the UI main thread for us to be able to do
111 // that...are we?
112 if (!NS_IsMainThread()) {
113 NS_ERROR("can't synchronously flush memory: not on UI thread");
114 return NS_ERROR_FAILURE;
118 bool lastVal = sIsFlushing.exchange(true);
119 if (lastVal) {
120 return NS_OK;
123 PRIntervalTime now = PR_IntervalNow();
125 // Run the flushers immediately if we can; otherwise, proxy to the
126 // UI thread an run 'em asynchronously.
127 if (aImmediate) {
128 rv = RunFlushers(aReason);
129 } else {
130 // Don't broadcast more than once every 1000ms to avoid being noisy
131 if (PR_IntervalToMicroseconds(now - sLastFlushTime) > 1000) {
132 sFlushEvent.mReason = aReason;
133 rv = NS_DispatchToMainThread(&sFlushEvent);
137 sLastFlushTime = now;
138 return rv;
141 nsresult
142 nsMemoryImpl::RunFlushers(const char16_t* aReason)
144 nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
145 if (os) {
147 // Instead of:
148 // os->NotifyObservers(this, "memory-pressure", aReason);
149 // we are going to do this manually to see who/what is
150 // deallocating.
152 nsCOMPtr<nsISimpleEnumerator> e;
153 os->EnumerateObservers("memory-pressure", getter_AddRefs(e));
155 if (e) {
156 nsCOMPtr<nsIObserver> observer;
157 bool loop = true;
159 while (NS_SUCCEEDED(e->HasMoreElements(&loop)) && loop) {
160 nsCOMPtr<nsISupports> supports;
161 e->GetNext(getter_AddRefs(supports));
163 if (!supports) {
164 continue;
167 observer = do_QueryInterface(supports);
168 observer->Observe(observer, "memory-pressure", aReason);
173 sIsFlushing = false;
174 return NS_OK;
177 // XXX need NS_IMPL_STATIC_ADDREF/RELEASE
178 NS_IMETHODIMP_(MozExternalRefCountType)
179 nsMemoryImpl::FlushEvent::AddRef()
181 return 2;
183 NS_IMETHODIMP_(MozExternalRefCountType)
184 nsMemoryImpl::FlushEvent::Release()
186 return 1;
188 NS_IMPL_QUERY_INTERFACE(nsMemoryImpl::FlushEvent, nsIRunnable)
190 NS_IMETHODIMP
191 nsMemoryImpl::FlushEvent::Run()
193 sGlobalMemory.RunFlushers(mReason);
194 return NS_OK;
197 mozilla::Atomic<bool>
198 nsMemoryImpl::sIsFlushing;
200 PRIntervalTime
201 nsMemoryImpl::sLastFlushTime = 0;
203 nsMemoryImpl::FlushEvent
204 nsMemoryImpl::sFlushEvent;
206 XPCOM_API(void*)
207 NS_Alloc(size_t aSize)
209 return moz_xmalloc(aSize);
212 XPCOM_API(void*)
213 NS_Realloc(void* aPtr, size_t aSize)
215 return moz_xrealloc(aPtr, aSize);
218 XPCOM_API(void)
219 NS_Free(void* aPtr)
221 moz_free(aPtr);
224 nsresult
225 NS_GetMemoryManager(nsIMemory** aResult)
227 return sGlobalMemory.QueryInterface(NS_GET_IID(nsIMemory), (void**)aResult);