Title: [276148] trunk
Revision
276148
Author
[email protected]
Date
2021-04-16 11:41:22 -0700 (Fri, 16 Apr 2021)

Log Message

Exit the GPUProcess when under memory pressure if it is not being used
https://bugs.webkit.org/show_bug.cgi?id=224556

Reviewed by Darin Adler.

Source/WebKit:

Exit the GPUProcess when under memory pressure if it is not being used. This will
help us save memory, especially until we are able to enable "DOM Rendering in
GPUProcess".

Note that when the GPUProcess is ready to exit, it sends an IPC to the UIProcess
in order to get terminated, instead of terminating itself. The reason I do this is
so that the UIProcess can distinguish a GPUProcess crash from a normal idle exit.

A/B testing shows:
- 5-8% PLUM3 progression on iPhone
- 2.5-4% PLUM3 progression on iPad
- No PLT5 regression on either iPhone or iPad.

* GPUProcess/GPUConnectionToWebProcess.cpp:
(WebKit::GPUConnectionToWebProcess::GPUConnectionToWebProcess):
(WebKit::GPUConnectionToWebProcess::allowsExitUnderMemoryPressure const):
(WebKit::GPUConnectionToWebProcess::releaseRenderingBackend):
(WebKit::GPUConnectionToWebProcess::releaseGraphicsContextGL):
* GPUProcess/GPUConnectionToWebProcess.h:
(WebKit::GPUConnectionToWebProcess::remoteMediaPlayerManagerProxy):
* GPUProcess/GPUProcess.cpp:
(WebKit::GPUProcess::removeGPUConnectionToWebProcess):
(WebKit::GPUProcess::canExitUnderMemoryPressure const):
(WebKit::GPUProcess::tryExitIfUnusedAndUnderMemoryPressure):
(WebKit::GPUProcess::tryExitIfUnused):
(WebKit::GPUProcess::lowMemoryHandler):
* GPUProcess/GPUProcess.h:
* GPUProcess/graphics/RemoteRenderingBackend.cpp:
(WebKit::RemoteRenderingBackend::allowsExitUnderMemoryPressure const):
* GPUProcess/graphics/RemoteRenderingBackend.h:
* GPUProcess/media/RemoteAudioDestinationManager.cpp:
(WebKit::RemoteAudioDestinationManager::deleteAudioDestination):
(WebKit::RemoteAudioDestinationManager::allowsExitUnderMemoryPressure const):
* GPUProcess/media/RemoteAudioDestinationManager.h:
* GPUProcess/media/RemoteCDMFactoryProxy.cpp:
(WebKit::RemoteCDMFactoryProxy::removeInstance):
(WebKit::RemoteCDMFactoryProxy::allowsExitUnderMemoryPressure const):
* GPUProcess/media/RemoteCDMFactoryProxy.h:
* GPUProcess/media/RemoteImageDecoderAVFProxy.cpp:
(WebKit::RemoteImageDecoderAVFProxy::deleteDecoder):
(WebKit::RemoteImageDecoderAVFProxy::allowsExitUnderMemoryPressure const):
* GPUProcess/media/RemoteImageDecoderAVFProxy.h:
* GPUProcess/media/RemoteLegacyCDMFactoryProxy.cpp:
(WebKit::RemoteLegacyCDMFactoryProxy::removeSession):
(WebKit::RemoteLegacyCDMFactoryProxy::allowsExitUnderMemoryPressure const):
* GPUProcess/media/RemoteLegacyCDMFactoryProxy.h:
* GPUProcess/media/RemoteMediaPlayerManagerProxy.cpp:
(WebKit::RemoteMediaPlayerManagerProxy::deleteMediaPlayer):
(WebKit::RemoteMediaPlayerManagerProxy::allowsExitUnderMemoryPressure const):
* GPUProcess/media/RemoteMediaPlayerManagerProxy.h:
* GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.cpp:
(WebKit::RemoteAudioMediaStreamTrackRendererManager::allowsExitUnderMemoryPressure const):
* GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.h:
* GPUProcess/webrtc/RemoteMediaRecorderManager.cpp:
(WebKit::RemoteMediaRecorderManager::releaseRecorder):
(WebKit::RemoteMediaRecorderManager::allowsExitUnderMemoryPressure const):
* GPUProcess/webrtc/RemoteMediaRecorderManager.h:
* GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.cpp:
(WebKit::RemoteSampleBufferDisplayLayerManager::allowsExitUnderMemoryPressure const):
* GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.h:
* Shared/ProcessTerminationReason.h:
* UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp:
(WebKit::UserMediaCaptureManagerProxy::hasSourceProxies const):
* UIProcess/Cocoa/UserMediaCaptureManagerProxy.h:
* UIProcess/GPU/GPUProcessProxy.cpp:
(WebKit::GPUProcessProxy::gpuProcessExited):
(WebKit::GPUProcessProxy::processIsReadyToExit):
(WebKit::GPUProcessProxy::didClose):
(WebKit::GPUProcessProxy::didFinishLaunching):
* UIProcess/GPU/GPUProcessProxy.h:
* UIProcess/GPU/GPUProcessProxy.messages.in:
* UIProcess/PageClient.h:
(WebKit::PageClient::gpuProcessDidExit):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::gpuProcessExited):
* UIProcess/WebPageProxy.h:
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::gpuProcessExited):
* UIProcess/WebProcessPool.h:
* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::gpuProcessExited):
* UIProcess/WebProcessProxy.h:
* UIProcess/ios/PageClientImplIOS.h:
* UIProcess/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::gpuProcessDidExit):
* UIProcess/ios/WKContentView.h:
* UIProcess/ios/WKContentView.mm:
(-[WKContentView _gpuProcessDidExit]):

Tools:

Add API test coverage.

* TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm:
(runMemoryPressureExitTest):
(TEST):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (276147 => 276148)


--- trunk/Source/WebKit/ChangeLog	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/ChangeLog	2021-04-16 18:41:22 UTC (rev 276148)
@@ -1,5 +1,101 @@
 2021-04-16  Chris Dumez  <[email protected]>
 
