1/*
2 * Copyright (C) 2011-2017 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2014 Raspberry Pi Foundation. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <atomic>
30#include <ctime>
31#include <wtf/FastMalloc.h>
32#include <wtf/Forward.h>
33#include <wtf/Function.h>
34#include <wtf/Optional.h>
35#include <wtf/RunLoop.h>
36
37#if USE(GLIB)
38#include <wtf/glib/GRefPtr.h>
39#endif
40
41#if OS(WINDOWS)
42#include <wtf/win/Win32Handle.h>
43#endif
44
45namespace WTF {
46
47enum class MemoryUsagePolicy {
48 Unrestricted, // Allocate as much as you want
49 Conservative, // Maybe you don't cache every single thing
50 Strict, // Time to start pinching pennies for real
51};
52
53enum class WebsamProcessState {
54 Active,
55 Inactive,
56};
57
58enum class Critical { No, Yes };
59enum class Synchronous { No, Yes };
60
61typedef WTF::Function<void(Critical, Synchronous)> LowMemoryHandler;
62
63class MemoryPressureHandler {
64 friend class WTF::NeverDestroyed<MemoryPressureHandler>;
65public:
66 WTF_EXPORT_PRIVATE static MemoryPressureHandler& singleton();
67
68 WTF_EXPORT_PRIVATE void install();
69
70 WTF_EXPORT_PRIVATE void setShouldUsePeriodicMemoryMonitor(bool);
71
72#if OS(LINUX)
73 WTF_EXPORT_PRIVATE void triggerMemoryPressureEvent(bool isCritical);
74#endif
75
76 void setMemoryKillCallback(WTF::Function<void()>&& function) { m_memoryKillCallback = WTFMove(function); }
77 void setMemoryPressureStatusChangedCallback(WTF::Function<void(bool)>&& function) { m_memoryPressureStatusChangedCallback = WTFMove(function); }
78 void setDidExceedInactiveLimitWhileActiveCallback(WTF::Function<void()>&& function) { m_didExceedInactiveLimitWhileActiveCallback = WTFMove(function); }
79
80 void setLowMemoryHandler(LowMemoryHandler&& handler)
81 {
82 m_lowMemoryHandler = WTFMove(handler);
83 }
84
85 bool isUnderMemoryPressure() const
86 {
87 return m_underMemoryPressure
88#if PLATFORM(MAC)
89 || m_memoryUsagePolicy >= MemoryUsagePolicy::Strict
90#endif
91 || m_isSimulatingMemoryPressure;
92 }
93 void setUnderMemoryPressure(bool);
94
95 WTF_EXPORT_PRIVATE static MemoryUsagePolicy currentMemoryUsagePolicy();
96
97#if PLATFORM(COCOA)
98 WTF_EXPORT_PRIVATE void setDispatchQueue(dispatch_queue_t);
99#endif
100
101 class ReliefLogger {
102 public:
103 explicit ReliefLogger(const char *log)
104 : m_logString(log)
105 , m_initialMemory(loggingEnabled() ? platformMemoryUsage() : MemoryUsage { })
106 {
107 }
108
109 ~ReliefLogger()
110 {
111 if (loggingEnabled())
112 logMemoryUsageChange();
113 }
114
115
116 const char* logString() const { return m_logString; }
117 static void setLoggingEnabled(bool enabled) { s_loggingEnabled = enabled; }
118 static bool loggingEnabled()
119 {
120#if RELEASE_LOG_DISABLED
121 return s_loggingEnabled;
122#else
123 return true;
124#endif
125 }
126
127 private:
128 struct MemoryUsage {
129 MemoryUsage() = default;
130 MemoryUsage(size_t resident, size_t physical)
131 : resident(resident)
132 , physical(physical)
133 {
134 }
135 size_t resident { 0 };
136 size_t physical { 0 };
137 };
138 Optional<MemoryUsage> platformMemoryUsage();
139 void logMemoryUsageChange();
140
141 const char* m_logString;
142 Optional<MemoryUsage> m_initialMemory;
143
144 WTF_EXPORT_PRIVATE static bool s_loggingEnabled;
145 };
146
147 WTF_EXPORT_PRIVATE void releaseMemory(Critical, Synchronous = Synchronous::No);
148
149 WTF_EXPORT_PRIVATE void beginSimulatedMemoryPressure();
150 WTF_EXPORT_PRIVATE void endSimulatedMemoryPressure();
151
152 WTF_EXPORT_PRIVATE void setProcessState(WebsamProcessState);
153 WebsamProcessState processState() const { return m_processState; }
154
155 WTF_EXPORT_PRIVATE static void setPageCount(unsigned);
156
157 void setShouldLogMemoryMemoryPressureEvents(bool shouldLog) { m_shouldLogMemoryMemoryPressureEvents = shouldLog; }
158
159private:
160 size_t thresholdForMemoryKill();
161 void memoryPressureStatusChanged();
162
163 void uninstall();
164
165 void holdOff(Seconds);
166
167 MemoryPressureHandler();
168 ~MemoryPressureHandler() = delete;
169
170 void respondToMemoryPressure(Critical, Synchronous = Synchronous::No);
171 void platformReleaseMemory(Critical);
172 void platformInitialize();
173
174 void measurementTimerFired();
175 void shrinkOrDie();
176 void setMemoryUsagePolicyBasedOnFootprint(size_t);
177 void doesExceedInactiveLimitWhileActive();
178 void doesNotExceedInactiveLimitWhileActive();
179
180 WebsamProcessState m_processState { WebsamProcessState::Inactive };
181
182 unsigned m_pageCount { 0 };
183
184 LowMemoryHandler m_lowMemoryHandler;
185
186 std::atomic<bool> m_underMemoryPressure;
187 bool m_installed { false };
188 bool m_isSimulatingMemoryPressure { false };
189 bool m_shouldLogMemoryMemoryPressureEvents { true };
190 bool m_hasInvokedDidExceedInactiveLimitWhileActiveCallback { false };
191
192 std::unique_ptr<RunLoop::Timer<MemoryPressureHandler>> m_measurementTimer;
193 MemoryUsagePolicy m_memoryUsagePolicy { MemoryUsagePolicy::Unrestricted };
194 WTF::Function<void()> m_memoryKillCallback;
195 WTF::Function<void(bool)> m_memoryPressureStatusChangedCallback;
196 WTF::Function<void()> m_didExceedInactiveLimitWhileActiveCallback;
197
198#if OS(WINDOWS)
199 void windowsMeasurementTimerFired();
200 RunLoop::Timer<MemoryPressureHandler> m_windowsMeasurementTimer;
201 Win32Handle m_lowMemoryHandle;
202#endif
203
204#if OS(LINUX)
205 RunLoop::Timer<MemoryPressureHandler> m_holdOffTimer;
206 void holdOffTimerFired();
207#endif
208
209#if PLATFORM(COCOA)
210 dispatch_queue_t m_dispatchQueue { nullptr };
211#endif
212};
213
214extern WTFLogChannel LogMemoryPressure;
215
216} // namespace WTF
217
218using WTF::Critical;
219using WTF::MemoryPressureHandler;
220using WTF::Synchronous;
221using WTF::WebsamProcessState;
222