Let the UI process do memory kills and replace crashes with diagnostic logging.
authorakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Mar 2017 22:21:31 +0000 (22:21 +0000)
committerakling@apple.com <akling@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Mar 2017 22:21:31 +0000 (22:21 +0000)
<https://webkit.org/b/170016>
<rdar://problem/31091292>

Reviewed by Chris Dumez.

Source/WebCore:

Remove the memory kill code from WebCore that just crashes in favor of controlled
teardown from UI process side in WebKit2.

* page/DiagnosticLoggingKeys.cpp:
(WebCore::DiagnosticLoggingKeys::simulatedProcessCrashKey):
(WebCore::DiagnosticLoggingKeys::exceededActiveMemoryLimitKey):
(WebCore::DiagnosticLoggingKeys::exceededInactiveMemoryLimitKey):
(WebCore::DiagnosticLoggingKeys::exceededBackgroundCPULimitKey):
* page/DiagnosticLoggingKeys.h:
* page/MemoryRelease.cpp:
(WebCore::didExceedMemoryLimitAndFailedToRecover): Deleted.
* page/MemoryRelease.h:

Source/WebKit2:

Have the WebProcess memory kill callback send a notification to the UI process
instead of outright crashing. The UI process then sends a diagnostic logging message
before carefully taking down the web process.

Also add drive-by diagnostic logging for background CPU limit kills.

* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::simulateProcessCrash):
(WebKit::WebProcessProxy::didExceedActiveMemoryLimit):
(WebKit::WebProcessProxy::didExceedInactiveMemoryLimit):
(WebKit::WebProcessProxy::didExceedBackgroundCPULimit):
* UIProcess/WebProcessProxy.h:
* UIProcess/WebProcessProxy.messages.in:
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::initializeWebProcess):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@214320 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/page/DiagnosticLoggingKeys.cpp
Source/WebCore/page/DiagnosticLoggingKeys.h
Source/WebCore/page/MemoryRelease.cpp
Source/WebCore/page/MemoryRelease.h
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/WebProcessProxy.cpp
Source/WebKit2/UIProcess/WebProcessProxy.h
Source/WebKit2/UIProcess/WebProcessProxy.messages.in
Source/WebKit2/WebProcess/WebProcess.cpp

index be4409a..7c6e58a 100644 (file)
@@ -1,3 +1,24 @@
+2017-03-23  Andreas Kling  <akling@apple.com>
+
+        Let the UI process do memory kills and replace crashes with diagnostic logging.
+        <https://webkit.org/b/170016>
+        <rdar://problem/31091292>
+
+        Reviewed by Chris Dumez.
+
+        Remove the memory kill code from WebCore that just crashes in favor of controlled
+        teardown from UI process side in WebKit2.
+
+        * page/DiagnosticLoggingKeys.cpp:
+        (WebCore::DiagnosticLoggingKeys::simulatedProcessCrashKey):
+        (WebCore::DiagnosticLoggingKeys::exceededActiveMemoryLimitKey):
+        (WebCore::DiagnosticLoggingKeys::exceededInactiveMemoryLimitKey):
+        (WebCore::DiagnosticLoggingKeys::exceededBackgroundCPULimitKey):
+        * page/DiagnosticLoggingKeys.h:
+        * page/MemoryRelease.cpp:
+        (WebCore::didExceedMemoryLimitAndFailedToRecover): Deleted.
+        * page/MemoryRelease.h:
+
 2017-03-23  Youenn Fablet  <youenn@apple.com>
 
         Clean RTCPeerConnection.idl after bug 169978
index 75cae60..65b544a 100644 (file)
@@ -353,6 +353,26 @@ String DiagnosticLoggingKeys::domainCausingJetsamKey()
     return ASCIILiteral("DomainCausingJetsam");
 }
 