+        Exit the GPUProcess when under memory pressure if it is not being used
+        https://bugs.webkit.org/show_bug.cgi?id=224556
+
+        Reviewed by Darin Adler.
+
+        Exit the GPUProcess when under memory pressure if it is not being used. This will
+        help us save memory, especially until we are able to enable "DOM Rendering in
+        GPUProcess".
+
+        Note that when the GPUProcess is ready to exit, it sends an IPC to the UIProcess
+        in order to get terminated, instead of terminating itself. The reason I do this is
+        so that the UIProcess can distinguish a GPUProcess crash from a normal idle exit.
+
+        A/B testing shows:
+        - 5-8% PLUM3 progression on iPhone
+        - 2.5-4% PLUM3 progression on iPad
+        - No PLT5 regression on either iPhone or iPad.
+
+        * GPUProcess/GPUConnectionToWebProcess.cpp:
+        (WebKit::GPUConnectionToWebProcess::GPUConnectionToWebProcess):
+        (WebKit::GPUConnectionToWebProcess::allowsExitUnderMemoryPressure const):
+        (WebKit::GPUConnectionToWebProcess::releaseRenderingBackend):
+        (WebKit::GPUConnectionToWebProcess::releaseGraphicsContextGL):
+        * GPUProcess/GPUConnectionToWebProcess.h:
+        (WebKit::GPUConnectionToWebProcess::remoteMediaPlayerManagerProxy):
+        * GPUProcess/GPUProcess.cpp:
+        (WebKit::GPUProcess::removeGPUConnectionToWebProcess):
+        (WebKit::GPUProcess::canExitUnderMemoryPressure const):
+        (WebKit::GPUProcess::tryExitIfUnusedAndUnderMemoryPressure):
+        (WebKit::GPUProcess::tryExitIfUnused):
+        (WebKit::GPUProcess::lowMemoryHandler):
+        * GPUProcess/GPUProcess.h:
+        * GPUProcess/graphics/RemoteRenderingBackend.cpp:
+        (WebKit::RemoteRenderingBackend::allowsExitUnderMemoryPressure const):
+        * GPUProcess/graphics/RemoteRenderingBackend.h:
+        * GPUProcess/media/RemoteAudioDestinationManager.cpp:
+        (WebKit::RemoteAudioDestinationManager::deleteAudioDestination):
+        (WebKit::RemoteAudioDestinationManager::allowsExitUnderMemoryPressure const):
+        * GPUProcess/media/RemoteAudioDestinationManager.h:
+        * GPUProcess/media/RemoteCDMFactoryProxy.cpp:
+        (WebKit::RemoteCDMFactoryProxy::removeInstance):
+        (WebKit::RemoteCDMFactoryProxy::allowsExitUnderMemoryPressure const):
+        * GPUProcess/media/RemoteCDMFactoryProxy.h:
+        * GPUProcess/media/RemoteImageDecoderAVFProxy.cpp:
+        (WebKit::RemoteImageDecoderAVFProxy::deleteDecoder):
+        (WebKit::RemoteImageDecoderAVFProxy::allowsExitUnderMemoryPressure const):
+        * GPUProcess/media/RemoteImageDecoderAVFProxy.h:
+        * GPUProcess/media/RemoteLegacyCDMFactoryProxy.cpp:
+        (WebKit::RemoteLegacyCDMFactoryProxy::removeSession):
+        (WebKit::RemoteLegacyCDMFactoryProxy::allowsExitUnderMemoryPressure const):
+        * GPUProcess/media/RemoteLegacyCDMFactoryProxy.h:
+        * GPUProcess/media/RemoteMediaPlayerManagerProxy.cpp:
+        (WebKit::RemoteMediaPlayerManagerProxy::deleteMediaPlayer):
+        (WebKit::RemoteMediaPlayerManagerProxy::allowsExitUnderMemoryPressure const):
+        * GPUProcess/media/RemoteMediaPlayerManagerProxy.h:
+        * GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.cpp:
+        (WebKit::RemoteAudioMediaStreamTrackRendererManager::allowsExitUnderMemoryPressure const):
+        * GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.h:
+        * GPUProcess/webrtc/RemoteMediaRecorderManager.cpp:
+        (WebKit::RemoteMediaRecorderManager::releaseRecorder):
+        (WebKit::RemoteMediaRecorderManager::allowsExitUnderMemoryPressure const):
+        * GPUProcess/webrtc/RemoteMediaRecorderManager.h:
+        * GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.cpp:
+        (WebKit::RemoteSampleBufferDisplayLayerManager::allowsExitUnderMemoryPressure const):
+        * GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.h:
+        * Shared/ProcessTerminationReason.h:
+        * UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp:
+        (WebKit::UserMediaCaptureManagerProxy::hasSourceProxies const):
+        * UIProcess/Cocoa/UserMediaCaptureManagerProxy.h:
+        * UIProcess/GPU/GPUProcessProxy.cpp:
+        (WebKit::GPUProcessProxy::gpuProcessExited):
+        (WebKit::GPUProcessProxy::processIsReadyToExit):
+        (WebKit::GPUProcessProxy::didClose):
+        (WebKit::GPUProcessProxy::didFinishLaunching):
+        * UIProcess/GPU/GPUProcessProxy.h:
+        * UIProcess/GPU/GPUProcessProxy.messages.in:
+        * UIProcess/PageClient.h:
+        (WebKit::PageClient::gpuProcessDidExit):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::gpuProcessExited):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::gpuProcessExited):
+        * UIProcess/WebProcessPool.h:
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::gpuProcessExited):
+        * UIProcess/WebProcessProxy.h:
+        * UIProcess/ios/PageClientImplIOS.h:
+        * UIProcess/ios/PageClientImplIOS.mm:
+        (WebKit::PageClientImpl::gpuProcessDidExit):
+        * UIProcess/ios/WKContentView.h:
+        * UIProcess/ios/WKContentView.mm:
+        (-[WKContentView _gpuProcessDidExit]):
+
+2021-04-16  Chris Dumez  <[email protected]>
+
         Early IPC messages to a WorkQueueMessageReceiver may get processed out of order
         https://bugs.webkit.org/show_bug.cgi?id=224623
 

Modified: trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -189,7 +189,7 @@
 #if HAVE(TASK_IDENTITY_TOKEN)
     , m_webProcessIdentityToken(WTFMove(parameters.webProcessIdentityToken))
 #endif
-    , m_remoteMediaPlayerManagerProxy(makeUnique<RemoteMediaPlayerManagerProxy>(*this))
+    , m_remoteMediaPlayerManagerProxy(makeUniqueRef<RemoteMediaPlayerManagerProxy>(*this))
     , m_sessionID(sessionID)
 #if PLATFORM(COCOA) && USE(LIBWEBRTC)
     , m_libWebRTCCodecsProxy(LibWebRTCCodecsProxy::create(*this))
@@ -267,6 +267,49 @@
 }
 #endif
 
