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