+String DiagnosticLoggingKeys::simulatedPageCrashKey()
+{
+    return ASCIILiteral("SimulatedPageCrash");
+}
+
+String DiagnosticLoggingKeys::exceededActiveMemoryLimitKey()
+{
+    return ASCIILiteral("ExceededActiveMemoryLimit");
+}
+
+String DiagnosticLoggingKeys::exceededInactiveMemoryLimitKey()
+{
+    return ASCIILiteral("ExceededInactiveMemoryLimit");
+}
+
+String DiagnosticLoggingKeys::exceededBackgroundCPULimitKey()
+{
+    return ASCIILiteral("ExceededBackgroundCPULimit");
+}
+
 String DiagnosticLoggingKeys::domainVisitedKey()
 {
     return ASCIILiteral("DomainVisited");
index 648243e..8130bd8 100644 (file)
@@ -52,6 +52,10 @@ public:
     static String documentLoaderStoppingKey();
     static String domainCausingEnergyDrainKey();
     WEBCORE_EXPORT static String domainCausingJetsamKey();
+    WEBCORE_EXPORT static String simulatedPageCrashKey();
+    WEBCORE_EXPORT static String exceededActiveMemoryLimitKey();
+    WEBCORE_EXPORT static String exceededInactiveMemoryLimitKey();
+    WEBCORE_EXPORT static String exceededBackgroundCPULimitKey();
     static String domainVisitedKey();
     static String engineFailedToLoadKey();
     WEBCORE_EXPORT static String entryRightlyNotWarmedUpKey();
index 5b164f9..060c483 100644 (file)
@@ -186,13 +186,6 @@ void logMemoryStatisticsAtTimeOfDeath()
 #endif
 }
 
-void didExceedMemoryLimitAndFailedToRecover()
-{
-    RELEASE_LOG(MemoryPressure, "Crashing non-visible process due to excessive memory usage + inability to free up memory below panic threshold.");
-    logMemoryStatisticsAtTimeOfDeath();
-    CRASH();
-}
-
 #if !PLATFORM(COCOA)
 void platformReleaseMemory(Critical) { }
 void jettisonExpensiveObjectsOnTopLevelNavigation() { }
index 61f30d2..a372a5d 100644 (file)
@@ -34,6 +34,5 @@ void platformReleaseMemory(Critical);
 void jettisonExpensiveObjectsOnTopLevelNavigation();
 WEBCORE_EXPORT void registerMemoryReleaseNotifyCallbacks();
 WEBCORE_EXPORT void logMemoryStatisticsAtTimeOfDeath();
-WEBCORE_EXPORT NO_RETURN_DUE_TO_CRASH void didExceedMemoryLimitAndFailedToRecover();
 
 } // namespace WebCore
index 29b7067..e2ecf53 100644 (file)
@@ -1,3 +1,27 @@
+2017-03-23  Andreas Kling  <akling@apple.com>
+
+        Let the UI process do memory kills and replace crashes with diagnostic logging.
+        <https://webkit.org/b/170016>
+        <rdar://problem/31091292>
+
+        Reviewed by Chris Dumez.
+
+        Have the WebProcess memory kill callback send a notification to the UI process
+        instead of outright crashing. The UI process then sends a diagnostic logging message
+        before carefully taking down the web process.
+
+        Also add drive-by diagnostic logging for background CPU limit kills.
+
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::simulateProcessCrash):
+        (WebKit::WebProcessProxy::didExceedActiveMemoryLimit):
+        (WebKit::WebProcessProxy::didExceedInactiveMemoryLimit):
+        (WebKit::WebProcessProxy::didExceedBackgroundCPULimit):
+        * UIProcess/WebProcessProxy.h:
+        * UIProcess/WebProcessProxy.messages.in:
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::initializeWebProcess):
+
 2017-03-23  Tim Horton  <timothy_horton@apple.com>
 
         Test DataDetectors supported schemes in lowercase
index f5eb0d5..ec94159 100644 (file)
@@ -50,6 +50,7 @@
 #include "WebProcessProxyMessages.h"
 #include "WebUserContentControllerProxy.h"
 #include "WebsiteData.h"
+#include <WebCore/DiagnosticLoggingKeys.h>
 #include <WebCore/SuddenTermination.h>
 #include <WebCore/URL.h>
 #include <stdio.h>
@@ -1127,6 +1128,39 @@ static Vector<RefPtr<WebPageProxy>> pagesCopy(WTF::IteratorRange<WebProcessProxy
     return vector;
 }
 