+bool GPUConnectionToWebProcess::allowsExitUnderMemoryPressure() const
+{
+    for (auto& remoteRenderingBackend : m_remoteRenderingBackendMap.values()) {
+        if (!remoteRenderingBackend->allowsExitUnderMemoryPressure())
+            return false;
+    }
+#if ENABLE(WEBGL)
+    if (!m_remoteGraphicsContextGLMap.isEmpty())
+        return false;
+#endif
+    if (!m_remoteMediaPlayerManagerProxy->allowsExitUnderMemoryPressure())
+        return false;
+#if ENABLE(WEB_AUDIO)
+    if (m_remoteAudioDestinationManager && !m_remoteAudioDestinationManager->allowsExitUnderMemoryPressure())
+        return false;
+#endif
+#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
+    if (m_userMediaCaptureManagerProxy && m_userMediaCaptureManagerProxy->hasSourceProxies())
+        return false;
+    if (!m_audioTrackRendererManager->allowsExitUnderMemoryPressure())
+        return false;
+    if (!m_sampleBufferDisplayLayerManager->allowsExitUnderMemoryPressure())
+        return false;
+#endif
+#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
+    if (m_remoteMediaRecorderManager && !m_remoteMediaRecorderManager->allowsExitUnderMemoryPressure())
+        return false;
+#endif
+#if HAVE(AVASSETREADER)
+    if (m_imageDecoderAVFProxy && !m_imageDecoderAVFProxy->allowsExitUnderMemoryPressure())
+        return false;
+#endif
+#if ENABLE(ENCRYPTED_MEDIA)
+    if (m_cdmFactoryProxy && !m_cdmFactoryProxy->allowsExitUnderMemoryPressure())
+        return false;
+#endif
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+    if (m_legacyCdmFactoryProxy && !m_legacyCdmFactoryProxy->allowsExitUnderMemoryPressure())
+        return false;
+#endif
+    return true;
+}
+
 Logger& GPUConnectionToWebProcess::logger()
 {
     if (!m_logger) {
@@ -319,8 +362,9 @@
 
     return *m_userMediaCaptureManagerProxy;
 }
+#endif
 
-#if HAVE(AVASSETWRITERDELEGATE)
+#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
 RemoteMediaRecorderManager& GPUConnectionToWebProcess::mediaRecorderManager()
 {
     if (!m_remoteMediaRecorderManager)
@@ -329,7 +373,6 @@
     return *m_remoteMediaRecorderManager;
 }
 #endif
-#endif //  PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
 
 #if ENABLE(ENCRYPTED_MEDIA)
 RemoteCDMFactoryProxy& GPUConnectionToWebProcess::cdmFactoryProxy()
@@ -374,6 +417,7 @@
 {
     bool found = m_remoteRenderingBackendMap.remove(renderingBackendIdentifier);
     ASSERT_UNUSED(found, found);
+    gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
 }
 
 #if ENABLE(WEBGL)
@@ -393,6 +437,8 @@
 void GPUConnectionToWebProcess::releaseGraphicsContextGL(GraphicsContextGLIdentifier graphicsContextGLIdentifier)
 {
     m_remoteGraphicsContextGLMap.remove(graphicsContextGLIdentifier);
+    if (m_remoteGraphicsContextGLMap.isEmpty())
+        gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
 }
 
 void GPUConnectionToWebProcess::releaseGraphicsContextGLForTesting(GraphicsContextGLIdentifier identifier)
@@ -537,7 +583,8 @@
         userMediaCaptureManagerProxy().didReceiveMessageFromGPUProcess(connection, decoder);
         return true;
     }
-#if HAVE(AVASSETWRITERDELEGATE)
+#endif
+#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
     if (decoder.messageReceiverName() == Messages::RemoteMediaRecorderManager::messageReceiverName()) {
         mediaRecorderManager().didReceiveMessageFromWebProcess(connection, decoder);
         return true;
@@ -546,8 +593,7 @@
         mediaRecorderManager().didReceiveRemoteMediaRecorderMessage(connection, decoder);
         return true;
     }
-#endif // HAVE(AVASSETWRITERDELEGATE)
-#endif // PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
+#endif
 #if ENABLE(ENCRYPTED_MEDIA)
     if (decoder.messageReceiverName() == Messages::RemoteCDMFactoryProxy::messageReceiverName()) {
         cdmFactoryProxy().didReceiveMessageFromWebProcess(connection, decoder);

Modified: trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -132,7 +132,7 @@
 #endif
 
     RemoteMediaEngineConfigurationFactoryProxy& mediaEngineConfigurationFactoryProxy();
-    RemoteMediaPlayerManagerProxy& remoteMediaPlayerManagerProxy() { return *m_remoteMediaPlayerManagerProxy; }
+    RemoteMediaPlayerManagerProxy& remoteMediaPlayerManagerProxy() { return m_remoteMediaPlayerManagerProxy.get(); }
 
 #if USE(AUDIO_SESSION)
     RemoteAudioSessionProxyManager& audioSessionManager();
@@ -144,6 +144,8 @@
 
     void updateSupportedRemoteCommands();
 
+    bool allowsExitUnderMemoryPressure() const;
+
     void terminateWebProcess();
 #if ENABLE(WEBGL)
     void releaseGraphicsContextGLForTesting(GraphicsContextGLIdentifier);
@@ -156,10 +158,10 @@
 #endif
 #if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
     UserMediaCaptureManagerProxy& userMediaCaptureManagerProxy();
-#if HAVE(AVASSETWRITERDELEGATE)
+#endif
+#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
     RemoteMediaRecorderManager& mediaRecorderManager();
 #endif
-#endif
 
     void createRenderingBackend(RemoteRenderingBackendCreationParameters&&);
     void releaseRenderingBackend(RenderingBackendIdentifier);
@@ -228,7 +230,7 @@
     std::unique_ptr<RemoteAudioDestinationManager> m_remoteAudioDestinationManager;
 #endif
     std::unique_ptr<RemoteMediaResourceManager> m_remoteMediaResourceManager;
-    std::unique_ptr<RemoteMediaPlayerManagerProxy> m_remoteMediaPlayerManagerProxy;
+    UniqueRef<RemoteMediaPlayerManagerProxy> m_remoteMediaPlayerManagerProxy;
     PAL::SessionID m_sessionID;
 #if PLATFORM(COCOA) && USE(LIBWEBRTC)
     Ref<LibWebRTCCodecsProxy> m_libWebRTCCodecsProxy;
@@ -237,10 +239,10 @@
     std::unique_ptr<UserMediaCaptureManagerProxy> m_userMediaCaptureManagerProxy;
     Ref<RemoteAudioMediaStreamTrackRendererManager> m_audioTrackRendererManager;
     Ref<RemoteSampleBufferDisplayLayerManager> m_sampleBufferDisplayLayerManager;
-#if HAVE(AVASSETWRITERDELEGATE)
+#endif
+#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
     std::unique_ptr<RemoteMediaRecorderManager> m_remoteMediaRecorderManager;
 #endif
-#endif
 #if ENABLE(MEDIA_STREAM)
     bool m_allowsAudioCapture { false };
     bool m_allowsVideoCapture { false };

Modified: trunk/Source/WebKit/GPUProcess/GPUProcess.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/GPUProcess.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/GPUProcess.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -111,6 +111,7 @@
 {
     ASSERT(m_webProcessConnections.contains(connection.webProcessIdentifier()));
     m_webProcessConnections.remove(connection.webProcessIdentifier());
+    tryExitIfUnusedAndUnderMemoryPressure();
 }
 
 void GPUProcess::connectionToWebProcessClosed(IPC::Connection& connection)
@@ -122,8 +123,40 @@
     return m_webProcessConnections.isEmpty();
 }
 
