Improve use of NeverDestroyed
[WebKit-https.git] / Source / WTF / wtf / MemoryPressureHandler.h
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
45 namespace WTF {
46
47 enum 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
53 enum class WebsamProcessState {
54     Active,
55     Inactive,
56 };
57
58 enum class Critical { No, Yes };
59 enum class Synchronous { No, Yes };
60
61 typedef WTF::Function<void(Critical, Synchronous)> LowMemoryHandler;
62
63 class MemoryPressureHandler {
64     friend class WTF::NeverDestroyed<MemoryPressureHandler>;
65 public:
66     WTF_EXPORT_PRIVATE static MemoryPressureHandler& singleton();
67
68     WTF_EXPORT_PRIVATE void install();
69
70     WTF_EXPORT_PRIVATE void setShouldUsePeriodicMemoryMonitor(bool);
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 #if OS(LINUX)
92     void setMemoryPressureMonitorHandle(int fd);
93 #endif
94
95     class ReliefLogger {
96     public:
97         explicit ReliefLogger(const char *log)
98             : m_logString(log)
99             , m_initialMemory(loggingEnabled() ? platformMemoryUsage() : MemoryUsage { })
100         {
101         }
102
103         ~ReliefLogger()
104         {
105             if (loggingEnabled())
106                 logMemoryUsageChange();
107         }
108
109
110         const char* logString() const { return m_logString; }
111         static void setLoggingEnabled(bool enabled) { s_loggingEnabled = enabled; }
112         static bool loggingEnabled()
113         {
114 #if RELEASE_LOG_DISABLED
115             return s_loggingEnabled;
116 #else
117             return true;
118 #endif
119         }
120
121     private:
122         struct MemoryUsage {
123             MemoryUsage() = default;
124             MemoryUsage(size_t resident, size_t physical)
125                 : resident(resident)
126                 , physical(physical)
127             {
128             }
129             size_t resident { 0 };
130             size_t physical { 0 };
131         };
132         std::optional<MemoryUsage> platformMemoryUsage();
133         void logMemoryUsageChange();
134
135         const char* m_logString;
136         std::optional<MemoryUsage> m_initialMemory;
137
138         WTF_EXPORT_PRIVATE static bool s_loggingEnabled;
139     };
140
141     WTF_EXPORT_PRIVATE void releaseMemory(Critical, Synchronous = Synchronous::No);
142
143     WTF_EXPORT_PRIVATE void beginSimulatedMemoryPressure();
144     WTF_EXPORT_PRIVATE void endSimulatedMemoryPressure();
145
146     WTF_EXPORT_PRIVATE void setProcessState(WebsamProcessState);
147     WebsamProcessState processState() const { return m_processState; }
148
149     WTF_EXPORT_PRIVATE static void setPageCount(unsigned);
150
151 private:
152     size_t thresholdForMemoryKill();
153     void memoryPressureStatusChanged();
154
155     void uninstall();
156
157     void holdOff(unsigned);
158
159     MemoryPressureHandler();
160     ~MemoryPressureHandler() = delete;
161
162     void respondToMemoryPressure(Critical, Synchronous = Synchronous::No);
163     void platformReleaseMemory(Critical);
164     void platformInitialize();
165
166     void measurementTimerFired();
167     void shrinkOrDie();
168     void setMemoryUsagePolicyBasedOnFootprint(size_t);
169     void doesExceedInactiveLimitWhileActive();
170     void doesNotExceedInactiveLimitWhileActive();
171
172 #if OS(LINUX)
173     class EventFDPoller {
174         WTF_MAKE_NONCOPYABLE(EventFDPoller); WTF_MAKE_FAST_ALLOCATED;
175     public:
176         EventFDPoller(int fd, WTF::Function<void ()>&& notifyHandler);
177         ~EventFDPoller();
178
179     private:
180         void readAndNotify() const;
181
182         std::optional<int> m_fd;
183         WTF::Function<void ()> m_notifyHandler;
184 #if USE(GLIB)
185         GRefPtr<GSource> m_source;
186 #else
187         RefPtr<Thread> m_thread;
188 #endif
189     };
190 #endif
191
192     WebsamProcessState m_processState { WebsamProcessState::Inactive };
193
194     unsigned m_pageCount { 0 };
195
196     bool m_installed { false };
197     LowMemoryHandler m_lowMemoryHandler;
198
199     std::atomic<bool> m_underMemoryPressure;
200     bool m_isSimulatingMemoryPressure { false };
201
202     std::unique_ptr<RunLoop::Timer<MemoryPressureHandler>> m_measurementTimer;
203     MemoryUsagePolicy m_memoryUsagePolicy { MemoryUsagePolicy::Unrestricted };
204     WTF::Function<void()> m_memoryKillCallback;
205     WTF::Function<void(bool)> m_memoryPressureStatusChangedCallback;
206     WTF::Function<void()> m_didExceedInactiveLimitWhileActiveCallback;
207     bool m_hasInvokedDidExceedInactiveLimitWhileActiveCallback { false };
208
209 #if OS(WINDOWS)
210     void windowsMeasurementTimerFired();
211     RunLoop::Timer<MemoryPressureHandler> m_windowsMeasurementTimer;
212     Win32Handle m_lowMemoryHandle;
213 #endif
214
215 #if OS(LINUX)
216     std::optional<int> m_eventFD;
217     std::optional<int> m_pressureLevelFD;
218     std::unique_ptr<EventFDPoller> m_eventFDPoller;
219     RunLoop::Timer<MemoryPressureHandler> m_holdOffTimer;
220     void holdOffTimerFired();
221     void logErrorAndCloseFDs(const char* error);
222     bool tryEnsureEventFD();
223 #endif
224 };
225
226 extern WTFLogChannel LogMemoryPressure;
227
228 } // namespace WTF
229
230 using WTF::Critical;
231 using WTF::MemoryPressureHandler;
232 using WTF::Synchronous;
233 using WTF::WebsamProcessState;