⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 276148 in webkit


Ignore:
Timestamp:
Apr 16, 2021, 11:41:22 AM (5 years ago)
Author:
Chris Dumez
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):

Location:
trunk
Files:
42 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r276145 r276148  
     12021-04-16  Chris Dumez  <cdumez@apple.com>
     2
     3        Exit the GPUProcess when under memory pressure if it is not being used
     4        https://bugs.webkit.org/show_bug.cgi?id=224556
     5
     6        Reviewed by Darin Adler.
     7
     8        Exit the GPUProcess when under memory pressure if it is not being used. This will
     9        help us save memory, especially until we are able to enable "DOM Rendering in
     10        GPUProcess".
     11
     12        Note that when the GPUProcess is ready to exit, it sends an IPC to the UIProcess
     13        in order to get terminated, instead of terminating itself. The reason I do this is
     14        so that the UIProcess can distinguish a GPUProcess crash from a normal idle exit.
     15
     16        A/B testing shows:
     17        - 5-8% PLUM3 progression on iPhone
     18        - 2.5-4% PLUM3 progression on iPad
     19        - No PLT5 regression on either iPhone or iPad.
     20
     21        * GPUProcess/GPUConnectionToWebProcess.cpp:
     22        (WebKit::GPUConnectionToWebProcess::GPUConnectionToWebProcess):
     23        (WebKit::GPUConnectionToWebProcess::allowsExitUnderMemoryPressure const):
     24        (WebKit::GPUConnectionToWebProcess::releaseRenderingBackend):
     25        (WebKit::GPUConnectionToWebProcess::releaseGraphicsContextGL):
     26        * GPUProcess/GPUConnectionToWebProcess.h:
     27        (WebKit::GPUConnectionToWebProcess::remoteMediaPlayerManagerProxy):
     28        * GPUProcess/GPUProcess.cpp:
     29        (WebKit::GPUProcess::removeGPUConnectionToWebProcess):
     30        (WebKit::GPUProcess::canExitUnderMemoryPressure const):
     31        (WebKit::GPUProcess::tryExitIfUnusedAndUnderMemoryPressure):
     32        (WebKit::GPUProcess::tryExitIfUnused):
     33        (WebKit::GPUProcess::lowMemoryHandler):
     34        * GPUProcess/GPUProcess.h:
     35        * GPUProcess/graphics/RemoteRenderingBackend.cpp:
     36        (WebKit::RemoteRenderingBackend::allowsExitUnderMemoryPressure const):
     37        * GPUProcess/graphics/RemoteRenderingBackend.h:
     38        * GPUProcess/media/RemoteAudioDestinationManager.cpp:
     39        (WebKit::RemoteAudioDestinationManager::deleteAudioDestination):
     40        (WebKit::RemoteAudioDestinationManager::allowsExitUnderMemoryPressure const):
     41        * GPUProcess/media/RemoteAudioDestinationManager.h:
     42        * GPUProcess/media/RemoteCDMFactoryProxy.cpp:
     43        (WebKit::RemoteCDMFactoryProxy::removeInstance):
     44        (WebKit::RemoteCDMFactoryProxy::allowsExitUnderMemoryPressure const):
     45        * GPUProcess/media/RemoteCDMFactoryProxy.h:
     46        * GPUProcess/media/RemoteImageDecoderAVFProxy.cpp:
     47        (WebKit::RemoteImageDecoderAVFProxy::deleteDecoder):
     48        (WebKit::RemoteImageDecoderAVFProxy::allowsExitUnderMemoryPressure const):
     49        * GPUProcess/media/RemoteImageDecoderAVFProxy.h:
     50        * GPUProcess/media/RemoteLegacyCDMFactoryProxy.cpp:
     51        (WebKit::RemoteLegacyCDMFactoryProxy::removeSession):
     52        (WebKit::RemoteLegacyCDMFactoryProxy::allowsExitUnderMemoryPressure const):
     53        * GPUProcess/media/RemoteLegacyCDMFactoryProxy.h:
     54        * GPUProcess/media/RemoteMediaPlayerManagerProxy.cpp:
     55        (WebKit::RemoteMediaPlayerManagerProxy::deleteMediaPlayer):
     56        (WebKit::RemoteMediaPlayerManagerProxy::allowsExitUnderMemoryPressure const):
     57        * GPUProcess/media/RemoteMediaPlayerManagerProxy.h:
     58        * GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.cpp:
     59        (WebKit::RemoteAudioMediaStreamTrackRendererManager::allowsExitUnderMemoryPressure const):
     60        * GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.h:
     61        * GPUProcess/webrtc/RemoteMediaRecorderManager.cpp:
     62        (WebKit::RemoteMediaRecorderManager::releaseRecorder):
     63        (WebKit::RemoteMediaRecorderManager::allowsExitUnderMemoryPressure const):
     64        * GPUProcess/webrtc/RemoteMediaRecorderManager.h:
     65        * GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.cpp:
     66        (WebKit::RemoteSampleBufferDisplayLayerManager::allowsExitUnderMemoryPressure const):
     67        * GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.h:
     68        * Shared/ProcessTerminationReason.h:
     69        * UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp:
     70        (WebKit::UserMediaCaptureManagerProxy::hasSourceProxies const):
     71        * UIProcess/Cocoa/UserMediaCaptureManagerProxy.h:
     72        * UIProcess/GPU/GPUProcessProxy.cpp:
     73        (WebKit::GPUProcessProxy::gpuProcessExited):
     74        (WebKit::GPUProcessProxy::processIsReadyToExit):
     75        (WebKit::GPUProcessProxy::didClose):
     76        (WebKit::GPUProcessProxy::didFinishLaunching):
     77        * UIProcess/GPU/GPUProcessProxy.h:
     78        * UIProcess/GPU/GPUProcessProxy.messages.in:
     79        * UIProcess/PageClient.h:
     80        (WebKit::PageClient::gpuProcessDidExit):
     81        * UIProcess/WebPageProxy.cpp:
     82        (WebKit::WebPageProxy::gpuProcessExited):
     83        * UIProcess/WebPageProxy.h:
     84        * UIProcess/WebProcessPool.cpp:
     85        (WebKit::WebProcessPool::gpuProcessExited):
     86        * UIProcess/WebProcessPool.h:
     87        * UIProcess/WebProcessProxy.cpp:
     88        (WebKit::WebProcessProxy::gpuProcessExited):
     89        * UIProcess/WebProcessProxy.h:
     90        * UIProcess/ios/PageClientImplIOS.h:
     91        * UIProcess/ios/PageClientImplIOS.mm:
     92        (WebKit::PageClientImpl::gpuProcessDidExit):
     93        * UIProcess/ios/WKContentView.h:
     94        * UIProcess/ios/WKContentView.mm:
     95        (-[WKContentView _gpuProcessDidExit]):
     96
    1972021-04-16  Chris Dumez  <cdumez@apple.com>
    298
  • trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp

    r276145 r276148  
    190190    , m_webProcessIdentityToken(WTFMove(parameters.webProcessIdentityToken))
    191191#endif
    192     , m_remoteMediaPlayerManagerProxy(makeUnique<RemoteMediaPlayerManagerProxy>(*this))
     192    , m_remoteMediaPlayerManagerProxy(makeUniqueRef<RemoteMediaPlayerManagerProxy>(*this))
    193193    , m_sessionID(sessionID)
    194194#if PLATFORM(COCOA) && USE(LIBWEBRTC)
     
    268268#endif
    269269
     270bool GPUConnectionToWebProcess::allowsExitUnderMemoryPressure() const
     271{
     272    for (auto& remoteRenderingBackend : m_remoteRenderingBackendMap.values()) {
     273        if (!remoteRenderingBackend->allowsExitUnderMemoryPressure())
     274            return false;
     275    }
     276#if ENABLE(WEBGL)
     277    if (!m_remoteGraphicsContextGLMap.isEmpty())
     278        return false;
     279#endif
     280    if (!m_remoteMediaPlayerManagerProxy->allowsExitUnderMemoryPressure())
     281        return false;
     282#if ENABLE(WEB_AUDIO)
     283    if (m_remoteAudioDestinationManager && !m_remoteAudioDestinationManager->allowsExitUnderMemoryPressure())
     284        return false;
     285#endif
     286#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
     287    if (m_userMediaCaptureManagerProxy && m_userMediaCaptureManagerProxy->hasSourceProxies())
     288        return false;
     289    if (!m_audioTrackRendererManager->allowsExitUnderMemoryPressure())
     290        return false;
     291    if (!m_sampleBufferDisplayLayerManager->allowsExitUnderMemoryPressure())
     292        return false;
     293#endif
     294#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
     295    if (m_remoteMediaRecorderManager && !m_remoteMediaRecorderManager->allowsExitUnderMemoryPressure())
     296        return false;
     297#endif
     298#if HAVE(AVASSETREADER)
     299    if (m_imageDecoderAVFProxy && !m_imageDecoderAVFProxy->allowsExitUnderMemoryPressure())
     300        return false;
     301#endif
     302#if ENABLE(ENCRYPTED_MEDIA)
     303    if (m_cdmFactoryProxy && !m_cdmFactoryProxy->allowsExitUnderMemoryPressure())
     304        return false;
     305#endif
     306#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
     307    if (m_legacyCdmFactoryProxy && !m_legacyCdmFactoryProxy->allowsExitUnderMemoryPressure())
     308        return false;
     309#endif
     310    return true;
     311}
     312
    270313Logger& GPUConnectionToWebProcess::logger()
    271314{
     
    320363    return *m_userMediaCaptureManagerProxy;
    321364}
    322 
    323 #if HAVE(AVASSETWRITERDELEGATE)
     365#endif
     366
     367#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
    324368RemoteMediaRecorderManager& GPUConnectionToWebProcess::mediaRecorderManager()
    325369{
     
    330374}
    331375#endif
    332 #endif //  PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
    333376
    334377#if ENABLE(ENCRYPTED_MEDIA)
     
    375418    bool found = m_remoteRenderingBackendMap.remove(renderingBackendIdentifier);
    376419    ASSERT_UNUSED(found, found);
     420    gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
    377421}
    378422
     
    394438{
    395439    m_remoteGraphicsContextGLMap.remove(graphicsContextGLIdentifier);
     440    if (m_remoteGraphicsContextGLMap.isEmpty())
     441        gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
    396442}
    397443
     
    538584        return true;
    539585    }
    540 #if HAVE(AVASSETWRITERDELEGATE)
     586#endif
     587#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
    541588    if (decoder.messageReceiverName() == Messages::RemoteMediaRecorderManager::messageReceiverName()) {
    542589        mediaRecorderManager().didReceiveMessageFromWebProcess(connection, decoder);
     
    547594        return true;
    548595    }
    549 #endif // HAVE(AVASSETWRITERDELEGATE)
    550 #endif // PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
     596#endif
    551597#if ENABLE(ENCRYPTED_MEDIA)
    552598    if (decoder.messageReceiverName() == Messages::RemoteCDMFactoryProxy::messageReceiverName()) {
  • trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h

    r276145 r276148  
    133133
    134134    RemoteMediaEngineConfigurationFactoryProxy& mediaEngineConfigurationFactoryProxy();
    135     RemoteMediaPlayerManagerProxy& remoteMediaPlayerManagerProxy() { return *m_remoteMediaPlayerManagerProxy; }
     135    RemoteMediaPlayerManagerProxy& remoteMediaPlayerManagerProxy() { return m_remoteMediaPlayerManagerProxy.get(); }
    136136
    137137#if USE(AUDIO_SESSION)
     
    145145    void updateSupportedRemoteCommands();
    146146
     147    bool allowsExitUnderMemoryPressure() const;
     148
    147149    void terminateWebProcess();
    148150#if ENABLE(WEBGL)
     
    157159#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
    158160    UserMediaCaptureManagerProxy& userMediaCaptureManagerProxy();
    159 #if HAVE(AVASSETWRITERDELEGATE)
     161#endif
     162#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
    160163    RemoteMediaRecorderManager& mediaRecorderManager();
    161 #endif
    162164#endif
    163165
     
    229231#endif
    230232    std::unique_ptr<RemoteMediaResourceManager> m_remoteMediaResourceManager;
    231     std::unique_ptr<RemoteMediaPlayerManagerProxy> m_remoteMediaPlayerManagerProxy;
     233    UniqueRef<RemoteMediaPlayerManagerProxy> m_remoteMediaPlayerManagerProxy;
    232234    PAL::SessionID m_sessionID;
    233235#if PLATFORM(COCOA) && USE(LIBWEBRTC)
     
    238240    Ref<RemoteAudioMediaStreamTrackRendererManager> m_audioTrackRendererManager;
    239241    Ref<RemoteSampleBufferDisplayLayerManager> m_sampleBufferDisplayLayerManager;
    240 #if HAVE(AVASSETWRITERDELEGATE)
     242#endif
     243#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) && HAVE(AVASSETWRITERDELEGATE)
    241244    std::unique_ptr<RemoteMediaRecorderManager> m_remoteMediaRecorderManager;
    242 #endif
    243245#endif
    244246#if ENABLE(MEDIA_STREAM)
  • trunk/Source/WebKit/GPUProcess/GPUProcess.cpp

    r275768 r276148  
    112112    ASSERT(m_webProcessConnections.contains(connection.webProcessIdentifier()));
    113113    m_webProcessConnections.remove(connection.webProcessIdentifier());
     114    tryExitIfUnusedAndUnderMemoryPressure();
    114115}
    115116
     
    123124}
    124125
     126bool GPUProcess::canExitUnderMemoryPressure() const
     127{
     128    ASSERT(isMainRunLoop());
     129    for (auto& webProcessConnection : m_webProcessConnections.values()) {
     130        if (!webProcessConnection->allowsExitUnderMemoryPressure())
     131            return false;
     132    }
     133    return true;
     134}
     135
     136void GPUProcess::tryExitIfUnusedAndUnderMemoryPressure()
     137{
     138    ASSERT(isMainRunLoop());
     139    if (!MemoryPressureHandler::singleton().isUnderMemoryPressure())
     140        return;
     141
     142    tryExitIfUnused();
     143}
     144
     145void GPUProcess::tryExitIfUnused()
     146{
     147    ASSERT(isMainRunLoop());
     148    if (!canExitUnderMemoryPressure())
     149        return;
     150
     151    RELEASE_LOG(Process, "GPUProcess::tryExitIfUnused: GPUProcess is exiting because we are under memory pressure and the process is no longer useful.");
     152    parentProcessConnection()->send(Messages::GPUProcessProxy::ProcessIsReadyToExit(), 0);
     153}
     154
    125155void GPUProcess::lowMemoryHandler(Critical critical, Synchronous synchronous)
    126156{
     157    RELEASE_LOG(Process, "GPUProcess::lowMemoryHandler: critical=%d, synchronous=%d", critical == Critical::Yes, synchronous == Synchronous::Yes);
     158    tryExitIfUnused();
     159
    127160    WebCore::releaseGraphicsMemory(critical, synchronous);
    128161}
  • trunk/Source/WebKit/GPUProcess/GPUProcess.h

    r275768 r276148  
    9393#endif
    9494
     95    void tryExitIfUnusedAndUnderMemoryPressure();
     96
    9597private:
    9698    void lowMemoryHandler(Critical, Synchronous);
     
    101103    void initializeSandbox(const AuxiliaryProcessInitializationParameters&, SandboxInitializationParameters&) override;
    102104    bool shouldTerminate() override;
     105
     106    void tryExitIfUnused();
     107    bool canExitUnderMemoryPressure() const;
    103108
    104109    // IPC::Connection::Client
  • trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp

    r275921 r276148  
    598598}
    599599
     600bool RemoteRenderingBackend::allowsExitUnderMemoryPressure() const
     601{
     602    return m_remoteResourceCache.imageBuffers().isEmpty() && m_remoteResourceCache.nativeImages().isEmpty();
     603}
     604
    600605} // namespace WebKit
    601606
  • trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.h

    r275921 r276148  
    8484    void populateGetImageDataSharedMemory(WebCore::ImageData*);
    8585
     86    bool allowsExitUnderMemoryPressure() const;
     87
    8688    // Runs Function in RemoteRenderingBackend task queue.
    8789    void dispatch(Function<void()>&&);
  • trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.cpp

    r274174 r276148  
    3030
    3131#include "GPUConnectionToWebProcess.h"
     32#include "GPUProcess.h"
    3233#include <WebCore/AudioUtilities.h>
    3334#include <wtf/ThreadSafeRefCounted.h>
     
    174175        destination->scheduleGracefulShutdownIfNeeded();
    175176    completionHandler();
     177
     178    if (allowsExitUnderMemoryPressure())
     179        m_gpuConnectionToWebProcess.gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
    176180}
    177181
     
    204208#endif
    205209
     210bool RemoteAudioDestinationManager::allowsExitUnderMemoryPressure() const
     211{
     212    return m_audioDestinations.isEmpty();
     213}
     214
    206215} // namespace WebKit
    207216
  • trunk/Source/WebKit/GPUProcess/media/RemoteAudioDestinationManager.h

    r274189 r276148  
    5757    void didReceiveMessageFromWebProcess(IPC::Connection& connection, IPC::Decoder& decoder) { didReceiveMessage(connection, decoder); }
    5858
     59    bool allowsExitUnderMemoryPressure() const;
     60
    5961private:
    6062    void didReceiveMessage(IPC::Connection&, IPC::Decoder&);
  • trunk/Source/WebKit/GPUProcess/media/RemoteCDMFactoryProxy.cpp

    r274189 r276148  
    2929#if ENABLE(GPU_PROCESS) && ENABLE(ENCRYPTED_MEDIA)
    3030
     31#include "GPUProcess.h"
    3132#include "RemoteCDMConfiguration.h"
    3233#include "RemoteCDMInstanceProxy.h"
     
    143144    ASSERT(m_instances.contains(identifier));
    144145    m_instances.remove(identifier);
     146    if (m_gpuConnectionToWebProcess && allowsExitUnderMemoryPressure())
     147        m_gpuConnectionToWebProcess->gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
    145148}
    146149
     
    162165}
    163166
     167bool RemoteCDMFactoryProxy::allowsExitUnderMemoryPressure() const
     168{
     169    return m_instances.isEmpty();
     170}
     171
    164172}
    165173
  • trunk/Source/WebKit/GPUProcess/media/RemoteCDMFactoryProxy.h

    r274189 r276148  
    7171    GPUConnectionToWebProcess* gpuConnectionToWebProcess() { return m_gpuConnectionToWebProcess.get(); }
    7272
     73    bool allowsExitUnderMemoryPressure() const;
     74
    7375private:
    7476    friend class GPUProcessConnection;
  • trunk/Source/WebKit/GPUProcess/media/RemoteImageDecoderAVFProxy.cpp

    r275235 r276148  
    3030
    3131#include "GPUConnectionToWebProcess.h"
     32#include "GPUProcess.h"
    3233#include "RemoteImageDecoderAVFManagerMessages.h"
    3334#include "RemoteImageDecoderAVFProxyMessages.h"
     
    7172
    7273    m_imageDecoders.take(identifier);
     74    if (m_connectionToWebProcess && allowsExitUnderMemoryPressure())
     75        m_connectionToWebProcess->gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
    7376}
    7477
     
    142145}
    143146
     147bool RemoteImageDecoderAVFProxy::allowsExitUnderMemoryPressure() const
     148{
     149    return m_imageDecoders.isEmpty();
     150}
     151
    144152}
    145153
  • trunk/Source/WebKit/GPUProcess/media/RemoteImageDecoderAVFProxy.h

    r275235 r276148  
    5151    bool didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, UniqueRef<IPC::Encoder>&) final;
    5252
     53    bool allowsExitUnderMemoryPressure() const;
     54
    5355private:
    5456    void createDecoder(const IPC::DataReference&, const String& mimeType, CompletionHandler<void(Optional<WebCore::ImageDecoderIdentifier>&&)>&&);
  • trunk/Source/WebKit/GPUProcess/media/RemoteLegacyCDMFactoryProxy.cpp

    r274189 r276148  
    3030
    3131#include "GPUConnectionToWebProcess.h"
     32#include "GPUProcess.h"
    3233#include "RemoteLegacyCDMProxy.h"
    3334#include "RemoteLegacyCDMProxyMessages.h"
     
    152153    ASSERT(m_sessions.contains(identifier));
    153154    m_sessions.remove(identifier);
     155
     156    if (m_gpuConnectionToWebProcess && allowsExitUnderMemoryPressure())
     157        m_gpuConnectionToWebProcess->gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
    154158}
    155159
     
    162166}
    163167
     168bool RemoteLegacyCDMFactoryProxy::allowsExitUnderMemoryPressure() const
     169{
     170    return m_sessions.isEmpty();
     171}
     172
    164173}
    165174
  • trunk/Source/WebKit/GPUProcess/media/RemoteLegacyCDMFactoryProxy.h

    r274189 r276148  
    6565    GPUConnectionToWebProcess* gpuConnectionToWebProcess() { return m_gpuConnectionToWebProcess.get(); }
    6666
     67    bool allowsExitUnderMemoryPressure() const;
     68
    6769private:
    6870    friend class GPUProcessConnection;
  • trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerManagerProxy.cpp

    r274264 r276148  
    3030
    3131#include "GPUConnectionToWebProcess.h"
     32#include "GPUProcess.h"
    3233#include "Logging.h"
    3334#include "RemoteMediaPlayerConfiguration.h"
     
    7374{
    7475    ASSERT(RunLoop::isMain());
    75     auto locker = holdLock(m_proxiesLock);
    76     if (auto proxy = m_proxies.take(identifier))
    77         proxy->invalidate();
     76    {
     77        auto locker = holdLock(m_proxiesLock);
     78        if (auto proxy = m_proxies.take(identifier))
     79            proxy->invalidate();
     80    }
     81    if (m_gpuConnectionToWebProcess && allowsExitUnderMemoryPressure())
     82        m_gpuConnectionToWebProcess->gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
    7883}
    7984
     
    180185}
    181186
     187bool RemoteMediaPlayerManagerProxy::allowsExitUnderMemoryPressure() const
     188{
     189    return m_proxies.isEmpty();
     190}
     191
    182192#if !RELEASE_LOG_DISABLED
    183193Logger& RemoteMediaPlayerManagerProxy::logger()
  • trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerManagerProxy.h

    r274264 r276148  
    6666
    6767    RefPtr<WebCore::MediaPlayer> mediaPlayer(const WebCore::MediaPlayerIdentifier&);
     68    bool allowsExitUnderMemoryPressure() const;
    6869
    6970private:
  • trunk/Source/WebKit/GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.cpp

    r273074 r276148  
    8989}
    9090
     91bool RemoteAudioMediaStreamTrackRendererManager::allowsExitUnderMemoryPressure() const
     92{
     93    return m_renderers.isEmpty();
     94}
     95
    9196}
    9297
  • trunk/Source/WebKit/GPUProcess/webrtc/RemoteAudioMediaStreamTrackRendererManager.h

    r273074 r276148  
    6161    void close();
    6262
     63    bool allowsExitUnderMemoryPressure() const;
     64
    6365private:
    6466    explicit RemoteAudioMediaStreamTrackRendererManager(GPUConnectionToWebProcess&);
  • trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.cpp

    r268363 r276148  
    6666{
    6767    m_recorders.remove(identifier);
     68    if (allowsExitUnderMemoryPressure())
     69        m_gpuConnectionToWebProcess.gpuProcess().tryExitIfUnusedAndUnderMemoryPressure();
     70}
     71
     72bool RemoteMediaRecorderManager::allowsExitUnderMemoryPressure() const
     73{
     74    return m_recorders.isEmpty();
    6875}
    6976
  • trunk/Source/WebKit/GPUProcess/webrtc/RemoteMediaRecorderManager.h

    r268363 r276148  
    5959    void didReceiveMessageFromWebProcess(IPC::Connection& connection, IPC::Decoder& decoder) { didReceiveMessage(connection, decoder); }
    6060
     61    bool allowsExitUnderMemoryPressure() const;
     62
    6163private:
    6264    // IPC::MessageReceiver
  • trunk/Source/WebKit/GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.cpp

    r274194 r276148  
    104104}
    105105
     106bool RemoteSampleBufferDisplayLayerManager::allowsExitUnderMemoryPressure() const
     107{
     108    return m_layers.isEmpty();
     109}
     110
    106111}
    107112
  • trunk/Source/WebKit/GPUProcess/webrtc/RemoteSampleBufferDisplayLayerManager.h

    r273074 r276148  
    6060    void close();
    6161
     62    bool allowsExitUnderMemoryPressure() const;
     63
    6264private:
    6365    explicit RemoteSampleBufferDisplayLayerManager(GPUConnectionToWebProcess&);
  • trunk/Source/WebKit/Shared/ProcessTerminationReason.h

    r270415 r276148  
    3838};
    3939
     40enum class GPUProcessTerminationReason {
     41    Crash,
     42    IdleExit
     43};
     44
    4045}
  • trunk/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp

    r273892 r276148  
    369369}
    370370
     371bool UserMediaCaptureManagerProxy::hasSourceProxies() const
     372{
     373    return !m_proxies.isEmpty();
     374}
     375
    371376}
    372377
  • trunk/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h

    r272778 r276148  
    6868    void didReceiveMessageFromGPUProcess(IPC::Connection& connection, IPC::Decoder& decoder) { didReceiveMessage(connection, decoder); }
    6969
     70    bool hasSourceProxies() const;
     71
    7072private:
    7173    // IPC::MessageReceiver
  • trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.cpp

    r275768 r276148  
    286286}
    287287
    288 void GPUProcessProxy::gpuProcessCrashed()
    289 {
     288void GPUProcessProxy::gpuProcessExited(GPUProcessTerminationReason reason)
     289{
     290    auto protectedThis = makeRef(*this);
     291
     292    switch (reason) {
     293    case GPUProcessTerminationReason::Crash:
     294        RELEASE_LOG_ERROR(Process, "%p - GPUProcessProxy::gpuProcessExited: reason=crash", this);
     295        break;
     296    case GPUProcessTerminationReason::IdleExit:
     297        RELEASE_LOG(Process, "%p - GPUProcessProxy::gpuProcessExited: reason=idle-exit", this);
     298        break;
     299    }
     300
    290301    if (singleton() == this)
    291302        singleton() = nullptr;
    292303
    293304    for (auto& processPool : WebProcessPool::allProcessPools())
    294         processPool->gpuProcessCrashed(processIdentifier());
     305        processPool->gpuProcessExited(processIdentifier(), reason);
     306}
     307
     308void GPUProcessProxy::processIsReadyToExit()
     309{
     310    RELEASE_LOG(Process, "%p - GPUProcessProxy::processIsReadyToExit:", this);
     311    terminate();
     312    gpuProcessExited(GPUProcessTerminationReason::IdleExit); // May cause |this| to get deleted.
    295313}
    296314
    297315void GPUProcessProxy::didClose(IPC::Connection&)
    298316{
    299     // This will cause us to be deleted.
    300     gpuProcessCrashed();
     317    RELEASE_LOG_ERROR(Process, "%p - GPUProcessProxy::didClose:", this);
     318    gpuProcessExited(GPUProcessTerminationReason::Crash); // May cause |this| to get deleted.
    301319}
    302320
     
    320338
    321339    if (!IPC::Connection::identifierIsValid(connectionIdentifier)) {
    322         gpuProcessCrashed();
     340        gpuProcessExited(GPUProcessTerminationReason::Crash);
    323341        return;
    324342    }
  • trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.h

    r275805 r276148  
    3131#include "GPUProcessProxyMessagesReplies.h"
    3232#include "ProcessLauncher.h"
     33#include "ProcessTerminationReason.h"
    3334#include "ProcessThrottler.h"
    3435#include "ProcessThrottlerClient.h"
     
    102103    void processWillShutDown(IPC::Connection&) override;
    103104
    104     void gpuProcessCrashed();
     105    void gpuProcessExited(GPUProcessTerminationReason);
    105106
    106107    // ProcessThrottlerClient
     
    118119
    119120    void terminateWebProcess(WebCore::ProcessIdentifier);
     121    void processIsReadyToExit();
    120122
    121123#if HAVE(VISIBILITY_PROPAGATION_VIEW)
  • trunk/Source/WebKit/UIProcess/GPU/GPUProcessProxy.messages.in

    r275768 r276148  
    2929#endif
    3030
     31    ProcessIsReadyToExit()
    3132    TerminateWebProcess(WebCore::ProcessIdentifier webProcessIdentifier)
    3233}
  • trunk/Source/WebKit/UIProcess/PageClient.h

    r275768 r276148  
    343343
    344344#if ENABLE(GPU_PROCESS)
    345     virtual void gpuProcessCrashed() { }
     345    virtual void gpuProcessDidExit() { }
    346346#endif
    347347
  • trunk/Source/WebKit/UIProcess/WebPageProxy.cpp

    r276120 r276148  
    1039810398
    1039910399#if ENABLE(GPU_PROCESS)
    10400 void WebPageProxy::gpuProcessCrashed()
     10400void WebPageProxy::gpuProcessExited(GPUProcessTerminationReason)
    1040110401{
    1040210402#if HAVE(VISIBILITY_PROPAGATION_VIEW)
     
    1040410404#endif
    1040510405
    10406     pageClient().gpuProcessCrashed();
     10406    pageClient().gpuProcessDidExit();
    1040710407
    1040810408#if ENABLE(MEDIA_STREAM)
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r276120 r276148  
    12381238
    12391239#if ENABLE(GPU_PROCESS)
    1240     void gpuProcessCrashed();
     1240    void gpuProcessExited(GPUProcessTerminationReason);
    12411241#endif
    12421242
  • trunk/Source/WebKit/UIProcess/WebProcessPool.cpp

    r275916 r276148  
    505505}
    506506
    507 void WebProcessPool::gpuProcessCrashed(ProcessID identifier)
    508 {
    509     WEBPROCESSPOOL_RELEASE_LOG_ERROR(Process, "gpuProcessCrashed: PID=%d", identifier);
     507void WebProcessPool::gpuProcessExited(ProcessID identifier, GPUProcessTerminationReason reason)
     508{
     509    WEBPROCESSPOOL_RELEASE_LOG(Process, "gpuProcessDidExit: PID=%d, reason=%u", identifier, static_cast<unsigned>(reason));
    510510    m_gpuProcess = nullptr;
    511511
    512     m_client.gpuProcessDidCrash(this, identifier);
     512    if (reason == GPUProcessTerminationReason::Crash)
     513        m_client.gpuProcessDidCrash(this, identifier);
     514
    513515    Vector<Ref<WebProcessProxy>> processes = m_processes;
    514516    for (auto& process : processes)
    515         process->gpuProcessCrashed();
    516 
    517     if (++m_recentGPUProcessCrashCount > maximumGPUProcessRelaunchAttemptsBeforeKillingWebProcesses) {
    518         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());
    519         m_resetGPUProcessCrashCountTimer.stop();
    520         m_recentGPUProcessCrashCount = 0;
    521         terminateAllWebContentProcesses();
    522     } else if (!m_resetGPUProcessCrashCountTimer.isActive())
    523         m_resetGPUProcessCrashCountTimer.startOneShot(resetGPUProcessCrashCountDelay);
     517        process->gpuProcessExited(reason);
     518
     519    if (reason == GPUProcessTerminationReason::Crash) {
     520        if (++m_recentGPUProcessCrashCount > maximumGPUProcessRelaunchAttemptsBeforeKillingWebProcesses) {
     521            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());
     522            m_resetGPUProcessCrashCountTimer.stop();
     523            m_recentGPUProcessCrashCount = 0;
     524            terminateAllWebContentProcesses();
     525        } else if (!m_resetGPUProcessCrashCountTimer.isActive())
     526            m_resetGPUProcessCrashCountTimer.startOneShot(resetGPUProcessCrashCountDelay);
     527    }
    524528}
    525529
  • trunk/Source/WebKit/UIProcess/WebProcessPool.h

    r275916 r276148  
    358358
    359359#if ENABLE(GPU_PROCESS)
    360     void gpuProcessCrashed(ProcessID);
     360    void gpuProcessExited(ProcessID, GPUProcessTerminationReason);
    361361
    362362    void getGPUProcessConnection(WebProcessProxy&, GPUProcessConnectionParameters&&, Messages::WebProcessProxy::GetGPUProcessConnectionDelayedReply&&);
  • trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp

    r275916 r276148  
    787787}
    788788
    789 void WebProcessProxy::gpuProcessCrashed()
     789void WebProcessProxy::gpuProcessExited(GPUProcessTerminationReason reason)
    790790{
    791791    for (auto& page : copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values()))
    792         page->gpuProcessCrashed();
     792        page->gpuProcessExited(reason);
    793793}
    794794#endif
  • trunk/Source/WebKit/UIProcess/WebProcessProxy.h

    r275937 r276148  
    377377
    378378#if ENABLE(GPU_PROCESS)
    379     void gpuProcessCrashed();
     379    void gpuProcessExited(GPUProcessTerminationReason);
    380380#endif
    381381
  • trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.h

    r275768 r276148  
    8282
    8383#if ENABLE(GPU_PROCESS)
    84     void gpuProcessCrashed() override;
     84    void gpuProcessDidExit() override;
    8585#endif
    8686    void preferencesDidChange() override;
  • trunk/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm

    r275768 r276148  
    213213
    214214#if ENABLE(GPU_PROCESS)
    215 void PageClientImpl::gpuProcessCrashed()
    216 {
    217     [m_contentView _gpuProcessCrashed];
     215void PageClientImpl::gpuProcessDidExit()
     216{
     217    [m_contentView _gpuProcessDidExit];
    218218}
    219219#endif
  • trunk/Source/WebKit/UIProcess/ios/WKContentView.h

    r276051 r276148  
    9999- (void)_processDidExit;
    100100#if ENABLE(GPU_PROCESS)
    101 - (void)_gpuProcessCrashed;
     101- (void)_gpuProcessDidExit;
    102102#endif
    103103- (void)_processWillSwap;
  • trunk/Source/WebKit/UIProcess/ios/WKContentView.mm

    r276051 r276148  
    657657
    658658#if ENABLE(GPU_PROCESS)
    659 - (void)_gpuProcessCrashed
     659- (void)_gpuProcessDidExit
    660660{
    661661#if HAVE(VISIBILITY_PROPAGATION_VIEW)
  • trunk/Tools/ChangeLog

    r276139 r276148  
     12021-04-16  Chris Dumez  <cdumez@apple.com>
     2
     3        Exit the GPUProcess when under memory pressure if it is not being used
     4        https://bugs.webkit.org/show_bug.cgi?id=224556
     5
     6        Reviewed by Darin Adler.
     7
     8        Add API test coverage.
     9
     10        * TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm:
     11        (runMemoryPressureExitTest):
     12        (TEST):
     13
    1142021-04-16  Aakash Jain  <aakash_jain@apple.com>
    215
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm

    r275887 r276148  
    3535#import <WebKit/WKWebViewConfiguration.h>
    3636#import <WebKit/WKWebViewPrivate.h>
     37#import <notify.h>
     38#import <wtf/Function.h>
    3739#import <wtf/RetainPtr.h>
    3840
     
    491493    TestWebKitAPI::Util::run(&done);
    492494}
     495
     496static void runMemoryPressureExitTest(Function<void(WKWebView *)>&& loadTestPageSynchronously)
     497{
     498    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     499    WKPreferencesSetBoolValueForKeyForTesting((__bridge WKPreferencesRef)[configuration preferences], true, WKStringCreateWithUTF8CString("UseGPUProcessForMediaEnabled"));
     500    WKPreferencesSetBoolValueForKeyForTesting((__bridge WKPreferencesRef)[configuration preferences], true, WKStringCreateWithUTF8CString("CaptureVideoInGPUProcessEnabled"));
     501    WKPreferencesSetBoolValueForKeyForTesting((__bridge WKPreferencesRef)[configuration preferences], true, WKStringCreateWithUTF8CString("UseGPUProcessForCanvasRenderingEnabled"));
     502    WKPreferencesSetBoolValueForKeyForTesting((__bridge WKPreferencesRef)[configuration preferences], false, WKStringCreateWithUTF8CString("UseGPUProcessForDOMRenderingEnabled"));
     503
     504    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 400, 400) configuration:configuration.get()]);
     505    loadTestPageSynchronously(webView.get());
     506
     507    // A GPUProcess should get launched.
     508    while (![configuration.get().processPool _gpuProcessIdentifier])
     509        TestWebKitAPI::Util::sleep(0.1);
     510    auto gpuProcessPID = [configuration.get().processPool _gpuProcessIdentifier];
     511
     512    // Simulate memory pressure (notifyutil -p org.WebKit.lowMemory).
     513    notify_post("org.WebKit.lowMemory");
     514
     515    // Make sure the GPUProcess does not exit since it is still needed.
     516    TestWebKitAPI::Util::sleep(0.5);
     517    EXPECT_EQ(gpuProcessPID, [configuration.get().processPool _gpuProcessIdentifier]);
     518
     519    // Navigate to another page that no longer requires the GPUProcess.
     520    [webView synchronouslyLoadTestPageNamed:@"simple"];
     521
     522    // The GPUProcess should exit on memory pressure.
     523    do {
     524        // Simulate memory pressure (notifyutil -p org.WebKit.lowMemory).
     525        notify_post("org.WebKit.lowMemory");
     526        TestWebKitAPI::Util::sleep(0.1);
     527    } while ([configuration.get().processPool _gpuProcessIdentifier]);
     528
     529    // The GPUProcess should not relaunch.
     530    TestWebKitAPI::Util::sleep(0.5);
     531    EXPECT_EQ(0, [configuration.get().processPool _gpuProcessIdentifier]);
     532}
     533
     534TEST(GPUProcess, ExitsUnderMemoryPressureCanvasCase)
     535{
     536    runMemoryPressureExitTest([](WKWebView *webView) {
     537        [webView synchronouslyLoadHTMLString:testCanvasPage];
     538
     539        __block bool done = false;
     540        [webView evaluateJavaScript:@"context.fillStyle = '#00FF00'; context.fillRect(0, 0, 400, 400);" completionHandler:^(id result, NSError *error) {
     541            EXPECT_TRUE(!error);
     542            done = true;
     543        }];
     544        TestWebKitAPI::Util::run(&done);
     545        done = false;
     546        [webView evaluateJavaScript:@"context.getImageData(0, 0, 400, 400).width" completionHandler:^(id result, NSError *error) {
     547            EXPECT_TRUE(!error);
     548            done = true;
     549        }];
     550        TestWebKitAPI::Util::run(&done);
     551    });
     552}
     553
     554TEST(GPUProcess, ExitsUnderMemoryPressureVideoCase)
     555{
     556    runMemoryPressureExitTest([](WKWebView *webView) {
     557        [webView synchronouslyLoadTestPageNamed:@"large-videos-with-audio"];
     558
     559        __block bool done = false;
     560        [webView evaluateJavaScript:@"document.getElementsByTagName('video')[0].play() && true" completionHandler:^(id result, NSError *error) {
     561            EXPECT_TRUE(!error);
     562            done = true;
     563        }];
     564        TestWebKitAPI::Util::run(&done);
     565    });
     566}
     567
     568TEST(GPUProcess, ExitsUnderMemoryPressureWebAudioCase)
     569{
     570    runMemoryPressureExitTest([](WKWebView *webView) {
     571        [webView synchronouslyLoadTestPageNamed:@"audio-context-playing"];
     572
     573        // evaluateJavaScript gives us the user gesture we need to reliably start audio playback on all platforms.
     574        __block bool done = false;
     575        [webView evaluateJavaScript:@"startPlaying()" completionHandler:^(id result, NSError *error) {
     576            EXPECT_TRUE(!error);
     577            done = true;
     578        }];
     579        TestWebKitAPI::Util::run(&done);
     580    });
     581}
Note: See TracChangeset for help on using the changeset viewer.