+bool GPUProcess::canExitUnderMemoryPressure() const
+{
+    ASSERT(isMainRunLoop());
+    for (auto& webProcessConnection : m_webProcessConnections.values()) {
+        if (!webProcessConnection->allowsExitUnderMemoryPressure())
+            return false;
+    }
+    return true;
+}
+
+void GPUProcess::tryExitIfUnusedAndUnderMemoryPressure()
+{
+    ASSERT(isMainRunLoop());
+    if (!MemoryPressureHandler::singleton().isUnderMemoryPressure())
+        return;
+
+    tryExitIfUnused();
+}
+
+void GPUProcess::tryExitIfUnused()
+{
+    ASSERT(isMainRunLoop());
+    if (!canExitUnderMemoryPressure())
+        return;
+
+    RELEASE_LOG(Process, "GPUProcess::tryExitIfUnused: GPUProcess is exiting because we are under memory pressure and the process is no longer useful.");
+    parentProcessConnection()->send(Messages::GPUProcessProxy::ProcessIsReadyToExit(), 0);
+}
+
 void GPUProcess::lowMemoryHandler(Critical critical, Synchronous synchronous)
 {
+    RELEASE_LOG(Process, "GPUProcess::lowMemoryHandler: critical=%d, synchronous=%d", critical == Critical::Yes, synchronous == Synchronous::Yes);
+    tryExitIfUnused();
+
     WebCore::releaseGraphicsMemory(critical, synchronous);
 }
 

Modified: trunk/Source/WebKit/GPUProcess/GPUProcess.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/GPUProcess.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/GPUProcess.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -92,6 +92,8 @@
     void enableVP9Decoders(bool shouldEnableVP8Decoder, bool shouldEnableVP9Decoder, bool shouldEnableVP9SWDecoder);
 #endif
 
+    void tryExitIfUnusedAndUnderMemoryPressure();
+
 private:
     void lowMemoryHandler(Critical, Synchronous);
 
@@ -101,6 +103,9 @@
     void initializeSandbox(const AuxiliaryProcessInitializationParameters&, SandboxInitializationParameters&) override;
     bool shouldTerminate() override;
 
+    void tryExitIfUnused();
+    bool canExitUnderMemoryPressure() const;
+
     // IPC::Connection::Client
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
 

Modified: trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -597,6 +597,11 @@
         m_renderingResourcesRequest = { };
 }
 
+bool RemoteRenderingBackend::allowsExitUnderMemoryPressure() const
+{
+    return m_remoteResourceCache.imageBuffers().isEmpty() && m_remoteResourceCache.nativeImages().isEmpty();
+}
+
 } // namespace WebKit
 
 #endif // ENABLE(GPU_PROCESS)

Modified: trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -83,6 +83,8 @@
 
     void populateGetImageDataSharedMemory(WebCore::ImageData*);
 
+    bool allowsExitUnderMemoryPressure() const;
+
     // Runs Function in RemoteRenderingBackend task queue.
     void dispatch(Function<void()>&&);
 

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -29,6 +29,7 @@
 #if ENABLE(GPU_PROCESS) && ENABLE(WEB_AUDIO)
 
 #include "GPUConnectionToWebProcess.h"
+#include "GPUProcess.h"
 #include <WebCore/AudioUtilities.h>
 #include <wtf/ThreadSafeRefCounted.h>
 
@@ -173,6 +174,9 @@
     if (destination)
         destination->scheduleGracefulShutdownIfNeeded();
     completionHandler();
+
+    if (allowsExitUnderMemoryPressure())
+        m_gpuConnectionToWebProcess.gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
 }
 
 void RemoteAudioDestinationManager::startAudioDestination(RemoteAudioDestinationIdentifier identifier, CompletionHandler<void(bool)>&& completionHandler)
@@ -203,6 +207,11 @@
 }
 #endif
 
+bool RemoteAudioDestinationManager::allowsExitUnderMemoryPressure() const
+{
+    return m_audioDestinations.isEmpty();
+}
+
 } // namespace WebKit
 
 #endif // ENABLE(GPU_PROCESS) && ENABLE(WEB_AUDIO)

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -56,6 +56,8 @@
     bool didReceiveSyncMessageFromWebProcess(IPC::Connection& connection, IPC::Decoder& decoder, UniqueRef<IPC::Encoder>& encoder) { return didReceiveSyncMessage(connection, decoder, encoder); }
     void didReceiveMessageFromWebProcess(IPC::Connection& connection, IPC::Decoder& decoder) { didReceiveMessage(connection, decoder); }
 
+    bool allowsExitUnderMemoryPressure() const;
+
 private:
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&);
     bool didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, UniqueRef<IPC::Encoder>&);

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteCDMFactoryProxy.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/media/RemoteCDMFactoryProxy.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteCDMFactoryProxy.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -28,6 +28,7 @@
 
 #if ENABLE(GPU_PROCESS) && ENABLE(ENCRYPTED_MEDIA)
 
+#include "GPUProcess.h"
 #include "RemoteCDMConfiguration.h"
 #include "RemoteCDMInstanceProxy.h"
 #include "RemoteCDMInstanceSessionProxy.h"
@@ -142,6 +143,8 @@
 {
     ASSERT(m_instances.contains(identifier));
     m_instances.remove(identifier);
+    if (m_gpuConnectionToWebProcess && allowsExitUnderMemoryPressure())
+        m_gpuConnectionToWebProcess->gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
 }
 
 RemoteCDMInstanceProxy* RemoteCDMFactoryProxy::getInstance(const RemoteCDMInstanceIdentifier& identifier)
@@ -161,6 +164,11 @@
     m_sessions.remove(identifier);
 }
 
+bool RemoteCDMFactoryProxy::allowsExitUnderMemoryPressure() const
+{
+    return m_instances.isEmpty();
 }
 
