Sometimes RemoteLayerBackingStore ends up non-volatile while the process is suspended
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Feb 2015 02:30:11 +0000 (02:30 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Feb 2015 02:30:11 +0000 (02:30 +0000)
<rdar://problem/19842957>
https://bugs.webkit.org/show_bug.cgi?id=141675

Reviewed by Simon Fraser.

Previously, it was possible to get a layer tree flush in between the
process suspension cleanup code making surfaces volatile and the process
actually being suspended (it was racy because the suspension requires
a few IPC round trips). Depending on how far through the flush we got,
we could sometimes end up either making new non-volatile backing store,
or switching some recently-made-volatile backing store back to non-volatile.
We don't want to have any non-volatile backing store while suspended.

* UIProcess/ProcessThrottler.cpp:
(WebKit::ProcessThrottler::updateAssertion):
Inform the WebProcess when it's going from suspended to runnable state.

* UIProcess/WebProcessProxy.cpp:
(WebKit::WebProcessProxy::sendProcessDidResume):
* UIProcess/WebProcessProxy.h:
Forward the message along.

* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::processWillSuspend):
(WebKit::WebProcess::cancelProcessWillSuspend):
(WebKit::WebProcess::setAllLayerTreeStatesFrozen):
(WebKit::WebProcess::processDidResume):
Freeze all of this process' pages' layer trees when we start trying to suspend,
and un-freeze them when either suspension is cancelled or we resume.

* WebProcess/WebProcess.h:
* WebProcess/WebProcess.messages.in:

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

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/ProcessThrottler.cpp
Source/WebKit2/UIProcess/WebProcessProxy.cpp
Source/WebKit2/UIProcess/WebProcessProxy.h
Source/WebKit2/WebProcess/WebProcess.cpp
Source/WebKit2/WebProcess/WebProcess.h
Source/WebKit2/WebProcess/WebProcess.messages.in

index 42ada8997c02febd0a9dadecb7f64eae84d704cf..c2734928c9e96d7229c2c9139549f2f09a4fa79c 100644 (file)
@@ -1,3 +1,39 @@
+2015-02-16  Tim Horton  <timothy_horton@apple.com>
+
+        Sometimes RemoteLayerBackingStore ends up non-volatile while the process is suspended
+        <rdar://problem/19842957>
+        https://bugs.webkit.org/show_bug.cgi?id=141675
+
+        Reviewed by Simon Fraser.
+
+        Previously, it was possible to get a layer tree flush in between the
+        process suspension cleanup code making surfaces volatile and the process
+        actually being suspended (it was racy because the suspension requires
+        a few IPC round trips). Depending on how far through the flush we got,
+        we could sometimes end up either making new non-volatile backing store,
+        or switching some recently-made-volatile backing store back to non-volatile.
+        We don't want to have any non-volatile backing store while suspended.
+
+        * UIProcess/ProcessThrottler.cpp:
+        (WebKit::ProcessThrottler::updateAssertion):
+        Inform the WebProcess when it's going from suspended to runnable state.
+
+        * UIProcess/WebProcessProxy.cpp:
+        (WebKit::WebProcessProxy::sendProcessDidResume):
+        * UIProcess/WebProcessProxy.h:
+        Forward the message along.
+
+        * WebProcess/WebProcess.cpp:
+        (WebKit::WebProcess::processWillSuspend):
+        (WebKit::WebProcess::cancelProcessWillSuspend):
+        (WebKit::WebProcess::setAllLayerTreeStatesFrozen):
+        (WebKit::WebProcess::processDidResume):
+        Freeze all of this process' pages' layer trees when we start trying to suspend,
+        and un-freeze them when either suspension is cancelled or we resume.
+
+        * WebProcess/WebProcess.h:
+        * WebProcess/WebProcess.messages.in:
+
 2015-02-16  Tim Horton  <timothy_horton@apple.com>
 
         Adopt CAMachPort-as-layer-contents
index ef981ac1d36f2e20a64b2472fa20187032893ac4..46cf5d77c42f722e8605382a231bc72824627248 100644 (file)
@@ -71,10 +71,15 @@ void ProcessThrottler::updateAssertion()
         m_assertion->setState(AssertionState::Background);
         return;
     }
+    
+    bool shouldBeRunnable = m_foregroundCounter.value() || m_backgroundCounter.value();
 
     // If we're currently waiting for the Web process to do suspension cleanup, but no longer need to be suspended, tell the Web process to cancel the cleanup.
