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/. */
8 #include "nsThreadUtils.h"
10 #include "nsIObserver.h"
11 #include "nsIObserverService.h"
12 #include "nsIRunnable.h"
13 #include "nsISimpleEnumerator.h"
16 #include "mozilla/Services.h"
17 #include "mozilla/Atomics.h"
18 #include "mozilla/IntegerPrintfMacros.h"
23 // Minimum memory threshold for a device to be considered
24 // a low memory platform. This value has be in sync with
25 // Java's equivalent threshold, defined in HardwareUtils.java
26 # define LOW_MEMORY_THRESHOLD_KB (384 * 1024)
29 static mozilla::Atomic
<bool> sIsFlushing
;
30 static PRIntervalTime sLastFlushTime
= 0;
33 bool nsMemory::IsLowMemoryPlatform() {
35 static int sLowMemory
=
36 -1; // initialize to unknown, lazily evaluate to 0 or 1
37 if (sLowMemory
== -1) {
38 sLowMemory
= 0; // assume "not low memory" in case file operations fail
40 // check if MemTotal from /proc/meminfo is less than LOW_MEMORY_THRESHOLD_KB
41 FILE* fd
= fopen("/proc/meminfo", "r");
46 int rv
= fscanf(fd
, "MemTotal: %" PRIu64
" kB", &mem
);
53 sLowMemory
= (mem
< LOW_MEMORY_THRESHOLD_KB
) ? 1 : 0;
55 return (sLowMemory
== 1);
61 static void RunFlushers(const char16_t
* aReason
) {
62 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
65 // os->NotifyObservers(this, "memory-pressure", aReason);
66 // we are going to do this manually to see who/what is
69 nsCOMPtr
<nsISimpleEnumerator
> e
;
70 os
->EnumerateObservers("memory-pressure", getter_AddRefs(e
));
73 nsCOMPtr
<nsIObserver
> observer
;
76 while (NS_SUCCEEDED(e
->HasMoreElements(&loop
)) && loop
) {
77 nsCOMPtr
<nsISupports
> supports
;
78 e
->GetNext(getter_AddRefs(supports
));
84 observer
= do_QueryInterface(supports
);
85 observer
->Observe(observer
, "memory-pressure", aReason
);
93 static nsresult
FlushMemory(const char16_t
* aReason
, bool aImmediate
) {
95 // They've asked us to run the flusher *immediately*. We've
96 // got to be on the UI main thread for us to be able to do
98 if (!NS_IsMainThread()) {
99 NS_ERROR("can't synchronously flush memory: not on UI thread");
100 return NS_ERROR_FAILURE
;
104 bool lastVal
= sIsFlushing
.exchange(true);
109 PRIntervalTime now
= PR_IntervalNow();
111 // Run the flushers immediately if we can; otherwise, proxy to the
112 // UI thread and run 'em asynchronously.
115 RunFlushers(aReason
);
117 // Don't broadcast more than once every 1000ms to avoid being noisy
118 if (PR_IntervalToMicroseconds(now
- sLastFlushTime
) > 1000) {
119 nsCOMPtr
<nsIRunnable
> runnable(NS_NewRunnableFunction(
121 [reason
= aReason
]() -> void { RunFlushers(reason
); }));
122 NS_DispatchToMainThread(runnable
.forget());
126 sLastFlushTime
= now
;
130 nsresult
nsMemory::HeapMinimize(bool aImmediate
) {
131 return FlushMemory(u
"heap-minimize", aImmediate
);