+}
+
 #endif

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteCDMFactoryProxy.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/media/RemoteCDMFactoryProxy.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteCDMFactoryProxy.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -70,6 +70,8 @@
 
     GPUConnectionToWebProcess* gpuConnectionToWebProcess() { return m_gpuConnectionToWebProcess.get(); }
 
+    bool allowsExitUnderMemoryPressure() const;
+
 private:
     friend class GPUProcessConnection;
     // IPC::MessageReceiver

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteImageDecoderAVFProxy.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/media/RemoteImageDecoderAVFProxy.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteImageDecoderAVFProxy.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -29,6 +29,7 @@
 #if ENABLE(GPU_PROCESS) && HAVE(AVASSETREADER)
 
 #include "GPUConnectionToWebProcess.h"
+#include "GPUProcess.h"
 #include "RemoteImageDecoderAVFManagerMessages.h"
 #include "RemoteImageDecoderAVFProxyMessages.h"
 #include "WebCoreArgumentCoders.h"
@@ -70,6 +71,8 @@
         return;
 
     m_imageDecoders.take(identifier);
+    if (m_connectionToWebProcess && allowsExitUnderMemoryPressure())
+        m_connectionToWebProcess->gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
 }
 
 void RemoteImageDecoderAVFProxy::encodedDataStatusChanged(ImageDecoderIdentifier identifier)
@@ -141,6 +144,11 @@
         imageDecoder->clearFrameBufferCache(std::min(index, imageDecoder->frameCount() - 1));
 }
 
+bool RemoteImageDecoderAVFProxy::allowsExitUnderMemoryPressure() const
+{
+    return m_imageDecoders.isEmpty();
 }
 
+}
+
 #endif

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteImageDecoderAVFProxy.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/media/RemoteImageDecoderAVFProxy.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteImageDecoderAVFProxy.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -50,6 +50,8 @@
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;
     bool didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, UniqueRef<IPC::Encoder>&) final;
 
+    bool allowsExitUnderMemoryPressure() const;
+
 private:
     void createDecoder(const IPC::DataReference&, const String& mimeType, CompletionHandler<void(Optional<WebCore::ImageDecoderIdentifier>&&)>&&);
     void deleteDecoder(WebCore::ImageDecoderIdentifier);

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteLegacyCDMFactoryProxy.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/media/RemoteLegacyCDMFactoryProxy.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteLegacyCDMFactoryProxy.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -29,6 +29,7 @@
 #if ENABLE(GPU_PROCESS) && ENABLE(LEGACY_ENCRYPTED_MEDIA)
 
 #include "GPUConnectionToWebProcess.h"
+#include "GPUProcess.h"
 #include "RemoteLegacyCDMProxy.h"
 #include "RemoteLegacyCDMProxyMessages.h"
 #include "RemoteLegacyCDMSessionProxy.h"
@@ -151,6 +152,9 @@
 
     ASSERT(m_sessions.contains(identifier));
     m_sessions.remove(identifier);
+
+    if (m_gpuConnectionToWebProcess && allowsExitUnderMemoryPressure())
+        m_gpuConnectionToWebProcess->gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
 }
 
 RemoteLegacyCDMSessionProxy* RemoteLegacyCDMFactoryProxy::getSession(const RemoteLegacyCDMSessionIdentifier& identifier) const
@@ -161,6 +165,11 @@
     return nullptr;
 }
 
+bool RemoteLegacyCDMFactoryProxy::allowsExitUnderMemoryPressure() const
+{
+    return m_sessions.isEmpty();
 }
 
+}
+
 #endif

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteLegacyCDMFactoryProxy.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/media/RemoteLegacyCDMFactoryProxy.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteLegacyCDMFactoryProxy.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -64,6 +64,8 @@
 
     GPUConnectionToWebProcess* gpuConnectionToWebProcess() { return m_gpuConnectionToWebProcess.get(); }
 
+    bool allowsExitUnderMemoryPressure() const;
+
 private:
     friend class GPUProcessConnection;
     // IPC::MessageReceiver

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerManagerProxy.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerManagerProxy.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerManagerProxy.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -29,6 +29,7 @@
 #if ENABLE(GPU_PROCESS)
 
 #include "GPUConnectionToWebProcess.h"
+#include "GPUProcess.h"
 #include "Logging.h"
 #include "RemoteMediaPlayerConfiguration.h"
 #include "RemoteMediaPlayerManagerProxyMessages.h"
@@ -72,9 +73,13 @@
 void RemoteMediaPlayerManagerProxy::deleteMediaPlayer(MediaPlayerIdentifier identifier)
 {
     ASSERT(RunLoop::isMain());
-    auto locker = holdLock(m_proxiesLock);
-    if (auto proxy = m_proxies.take(identifier))
-        proxy->invalidate();
+    {
+        auto locker = holdLock(m_proxiesLock);
+        if (auto proxy = m_proxies.take(identifier))
+            proxy->invalidate();
+    }
+    if (m_gpuConnectionToWebProcess && allowsExitUnderMemoryPressure())
+        m_gpuConnectionToWebProcess->gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
 }
 
 void RemoteMediaPlayerManagerProxy::getSupportedTypes(MediaPlayerEnums::MediaEngineIdentifier engineIdentifier, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
@@ -179,6 +184,11 @@
     return nullptr;
 }
 
+bool RemoteMediaPlayerManagerProxy::allowsExitUnderMemoryPressure() const
+{
+    return m_proxies.isEmpty();
+}
+
 #if !RELEASE_LOG_DISABLED
 Logger& RemoteMediaPlayerManagerProxy::logger()
 {

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerManagerProxy.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerManagerProxy.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerManagerProxy.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -65,6 +65,7 @@
     bool didReceiveSyncPlayerMessage(IPC::Connection&, IPC::Decoder&, UniqueRef<IPC::Encoder>&);
 
     RefPtr<WebCore::MediaPlayer> mediaPlayer(const WebCore::MediaPlayerIdentifier&);
+    bool allowsExitUnderMemoryPressure() const;
 
 private:
     // IPC::MessageReceiver

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -88,6 +88,11 @@
     m_renderers.remove(identifier);
 }
 
+bool RemoteAudioMediaStreamTrackRendererManager::allowsExitUnderMemoryPressure() const
+{
+    return m_renderers.isEmpty();
 }
 
+}
+
 #endif // PLATFORM(COCOA) && ENABLE(GPU_PROCESS) && ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -60,6 +60,8 @@
 
     void close();
 
+    bool allowsExitUnderMemoryPressure() const;
+
 private:
     explicit RemoteAudioMediaStreamTrackRendererManager(GPUConnectionToWebProcess&);
     void startListeningForIPC();

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -65,8 +65,15 @@
 void RemoteMediaRecorderManager::releaseRecorder(MediaRecorderIdentifier identifier)
 {
     m_recorders.remove(identifier);
+    if (allowsExitUnderMemoryPressure())
+        m_gpuConnectionToWebProcess.gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
 }
 
