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 OS(WINDOWS)
38#include <wtf/win/Win32Handle.h>
39#endif
40
41namespace WTF {
42
43enum class MemoryUsagePolicy {
44 Unrestricted, // Allocate as much as you want
45 Conservative, // Maybe you don't cache every single thing
46 Strict, // Time to start pinching pennies for real
47};
48
49enum class WebsamProcessState {
50 Active,
51 Inactive,
52};
53
54enum class Critical { No, Yes };
55enum class Synchronous { No, Yes };
56
57typedef WTF::Function<void(Critical, Synchronous)> LowMemoryHandler;
58
59class MemoryPressureHandler {
60 WTF_MAKE_FAST_ALLOCATED;
61 friend class WTF::NeverDestroyed<MemoryPressureHandler>;
62public:
63 WTF_EXPORT_PRIVATE static MemoryPressureHandler& singleton();
64
65 WTF_EXPORT_PRIVATE void install();
66
67 WTF_EXPORT_PRIVATE void setShouldUsePeriodicMemoryMonitor(bool);
68
69#if OS(LINUX)
70 WTF_EXPORT_PRIVATE void triggerMemoryPressureEvent(bool isCritical);
71#endif
72
73 void setMemoryKillCallback(WTF::Function<void()>&& function) { m_memoryKillCallback = WTFMove(function); }
74 void setMemoryPressureStatusChangedCallback(WTF::Function<void(bool)>&& function) { m_memoryPressureStatusChangedCallback = WTFMove(function); }
75 void setDidExceedInactiveLimitWhileActiveCallback(WTF::Function<void()>&& function) { m_didExceedInactiveLimitWhileActiveCallback = WTFMove(function); }
76
77 void setLowMemoryHandler(LowMemoryHandler&& handler)
78 {
79 m_lowMemoryHandler = WTFMove(handler);
80 }
81
82 bool isUnderMemoryPressure() const
83 {
84 return m_underMemoryPressure
85#if PLATFORM(MAC)
86 || m_memoryUsagePolicy >= MemoryUsagePolicy::Strict
87#endif
88 || m_isSimulatingMemoryPressure;
89 }
90 void setUnderMemoryPressure(bool);
91
92 WTF_EXPORT_PRIVATE static MemoryUsagePolicy currentMemoryUsagePolicy();
93
94#if PLATFORM(COCOA)
95 WTF_EXPORT_PRIVATE void setDispatchQueue(dispatch_queue_t);
96#endif
97
98 class ReliefLogger {
99 WTF_MAKE_FAST_ALLOCATED;
100 public:
101 explicit ReliefLogger(const char *log)
102 : m_logString(log)
103 , m_initialMemory(loggingEnabled() ? platformMemoryUsage() : MemoryUsage { })
104 {
105 }
106
107 ~ReliefLogger()
108 {
109 if (loggingEnabled())
110 logMemoryUsageChange();
111 }
112
113
114 const char* logString() const { return m_logString; }
115 static void setLoggingEnabled(bool enabled) { s_loggingEnabled = enabled; }
116 static bool loggingEnabled()
117 {
118#if RELEASE_LOG_DISABLED
119 return s_loggingEnabled;
120#else
121 return true;
122#endif
123 }
124
125 private:
126 struct MemoryUsage {
127 WTF_MAKE_STRUCT_FAST_ALLOCATED;
128 MemoryUsage() = default;
129 MemoryUsage(size_t resident, size_t physical)
130 : resident(resident)
131 , physical(physical)
132 {
133 }
134 size_t resident { 0 };
135 size_t physical { 0 };
136 };
137 Optional<MemoryUsage> platformMemoryUsage();
138 void logMemoryUsageChange();
139
140 const char* m_logString;
141 Optional<MemoryUsage> m_initialMemory;
142
143 WTF_EXPORT_PRIVATE static bool s_loggingEnabled;
144 };
145
146 WTF_EXPORT_PRIVATE void releaseMemory(Critical, Synchronous = Synchronous::No);
147
148 WTF_EXPORT_PRIVATE void beginSimulatedMemoryPressure();
149 WTF_EXPORT_PRIVATE void endSimulatedMemoryPressure();
150
151 WTF_EXPORT_PRIVATE void setProcessState(WebsamProcessState);
152 WebsamProcessState processState() const { return m_processState; }
153
154 WTF_EXPORT_PRIVATE static void setPageCount(unsigned);
155
156 void setShouldLogMemoryMemoryPressureEvents(bool shouldLog) { m_shouldLogMemoryMemoryPressureEvents = shouldLog; }
157
158private:
159 size_t thresholdForMemoryKill();
160 void memoryPressureStatusChanged();
161
162 void uninstall();
163
164 void holdOff(Seconds);
165
166 MemoryPressureHandler();
167 ~MemoryPressureHandler() = delete;
168
169 void respondToMemoryPressure(Critical, Synchronous = Synchronous::No);
170 void platformReleaseMemory(Critical);
171 void platformInitialize();
172
173 void measurementTimerFired();
174 void shrinkOrDie();
175 void setMemoryUsagePolicyBasedOnFootprint(size_t);
176 void doesExceedInactiveLimitWhileActive();
177 void doesNotExceedInactiveLimitWhileActive();
178
179 WebsamProcessState m_processState { WebsamProcessState::Inactive };
180
181 unsigned m_pageCount { 0 };
182
183 LowMemoryHandler m_lowMemoryHandler;
184
185 std::atomic<bool> m_underMemoryPressure { false };
186 bool m_installed { false };
187 bool m_isSimulatingMemoryPressure { false };
188 bool m_shouldLogMemoryMemoryPressureEvents { true };
189 bool m_hasInvokedDidExceedInactiveLimitWhileActiveCallback { false };
190
191 std::unique_ptr<RunLoop::Timer<MemoryPressureHandler>> m_measurementTimer;
192 MemoryUsagePolicy m_memoryUsagePolicy { MemoryUsagePolicy::Unrestricted };
193 WTF::Function<void()> m_memoryKillCallback;
194 WTF::Function<void(bool)> m_memoryPressureStatusChangedCallback;
195 WTF::Function<void()> m_didExceedInactiveLimitWhileActiveCallback;
196
197#if OS(WINDOWS)
198 void windowsMeasurementTimerFired();
199 RunLoop::Timer<MemoryPressureHandler> m_windowsMeasurementTimer;
200 Win32Handle m_lowMemoryHandle;
201#endif
202
203#if OS(LINUX)
204 RunLoop::Timer<MemoryPressureHandler> m_holdOffTimer;
205 void holdOffTimerFired();
206#endif
207
208#if PLATFORM(COCOA)
209 dispatch_queue_t m_dispatchQueue { nullptr };
210#endif
211};
212
213extern WTFLogChannel LogMemoryPressure;
214
215} // namespace WTF
216
217using WTF::Critical;
218using WTF::MemoryPressureHandler;
219using WTF::Synchronous;
220using WTF::WebsamProcessState;
221