+static String diagnosticLoggingKeyForSimulatedCrashReason(SimulatedCrashReason reason)
+{
+    switch (reason) {
+    case SimulatedCrashReason::ExceededActiveMemoryLimit:
+        return DiagnosticLoggingKeys::exceededActiveMemoryLimitKey();
+    case SimulatedCrashReason::ExceededInactiveMemoryLimit:
+        return DiagnosticLoggingKeys::exceededInactiveMemoryLimitKey();
+    case SimulatedCrashReason::ExceededBackgroundCPULimit:
+        return DiagnosticLoggingKeys::exceededBackgroundCPULimitKey();
+    }
+}
+
+void WebProcessProxy::simulateProcessCrash(SimulatedCrashReason reason)
+{
+    for (auto& page : pagesCopy(pages())) {
+        page->logDiagnosticMessage(DiagnosticLoggingKeys::simulatedPageCrashKey(), diagnosticLoggingKeyForSimulatedCrashReason(reason), ShouldSample::No);
+        page->terminateProcess();
+        page->processDidCrash();
+    }
+}
+
+void WebProcessProxy::didExceedActiveMemoryLimit()
+{
+    RELEASE_LOG(PerformanceLogging, "%p - WebProcessProxy::didExceedActiveMemoryLimit() Terminating WebProcess that has exceeded the active memory limit", this);
+    simulateProcessCrash(SimulatedCrashReason::ExceededActiveMemoryLimit);
+}
+
+void WebProcessProxy::didExceedInactiveMemoryLimit()
+{
+    RELEASE_LOG(PerformanceLogging, "%p - WebProcessProxy::didExceedInactiveMemoryLimit() Terminating WebProcess that has exceeded the inactive memory limit", this);
+    simulateProcessCrash(SimulatedCrashReason::ExceededInactiveMemoryLimit);
+}
+
 void WebProcessProxy::didExceedBackgroundCPULimit()
 {
     for (auto& page : pages()) {
@@ -1140,11 +1174,7 @@ void WebProcessProxy::didExceedBackgroundCPULimit()
     }
 
     RELEASE_LOG(PerformanceLogging, "%p - WebProcessProxy::didExceedBackgroundCPULimit() Terminating background WebProcess that has exceeded the background CPU limit", this);
-
-    for (auto& page : pagesCopy(pages())) {
-        page->terminateProcess();
-        page->processDidCrash();
-    }
+    simulateProcessCrash(SimulatedCrashReason::ExceededBackgroundCPULimit);
 }
 
 void WebProcessProxy::updateBackgroundResponsivenessTimer()
index b328815..4a60e84 100644 (file)
@@ -55,6 +55,12 @@ struct PluginInfo;
 
 namespace WebKit {
 
+enum class SimulatedCrashReason {
+    ExceededActiveMemoryLimit,
+    ExceededInactiveMemoryLimit,
+    ExceededBackgroundCPULimit,
+};
+
 class NetworkProcessProxy;
 class UserMediaCaptureManagerProxy;
 class WebBackForwardListItem;
@@ -165,7 +171,10 @@ public:
     bool isUnderMemoryPressure() const { return m_isUnderMemoryPressure; }
 
     void processTerminated();
+
     void didExceedBackgroundCPULimit();
+    void didExceedActiveMemoryLimit();
+    void didExceedInactiveMemoryLimit();
 
 private:
     explicit WebProcessProxy(WebProcessPool&, WebsiteDataStore*);
@@ -238,6 +247,8 @@ private:
 
     bool canTerminateChildProcess();
 
+    void simulateProcessCrash(SimulatedCrashReason);
+
     ResponsivenessTimer m_responsivenessTimer;
     BackgroundProcessResponsivenessTimer m_backgroundResponsivenessTimer;
     
index 6b21f99..3d0dbf0 100644 (file)
@@ -45,6 +45,8 @@ messages -> WebProcessProxy LegacyReceiver {
 
     SetIsHoldingLockedFiles(bool isHoldingLockedFiles)
 
+    DidExceedActiveMemoryLimit()
+    DidExceedInactiveMemoryLimit()
     DidExceedBackgroundCPULimit()
 
     RetainIconForPageURL(String pageURL)
index b1c180e..570d6aa 100644 (file)
@@ -267,8 +267,12 @@ void WebProcess::initializeWebProcess(WebProcessCreationParameters&& parameters)
         });
 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
         memoryPressureHandler.setShouldUsePeriodicMemoryMonitor(true);
-        memoryPressureHandler.setMemoryKillCallback([] () {
-            WebCore::didExceedMemoryLimitAndFailedToRecover();
+        memoryPressureHandler.setMemoryKillCallback([this] () {
+            WebCore::logMemoryStatisticsAtTimeOfDeath();
+            if (MemoryPressureHandler::singleton().processState() == WebsamProcessState::Active)
+                parentProcessConnection()->send(Messages::WebProcessProxy::DidExceedActiveMemoryLimit(), 0);
+            else
+                parentProcessConnection()->send(Messages::WebProcessProxy::DidExceedInactiveMemoryLimit(), 0);
         });
 #endif
         memoryPressureHandler.setMemoryPressureStatusChangedCallback([this](bool isUnderMemoryPressure) {