+bool RemoteMediaRecorderManager::allowsExitUnderMemoryPressure() const
+{
+    return m_recorders.isEmpty();
 }
 
+}
+
 #endif

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -58,6 +58,8 @@
     void didReceiveRemoteMediaRecorderMessage(IPC::Connection&, IPC::Decoder&);
     void didReceiveMessageFromWebProcess(IPC::Connection& connection, IPC::Decoder& decoder) { didReceiveMessage(connection, decoder); }
 
+    bool allowsExitUnderMemoryPressure() const;
+
 private:
     // IPC::MessageReceiver
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.cpp (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -103,6 +103,11 @@
     });
 }
 
+bool RemoteSampleBufferDisplayLayerManager::allowsExitUnderMemoryPressure() const
+{
+    return m_layers.isEmpty();
 }
 
+}
+
 #endif // PLATFORM(COCOA) && ENABLE(GPU_PROCESS) && ENABLE(MEDIA_STREAM)

Modified: trunk/Source/WebKit/GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.h (276147 => 276148)


--- trunk/Source/WebKit/GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -59,6 +59,8 @@
 
     void close();
 
+    bool allowsExitUnderMemoryPressure() const;
+
 private:
     explicit RemoteSampleBufferDisplayLayerManager(GPUConnectionToWebProcess&);
     void startListeningForIPC();

Modified: trunk/Source/WebKit/Shared/ProcessTerminationReason.h (276147 => 276148)


--- trunk/Source/WebKit/Shared/ProcessTerminationReason.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/Shared/ProcessTerminationReason.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -37,4 +37,9 @@
     RequestedByGPUProcess
 };
 
+enum class GPUProcessTerminationReason {
+    Crash,
+    IdleExit
+};
+
 }

Modified: trunk/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -368,8 +368,13 @@
     m_orientationNotifier.orientationChanged(orientation);
 }
 
+bool UserMediaCaptureManagerProxy::hasSourceProxies() const
+{
+    return !m_proxies.isEmpty();
 }
 
+}
+
 #undef MESSAGE_CHECK
 
 #endif

Modified: trunk/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -67,6 +67,8 @@
 
     void didReceiveMessageFromGPUProcess(IPC::Connection& connection, IPC::Decoder& decoder) { didReceiveMessage(connection, decoder); }
 
+    bool hasSourceProxies() const;
+
 private:
     // IPC::MessageReceiver
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;

Modified: trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -285,19 +285,37 @@
     }, 0, IPC::SendOption::DispatchMessageEvenWhenWaitingForSyncReply);
 }
 
-void GPUProcessProxy::gpuProcessCrashed()
+void GPUProcessProxy::gpuProcessExited(GPUProcessTerminationReason reason)
 {
+    auto protectedThis = makeRef(*this);
+
+    switch (reason) {
+    case GPUProcessTerminationReason::Crash:
+        RELEASE_LOG_ERROR(Process, "%p - GPUProcessProxy::gpuProcessExited: reason=crash", this);
+        break;
+    case GPUProcessTerminationReason::IdleExit:
+        RELEASE_LOG(Process, "%p - GPUProcessProxy::gpuProcessExited: reason=idle-exit", this);
+        break;
+    }
+
     if (singleton() == this)
         singleton() = nullptr;
 
     for (auto& processPool : WebProcessPool::allProcessPools())
-        processPool->gpuProcessCrashed(processIdentifier());
+        processPool->gpuProcessExited(processIdentifier(), reason);
 }
 
+void GPUProcessProxy::processIsReadyToExit()
+{
+    RELEASE_LOG(Process, "%p - GPUProcessProxy::processIsReadyToExit:", this);
+    terminate();
+    gpuProcessExited(GPUProcessTerminationReason::IdleExit); // May cause |this| to get deleted.
+}
+
 void GPUProcessProxy::didClose(IPC::Connection&)
 {
-    // This will cause us to be deleted.
-    gpuProcessCrashed();
+    RELEASE_LOG_ERROR(Process, "%p - GPUProcessProxy::didClose:", this);
+    gpuProcessExited(GPUProcessTerminationReason::Crash); // May cause |this| to get deleted.
 }
 
 void GPUProcessProxy::didReceiveInvalidMessage(IPC::Connection& connection, IPC::MessageName messageName)
@@ -319,7 +337,7 @@
     AuxiliaryProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
 
     if (!IPC::Connection::identifierIsValid(connectionIdentifier)) {
-        gpuProcessCrashed();
+        gpuProcessExited(GPUProcessTerminationReason::Crash);
         return;
     }
     

