| /* |
| * Copyright (C) 2011-2017 Apple Inc. All rights reserved. |
| * Copyright (C) 2014 Raspberry Pi Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #include <atomic> |
| #include <ctime> |
| #include <wtf/CanMakeWeakPtr.h> |
| #include <wtf/FastMalloc.h> |
| #include <wtf/Forward.h> |
| #include <wtf/Function.h> |
| #include <wtf/RunLoop.h> |
| |
| #if OS(WINDOWS) |
| #include <wtf/win/Win32Handle.h> |
| #endif |
| |
| #if PLATFORM(COCOA) |
| #include <wtf/darwin/DispatchOSObject.h> |
| #endif |
| |
| namespace WTF { |
| |
| enum class SystemMemoryPressureStatus : uint8_t { |
| Normal, |
| Warning, |
| Critical, |
| }; |
| |
| enum class ProcessMemoryLimit : uint8_t { |
| Warning, |
| Critical, |
| }; |
| |
| enum class MemoryUsagePolicy : uint8_t { |
| Unrestricted, // Allocate as much as you want |
| Conservative, // Maybe you don't cache every single thing |
| Strict, // Time to start pinching pennies for real |
| }; |
| |
| enum class WebsamProcessState : uint8_t { |
| Active, |
| Inactive, |
| }; |
| |
| enum class Critical : bool { No, Yes }; |
| enum class Synchronous : bool { No, Yes }; |
| |
| typedef WTF::Function<void(Critical, Synchronous)> LowMemoryHandler; |
| |
| struct MemoryPressureHandlerConfiguration { |
| WTF_DEPRECATED_MAKE_STRUCT_FAST_ALLOCATED(MemoryPressureHandlerConfiguration); |
| WTF_EXPORT_PRIVATE MemoryPressureHandlerConfiguration(); |
| WTF_EXPORT_PRIVATE MemoryPressureHandlerConfiguration(uint64_t, double, double, std::optional<double>, Seconds); |
| |
| uint64_t baseThreshold; |
| double conservativeThresholdFraction; |
| double strictThresholdFraction; |
| std::optional<double> killThresholdFraction; |
| Seconds pollInterval; |
| }; |
| |
| class MemoryPressureHandler : public CanMakeWeakPtr<MemoryPressureHandler> { |
| WTF_DEPRECATED_MAKE_FAST_ALLOCATED(MemoryPressureHandler); |
| friend class WTF::NeverDestroyed<MemoryPressureHandler>; |
| public: |
| WTF_EXPORT_PRIVATE static MemoryPressureHandler& singleton(); |
| |
| // Do nothing since this is a singleton. |
| void ref() const { } |
| void deref() const { } |
| |
| WTF_EXPORT_PRIVATE void install(); |
| |
| WTF_EXPORT_PRIVATE void NODELETE setMemoryFootprintPollIntervalForTesting(Seconds); |
| WTF_EXPORT_PRIVATE void setShouldUsePeriodicMemoryMonitor(bool); |
| |
| #if OS(LINUX) || OS(FREEBSD) || OS(HAIKU) || OS(QNX) |
| WTF_EXPORT_PRIVATE void triggerMemoryPressureEvent(bool isCritical); |
| #endif |
| |
| void setMemoryKillCallback(WTF::Function<void()>&& function) { m_memoryKillCallback = WTF::move(function); } |
| void setMemoryPressureStatusChangedCallback(WTF::Function<void()>&& function) { m_memoryPressureStatusChangedCallback = WTF::move(function); } |
| void setDidExceedProcessMemoryLimitCallback(WTF::Function<void(ProcessMemoryLimit)>&& function) { m_didExceedProcessMemoryLimitCallback = WTF::move(function); } |
| |
| void setLowMemoryHandler(LowMemoryHandler&& handler) |
| { |
| m_lowMemoryHandler = WTF::move(handler); |
| } |
| |
| bool isUnderMemoryWarning() const |
| { |
| return m_memoryPressureStatus == SystemMemoryPressureStatus::Warning |
| #if PLATFORM(MAC) |
| || m_memoryUsagePolicy == MemoryUsagePolicy::Conservative |
| #endif |
| || m_isSimulatingMemoryWarning; |
| } |
| |
| bool isUnderMemoryPressure() const |
| { |
| return m_memoryPressureStatus == SystemMemoryPressureStatus::Critical |
| #if PLATFORM(MAC) |
| || m_memoryUsagePolicy >= MemoryUsagePolicy::Strict |
| #endif |
| || m_isSimulatingMemoryPressure; |
| } |
| |
| bool isSimulatingMemoryWarning() const { return m_isSimulatingMemoryWarning; } |
| bool isSimulatingMemoryPressure() const { return m_isSimulatingMemoryPressure; } |
| |
| void setMemoryPressureStatus(SystemMemoryPressureStatus); |
| SystemMemoryPressureStatus memoryPressureStatus() const { return m_memoryPressureStatus; } |
| |
| WTF_EXPORT_PRIVATE MemoryUsagePolicy currentMemoryUsagePolicy(); |
| |
| #if PLATFORM(COCOA) |
| void setDispatchQueue(OSObjectPtr<dispatch_queue_t>&& queue) |
| { |
| RELEASE_ASSERT(!m_installed); |
| m_dispatchQueue = WTF::move(queue); |
| } |
| #endif |
| |
| class ReliefLogger { |
| WTF_DEPRECATED_MAKE_FAST_ALLOCATED(ReliefLogger); |
| public: |
| explicit ReliefLogger(const char *log) |
| : m_logString(log) |
| , m_initialMemory(loggingEnabled() ? platformMemoryUsage() : MemoryUsage { }) |
| { |
| } |
| |
| ~ReliefLogger(); |
| |
| const char* logString() const { return m_logString; } |
| static void setLoggingEnabled(bool enabled) { s_loggingEnabled = enabled; } |
| static bool loggingEnabled() |
| { |
| #if RELEASE_LOG_DISABLED |
| return s_loggingEnabled; |
| #else |
| return true; |
| #endif |
| } |
| |
| private: |
| struct MemoryUsage { |
| WTF_DEPRECATED_MAKE_STRUCT_FAST_ALLOCATED(MemoryUsage); |
| MemoryUsage() = default; |
| MemoryUsage(size_t resident, size_t physical) |
| : resident(resident) |
| , physical(physical) |
| { |
| } |
| size_t resident { 0 }; |
| size_t physical { 0 }; |
| }; |
| std::optional<MemoryUsage> platformMemoryUsage(); |
| void logMemoryUsageChange(); |
| |
| const char* m_logString; |
| std::optional<MemoryUsage> m_initialMemory; |
| |
| WTF_EXPORT_PRIVATE static bool s_loggingEnabled; |
| }; |
| |
| using Configuration = MemoryPressureHandlerConfiguration; |
| |
| void setConfiguration(Configuration&& configuration) { m_configuration = WTF::move(configuration); } |
| void setConfiguration(const Configuration& configuration) { m_configuration = configuration; } |
| |
| WTF_EXPORT_PRIVATE void releaseMemory(Critical, Synchronous = Synchronous::No); |
| |
| WTF_EXPORT_PRIVATE void beginSimulatedMemoryWarning(); |
| WTF_EXPORT_PRIVATE void endSimulatedMemoryWarning(); |
| WTF_EXPORT_PRIVATE void beginSimulatedMemoryPressure(); |
| WTF_EXPORT_PRIVATE void endSimulatedMemoryPressure(); |
| |
| WTF_EXPORT_PRIVATE void NODELETE setProcessState(WebsamProcessState); |
| WebsamProcessState processState() const { return m_processState; } |
| |
| WTF_EXPORT_PRIVATE static ASCIILiteral processStateDescription(); |
| |
| WTF_EXPORT_PRIVATE static void setPageCount(unsigned); |
| |
| void setShouldLogMemoryMemoryPressureEvents(bool shouldLog) { m_shouldLogMemoryMemoryPressureEvents = shouldLog; } |
| |
| // Runs the provided callback the first time that this process's footprint exceeds any of the given thresholds. |
| // Only works in processes that use PeriodicMemoryMonitor. |
| WTF_EXPORT_PRIVATE void setMemoryFootprintNotificationThresholds(Vector<uint64_t>&& thresholds, WTF::Function<void(uint64_t)>&&); |
| |
| private: |
| std::optional<size_t> thresholdForMemoryKill(); |
| size_t NODELETE thresholdForPolicy(MemoryUsagePolicy); |
| MemoryUsagePolicy NODELETE policyForFootprint(size_t); |
| |
| void memoryPressureStatusChanged(); |
| |
| void uninstall(); |
| |
| void holdOff(Seconds); |
| |
| MemoryPressureHandler(); |
| ~MemoryPressureHandler() = delete; |
| |
| void didExceedProcessMemoryLimit(ProcessMemoryLimit); |
| void respondToMemoryPressure(Critical, Synchronous = Synchronous::No); |
| void platformReleaseMemory(Critical); |
| void NODELETE platformInitialize(); |
| |
| void measurementTimerFired(); |
| void shrinkOrDie(size_t killThreshold); |
| void setMemoryUsagePolicyBasedOnFootprint(size_t); |
| |
| unsigned m_pageCount { 0 }; |
| |
| std::atomic<SystemMemoryPressureStatus> m_memoryPressureStatus { SystemMemoryPressureStatus::Normal }; |
| bool m_installed { false }; |
| bool m_isSimulatingMemoryWarning { false }; |
| bool m_isSimulatingMemoryPressure { false }; |
| bool m_shouldLogMemoryMemoryPressureEvents { true }; |
| |
| WebsamProcessState m_processState { WebsamProcessState::Inactive }; |
| |
| MemoryUsagePolicy m_memoryUsagePolicy { MemoryUsagePolicy::Unrestricted }; |
| |
| std::unique_ptr<RunLoop::Timer>m_measurementTimer; |
| WTF::Function<void()> m_memoryKillCallback; |
| WTF::Function<void()> m_memoryPressureStatusChangedCallback; |
| WTF::Function<void(ProcessMemoryLimit)> m_didExceedProcessMemoryLimitCallback; |
| LowMemoryHandler m_lowMemoryHandler; |
| Vector<uint64_t> m_memoryFootprintNotificationThresholds; |
| WTF::Function<void(uint64_t)> m_memoryFootprintNotificationHandler; |
| |
| Configuration m_configuration; |
| |
| #if OS(WINDOWS) |
| friend VOID CALLBACK lowMemoryNotificationCallback(PVOID, BOOLEAN); |
| void windowsMeasurementTimerFired(); |
| void windowsLowMemoryNotificationFired(); |
| void beginWaitingForLowMemoryNotification(); |
| RunLoop::Timer m_windowsMeasurementTimer; |
| Win32Handle m_lowMemoryHandle; |
| HANDLE m_lowMemoryWaitHandle { nullptr }; |
| #endif |
| |
| #if (OS(LINUX) || OS(FREEBSD) || OS(HAIKU) || OS(QNX)) && !OS(ANDROID) |
| RunLoop::Timer m_holdOffTimer; |
| void holdOffTimerFired(); |
| #endif |
| |
| #if PLATFORM(COCOA) |
| OSObjectPtr<dispatch_queue_t> m_dispatchQueue; |
| #endif |
| }; |
| |
| } // namespace WTF |
| |
| using WTF::Critical; |
| using WTF::MemoryPressureHandler; |
| using WTF::Synchronous; |
| using WTF::SystemMemoryPressureStatus; |
| using WTF::WebsamProcessState; |