-    if (m_suspendTimer.isActive() && (m_foregroundCounter.value() || m_backgroundCounter.value()))
+    if (m_suspendTimer.isActive() && shouldBeRunnable)
         m_process->sendCancelProcessWillSuspend();
+    
+    if (m_assertion && m_assertion->state() == AssertionState::Suspended && shouldBeRunnable)
+        m_process->sendProcessDidResume();
 
     updateAssertionNow();
 }
index dd0064804e8074f2367957564a8682a114185fd6..c7ef8a2af613fa4b4c6922aa8b1365d0366077bf 100644 (file)
@@ -762,6 +762,12 @@ void WebProcessProxy::sendCancelProcessWillSuspend()
         send(Messages::WebProcess::CancelProcessWillSuspend(), 0);
 }
     
+void WebProcessProxy::sendProcessDidResume()
+{
+    if (canSendMessage())
+        send(Messages::WebProcess::ProcessDidResume(), 0);
+}
+    
 void WebProcessProxy::processReadyToSuspend()
 {
     m_throttler->processReadyToSuspend();
index 5760ddd2cfbe282b83ddb2d8e2e468acf191b4cf..b6af63ada337db7e3879d94fc4aaae87dc4c71b6 100644 (file)
@@ -140,6 +140,7 @@ public:
     void processReadyToSuspend();
     void sendCancelProcessWillSuspend();
     void didCancelProcessSuspension();
+    void sendProcessDidResume();
 
     void setIsHoldingLockedFiles(bool);
 
index 8a4423f140f4f265c41186dd05114ebc375a656c..a8bc2c9d96720703382340ca2493200f7f54f638 100644 (file)
@@ -1164,6 +1164,7 @@ void WebProcess::resetAllGeolocationPermissions()
 void WebProcess::processWillSuspend()
 {
     memoryPressureHandler().releaseMemory(true);
+    setAllLayerTreeStatesFrozen(true);
 
     if (!markAllLayersVolatileIfPossible())
         m_processSuspensionCleanupTimer.startRepeating(std::chrono::milliseconds(20));
@@ -1173,6 +1174,8 @@ void WebProcess::processWillSuspend()
 
 void WebProcess::cancelProcessWillSuspend()
 {
+    setAllLayerTreeStatesFrozen(false);
+
     // If we've already finished cleaning up and sent ProcessReadyToSuspend, we
     // shouldn't send DidCancelProcessSuspension; the UI process strictly expects one or the other.
     if (!m_processSuspensionCleanupTimer.isActive())
@@ -1193,6 +1196,14 @@ bool WebProcess::markAllLayersVolatileIfPossible()
     return successfullyMarkedAllLayersVolatile;
 }
 
+void WebProcess::setAllLayerTreeStatesFrozen(bool frozen)
+{
+    for (auto& page : m_pageMap.values()) {
+        if (auto drawingArea = page->drawingArea())
+            drawingArea->setLayerTreeStateIsFrozen(frozen);
+    }
+}
+
 void WebProcess::processSuspensionCleanupTimerFired()
 {
     if (markAllLayersVolatileIfPossible()) {
@@ -1200,6 +1211,11 @@ void WebProcess::processSuspensionCleanupTimerFired()
         parentProcessConnection()->send(Messages::WebProcessProxy::ProcessReadyToSuspend(), 0);
     }
 }
+    
+void WebProcess::processDidResume()
+{
+    setAllLayerTreeStatesFrozen(false);
+}
 
 void WebProcess::pageDidEnterWindow(uint64_t pageID)
 {
index 9afc729b15818a4fc63f43ea71d2369a1c5a4bf5..d41f15042ab3b7a01e6fedc03a11c46d97358cd8 100644 (file)
@@ -181,7 +181,9 @@ public:
     void processWillSuspend();
     void cancelProcessWillSuspend();
     bool markAllLayersVolatileIfPossible();
+    void setAllLayerTreeStatesFrozen(bool);
     void processSuspensionCleanupTimerFired();
+    void processDidResume();
 
 #if PLATFORM(IOS)
     void resetAllGeolocationPermissions();
index 2122846789bf261d5db34e2e2225678638bda2f9..bcf50576c295ca4289d1ff03a31e864e5a976dab 100644 (file)
@@ -96,4 +96,5 @@ messages -> WebProcess LegacyReceiver {
 
     ProcessWillSuspend()
     CancelProcessWillSuspend()
+    ProcessDidResume()
 }