Modified: trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.h (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -30,6 +30,7 @@
 #include "AuxiliaryProcessProxy.h"
 #include "GPUProcessProxyMessagesReplies.h"
 #include "ProcessLauncher.h"
+#include "ProcessTerminationReason.h"
 #include "ProcessThrottler.h"
 #include "ProcessThrottlerClient.h"
 #include "WebPageProxyIdentifier.h"
@@ -101,7 +102,7 @@
     void connectionWillOpen(IPC::Connection&) override;
     void processWillShutDown(IPC::Connection&) override;
 
-    void gpuProcessCrashed();
+    void gpuProcessExited(GPUProcessTerminationReason);
 
     // ProcessThrottlerClient
     ASCIILiteral clientName() const final { return "GPUProcess"_s; }
@@ -117,6 +118,7 @@
     void didReceiveInvalidMessage(IPC::Connection&, IPC::MessageName) override;
 
     void terminateWebProcess(WebCore::ProcessIdentifier);
+    void processIsReadyToExit();
 
 #if HAVE(VISIBILITY_PROPAGATION_VIEW)
     void didCreateContextForVisibilityPropagation(WebPageProxyIdentifier, WebCore::PageIdentifier, LayerHostingContextID);

Modified: trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.messages.in (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.messages.in	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.messages.in	2021-04-16 18:41:22 UTC (rev 276148)
@@ -28,6 +28,7 @@
     DidCreateContextForVisibilityPropagation(WebKit::WebPageProxyIdentifier pageProxyID, WebCore::PageIdentifier pageID, WebKit::LayerHostingContextID contextID)
 #endif
 
+    ProcessIsReadyToExit()
     TerminateWebProcess(WebCore::ProcessIdentifier webProcessIdentifier)
 }
 

Modified: trunk/Source/WebKit/UIProcess/PageClient.h (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/PageClient.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/PageClient.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -342,7 +342,7 @@
 #endif
 
 #if ENABLE(GPU_PROCESS)
-    virtual void gpuProcessCrashed() { }
+    virtual void gpuProcessDidExit() { }
 #endif
 
     virtual void doneWithKeyEvent(const NativeWebKeyboardEvent&, bool wasEventHandled) = 0;

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -10397,13 +10397,13 @@
 #endif
 
 #if ENABLE(GPU_PROCESS)
-void WebPageProxy::gpuProcessCrashed()
+void WebPageProxy::gpuProcessExited(GPUProcessTerminationReason)
 {
 #if HAVE(VISIBILITY_PROPAGATION_VIEW)
     m_contextIDForVisibilityPropagationInGPUProcess = 0;
 #endif
 
-    pageClient().gpuProcessCrashed();
+    pageClient().gpuProcessDidExit();
 
 #if ENABLE(MEDIA_STREAM)
     bool shouldAllowAudioCapture = isCapturingAudio() && preferences().captureAudioInGPUProcessEnabled();

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -1237,7 +1237,7 @@
 #endif
 
 #if ENABLE(GPU_PROCESS)
-    void gpuProcessCrashed();
+    void gpuProcessExited(GPUProcessTerminationReason);
 #endif
 
     virtual void enterAcceleratedCompositingMode(const LayerTreeContext&);

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -504,23 +504,27 @@
     return *m_gpuProcess;
 }
 
-void WebProcessPool::gpuProcessCrashed(ProcessID identifier)
+void WebProcessPool::gpuProcessExited(ProcessID identifier, GPUProcessTerminationReason reason)
 {
-    WEBPROCESSPOOL_RELEASE_LOG_ERROR(Process, "gpuProcessCrashed: PID=%d", identifier);
+    WEBPROCESSPOOL_RELEASE_LOG(Process, "gpuProcessDidExit: PID=%d, reason=%u", identifier, static_cast<unsigned>(reason));
     m_gpuProcess = nullptr;
 
-    m_client.gpuProcessDidCrash(this, identifier);
+    if (reason == GPUProcessTerminationReason::Crash)
+        m_client.gpuProcessDidCrash(this, identifier);
+
     Vector<Ref<WebProcessProxy>> processes = m_processes;
     for (auto& process : processes)
-        process->gpuProcessCrashed();
+        process->gpuProcessExited(reason);
 
-    if (++m_recentGPUProcessCrashCount > maximumGPUProcessRelaunchAttemptsBeforeKillingWebProcesses) {
-        WEBPROCESSPOOL_RELEASE_LOG_ERROR(Process, "gpuProcessCrashed: GPU Process has crashed more than %u times in the last %g seconds, terminating all WebProcesses", maximumGPUProcessRelaunchAttemptsBeforeKillingWebProcesses, resetGPUProcessCrashCountDelay.seconds());
-        m_resetGPUProcessCrashCountTimer.stop();
-        m_recentGPUProcessCrashCount = 0;
-        terminateAllWebContentProcesses();
-    } else if (!m_resetGPUProcessCrashCountTimer.isActive())
-        m_resetGPUProcessCrashCountTimer.startOneShot(resetGPUProcessCrashCountDelay);
+    if (reason == GPUProcessTerminationReason::Crash) {
+        if (++m_recentGPUProcessCrashCount > maximumGPUProcessRelaunchAttemptsBeforeKillingWebProcesses) {
+            WEBPROCESSPOOL_RELEASE_LOG_ERROR(Process, "gpuProcessDidExit: GPU Process has crashed more than %u times in the last %g seconds, terminating all WebProcesses", maximumGPUProcessRelaunchAttemptsBeforeKillingWebProcesses, resetGPUProcessCrashCountDelay.seconds());
+            m_resetGPUProcessCrashCountTimer.stop();
+            m_recentGPUProcessCrashCount = 0;
+            terminateAllWebContentProcesses();
+        } else if (!m_resetGPUProcessCrashCountTimer.isActive())
+            m_resetGPUProcessCrashCountTimer.startOneShot(resetGPUProcessCrashCountDelay);
+    }
 }
 
 void WebProcessPool::getGPUProcessConnection(WebProcessProxy& webProcessProxy, GPUProcessConnectionParameters&& parameters, Messages::WebProcessProxy::GetGPUProcessConnection::DelayedReply&& reply)

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -357,7 +357,7 @@
     void textCheckerStateChanged();
 
 #if ENABLE(GPU_PROCESS)
-    void gpuProcessCrashed(ProcessID);
+    void gpuProcessExited(ProcessID, GPUProcessTerminationReason);
 
     void getGPUProcessConnection(WebProcessProxy&, GPUProcessConnectionParameters&&, Messages::WebProcessProxy::GetGPUProcessConnectionDelayedReply&&);
 

Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp	2021-04-16 18:41:22 UTC (rev 276148)
@@ -786,10 +786,10 @@
     m_processPool->getGPUProcessConnection(*this, WTFMove(parameters), WTFMove(reply));
 }
 
-void WebProcessProxy::gpuProcessCrashed()
+void WebProcessProxy::gpuProcessExited(GPUProcessTerminationReason reason)
 {
     for (auto& page : copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values()))
-        page->gpuProcessCrashed();
+        page->gpuProcessExited(reason);
 }
 #endif
 

Modified: trunk/Source/WebKit/UIProcess/WebProcessProxy.h (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/WebProcessProxy.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/WebProcessProxy.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -376,7 +376,7 @@
 #endif
 
 #if ENABLE(GPU_PROCESS)
-    void gpuProcessCrashed();
+    void gpuProcessExited(GPUProcessTerminationReason);
 #endif
 
     bool hasSleepDisabler() const;

Modified: trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -81,7 +81,7 @@
 #endif // HAVE(VISIBILITY_PROPAGATION_VIEW)
 
 #if ENABLE(GPU_PROCESS)
-    void gpuProcessCrashed() override;
+    void gpuProcessDidExit() override;
 #endif
     void preferencesDidChange() override;
     void toolTipChanged(const String&, const String&) override;

Modified: trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm	2021-04-16 18:41:22 UTC (rev 276148)
@@ -212,9 +212,9 @@
 #endif // HAVE(VISIBILITY_PROPAGATION_VIEW)
 
 #if ENABLE(GPU_PROCESS)
-void PageClientImpl::gpuProcessCrashed()
+void PageClientImpl::gpuProcessDidExit()
 {
-    [m_contentView _gpuProcessCrashed];
+    [m_contentView _gpuProcessDidExit];
 }
 #endif
 

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentView.h (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/ios/WKContentView.h	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentView.h	2021-04-16 18:41:22 UTC (rev 276148)
@@ -98,7 +98,7 @@
 - (std::unique_ptr<WebKit::DrawingAreaProxy>)_createDrawingAreaProxy:(WebKit::WebProcessProxy&)process;
 - (void)_processDidExit;
 #if ENABLE(GPU_PROCESS)
-- (void)_gpuProcessCrashed;
+- (void)_gpuProcessDidExit;
 #endif
 - (void)_processWillSwap;
 - (void)_didRelaunchProcess;

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentView.mm (276147 => 276148)


--- trunk/Source/WebKit/UIProcess/ios/WKContentView.mm	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentView.mm	2021-04-16 18:41:22 UTC (rev 276148)
@@ -656,7 +656,7 @@
 }
 
 #if ENABLE(GPU_PROCESS)
-- (void)_gpuProcessCrashed
+- (void)_gpuProcessDidExit
 {
 #if HAVE(VISIBILITY_PROPAGATION_VIEW)
     [self _removeVisibilityPropagationViewForGPUProcess];

Modified: trunk/Tools/ChangeLog (276147 => 276148)


--- trunk/Tools/ChangeLog	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Tools/ChangeLog	2021-04-16 18:41:22 UTC (rev 276148)
@@ -1,3 +1,16 @@
+2021-04-16  Chris Dumez  <[email protected]>
+
+        Exit the GPUProcess when under memory pressure if it is not being used
+        https://bugs.webkit.org/show_bug.cgi?id=224556
+
+        Reviewed by Darin Adler.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm:
+        (runMemoryPressureExitTest):
+        (TEST):
+
 2021-04-16  Aakash Jain  <[email protected]>
 
         [ews] Improve step description when layout-tests step is skipped

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm (276147 => 276148)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm	2021-04-16 18:17:21 UTC (rev 276147)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm	2021-04-16 18:41:22 UTC (rev 276148)
@@ -34,6 +34,8 @@
 #import <WebKit/WKString.h>
 #import <WebKit/WKWebViewConfiguration.h>
 #import <WebKit/WKWebViewPrivate.h>
+#import <notify.h>
+#import <wtf/Function.h>
 #import <wtf/RetainPtr.h>
 
 #if PLATFORM(MAC)
@@ -490,3 +492,90 @@
     }];
     TestWebKitAPI::Util::run(&done);
 }
+
+static void runMemoryPressureExitTest(Function<void(WKWebView *)>&& loadTestPageSynchronously)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    WKPreferencesSetBoolValueForKeyForTesting((__bridge WKPreferencesRef)[configuration preferences], true, WKStringCreateWithUTF8CString("UseGPUProcessForMediaEnabled"));
+    WKPreferencesSetBoolValueForKeyForTesting((__bridge WKPreferencesRef)[configuration preferences], true, WKStringCreateWithUTF8CString("CaptureVideoInGPUProcessEnabled"));
+    WKPreferencesSetBoolValueForKeyForTesting((__bridge WKPreferencesRef)[configuration preferences], true, WKStringCreateWithUTF8CString("UseGPUProcessForCanvasRenderingEnabled"));
+    WKPreferencesSetBoolValueForKeyForTesting((__bridge WKPreferencesRef)[configuration preferences], false, WKStringCreateWithUTF8CString("UseGPUProcessForDOMRenderingEnabled"));
+
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 400) configuration:configuration.get()]);
+    loadTestPageSynchronously(webView.get());
+
+    // A GPUProcess should get launched.
+    while (![configuration.get().processPool _gpuProcessIdentifier])
+        TestWebKitAPI::Util::sleep(0.1);
+    auto gpuProcessPID = [configuration.get().processPool _gpuProcessIdentifier];
+
+    // Simulate memory pressure (notifyutil -p org.WebKit.lowMemory).
+    notify_post("org.WebKit.lowMemory");
+
+    // Make sure the GPUProcess does not exit since it is still needed.
+    TestWebKitAPI::Util::sleep(0.5);
+    EXPECT_EQ(gpuProcessPID, [configuration.get().processPool _gpuProcessIdentifier]);
+
+    // Navigate to another page that no longer requires the GPUProcess.
+    [webView synchronouslyLoadTestPageNamed:@"simple"];
+
+    // The GPUProcess should exit on memory pressure.
+    do {
+        // Simulate memory pressure (notifyutil -p org.WebKit.lowMemory).
+        notify_post("org.WebKit.lowMemory");
+        TestWebKitAPI::Util::sleep(0.1);
+    } while ([configuration.get().processPool _gpuProcessIdentifier]);
+
+    // The GPUProcess should not relaunch.
+    TestWebKitAPI::Util::sleep(0.5);
+    EXPECT_EQ(0, [configuration.get().processPool _gpuProcessIdentifier]);
+}
+
+TEST(GPUProcess, ExitsUnderMemoryPressureCanvasCase)
+{
+    runMemoryPressureExitTest([](WKWebView *webView) {
+        [webView synchronouslyLoadHTMLString:testCanvasPage];
+
+        __block bool done = false;
+        [webView evaluateJavaScript:@"context.fillStyle = '#00FF00'; context.fillRect(0, 0, 400, 400);" completionHandler:^(id result, NSError *error) {
+            EXPECT_TRUE(!error);
+            done = true;
+        }];
+        TestWebKitAPI::Util::run(&done);
+        done = false;
+        [webView evaluateJavaScript:@"context.getImageData(0, 0, 400, 400).width" completionHandler:^(id result, NSError *error) {
+            EXPECT_TRUE(!error);
+            done = true;
+        }];
+        TestWebKitAPI::Util::run(&done);
+    });
+}
+
+TEST(GPUProcess, ExitsUnderMemoryPressureVideoCase)
+{
+    runMemoryPressureExitTest([](WKWebView *webView) {
+        [webView synchronouslyLoadTestPageNamed:@"large-videos-with-audio"];
+
+        __block bool done = false;
+        [webView evaluateJavaScript:@"document.getElementsByTagName('video')[0].play() && true" completionHandler:^(id result, NSError *error) {
+            EXPECT_TRUE(!error);
+            done = true;
+        }];
+        TestWebKitAPI::Util::run(&done);
+    });
+}
+
+TEST(GPUProcess, ExitsUnderMemoryPressureWebAudioCase)
+{
+    runMemoryPressureExitTest([](WKWebView *webView) {
+        [webView synchronouslyLoadTestPageNamed:@"audio-context-playing"];
+
+        // evaluateJavaScript gives us the user gesture we need to reliably start audio playback on all platforms.
+        __block bool done = false;
+        [webView evaluateJavaScript:@"startPlaying()" completionHandler:^(id result, NSError *error) {
+            EXPECT_TRUE(!error);
+            done = true;
+        }];
+        TestWebKitAPI::Util::run(&done);
+    });
+}
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to