Title: [240725] trunk
Revision
240725
Author
[email protected]
Date
2019-01-30 12:27:37 -0800 (Wed, 30 Jan 2019)

Log Message

Regression(PSON) Load hang can occur on history navigation
https://bugs.webkit.org/show_bug.cgi?id=194030
<rdar://problem/47656939>

Reviewed by Antti Koivisto.

Source/WebKit:

We do not support having more than one WebPage in a WebProcess with the same page ID. As a result,
if we decide to reuse an existing process on process-swap, we need to make sure that we either use
its suspended page (when possible, meaning that it is for the right HistoryItem / page) or we need
make sure we drop the existing suspended page for this process / pagePID combination, so that the
WebPage on WebProcess side gets closed before we attempt to do the new load.

We were doing this correctly in 2 places in WebProcessPool::processForNavigationInternal() but failed
to do so in a third place, when doing back to a HistoryItem which does not have a SuspendedPage but
whose process is still alive (presumably because it is kept alive by another suspended page). This
patch fixes this third place to remove any suspended page in the process for the current page before
reusing the process. An assertion was also added to the call site in
WebPageProxy::receivedNavigationPolicyDecision() to make sure we catch this more easily in the
future.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::receivedNavigationPolicyDecision):
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigationInternal):
(WebKit::WebProcessPool::removeAllSuspendedPagesForPage):
(WebKit::WebProcessPool::hasSuspendedPageFor const):
* UIProcess/WebProcessPool.h:

Tools:

Add API test coverage.

* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (240724 => 240725)


--- trunk/Source/WebKit/ChangeLog	2019-01-30 20:08:16 UTC (rev 240724)
+++ trunk/Source/WebKit/ChangeLog	2019-01-30 20:27:37 UTC (rev 240725)
@@ -1,3 +1,33 @@
+2019-01-30  Chris Dumez  <[email protected]>
+
+        Regression(PSON) Load hang can occur on history navigation
+        https://bugs.webkit.org/show_bug.cgi?id=194030
+        <rdar://problem/47656939>
+
+        Reviewed by Antti Koivisto.
+
+        We do not support having more than one WebPage in a WebProcess with the same page ID. As a result,
+        if we decide to reuse an existing process on process-swap, we need to make sure that we either use
+        its suspended page (when possible, meaning that it is for the right HistoryItem / page) or we need
+        make sure we drop the existing suspended page for this process / pagePID combination, so that the
+        WebPage on WebProcess side gets closed before we attempt to do the new load.
+
+        We were doing this correctly in 2 places in WebProcessPool::processForNavigationInternal() but failed
+        to do so in a third place, when doing back to a HistoryItem which does not have a SuspendedPage but
+        whose process is still alive (presumably because it is kept alive by another suspended page). This
+        patch fixes this third place to remove any suspended page in the process for the current page before
+        reusing the process. An assertion was also added to the call site in
+        WebPageProxy::receivedNavigationPolicyDecision() to make sure we catch this more easily in the
+        future.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::receivedNavigationPolicyDecision):
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::processForNavigationInternal):
+        (WebKit::WebProcessPool::removeAllSuspendedPagesForPage):
+        (WebKit::WebProcessPool::hasSuspendedPageFor const):
+        * UIProcess/WebProcessPool.h:
+
 2019-01-30  Carlos Garcia Campos  <[email protected]>
 
         [GTK][Wayland] REGRESSION(r240712): Clear the GL context if it's the current one on dispose

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (240724 => 240725)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2019-01-30 20:08:16 UTC (rev 240724)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2019-01-30 20:27:37 UTC (rev 240725)
@@ -2722,6 +2722,11 @@
         if (!shouldProcessSwap)
             return;
 
+        // FIXME: Architecturally we do not currently support multiple WebPage's with the same ID in a given WebProcess.
+        // In the case where the destination WebProcess has a SuspendedPageProxy for this WebPage, we should have thrown
+        // it away to support WebProcess re-use.
+        ASSERT(destinationSuspendedPage || !process().processPool().hasSuspendedPageFor(processForNavigation, this));
+
         auto suspendedPage = destinationSuspendedPage ? process().processPool().takeSuspendedPage(*destinationSuspendedPage) : nullptr;
         if (suspendedPage && suspendedPage->failedToSuspend())
             suspendedPage = nullptr;

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (240724 => 240725)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2019-01-30 20:08:16 UTC (rev 240724)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2019-01-30 20:27:37 UTC (rev 240725)
@@ -2190,8 +2190,14 @@
             });
         }
 
-        if (auto* process = WebProcessProxy::processForIdentifier(targetItem->itemID().processIdentifier))
-            return completionHandler(*process, nullptr, "Using target back/forward item's process"_s);
+        if (RefPtr<WebProcessProxy> process = WebProcessProxy::processForIdentifier(targetItem->itemID().processIdentifier)) {
+            // FIXME: Architecturally we do not currently support multiple WebPage's with the same ID in a given WebProcess.
+            // In the case where this WebProcess has a SuspendedPageProxy for this WebPage, we can throw it away to support
+            // WebProcess re-use.
+            removeAllSuspendedPagesForPage(page, process.get());
+
+            return completionHandler(process.releaseNonNull(), nullptr, "Using target back/forward item's process"_s);
+        }
     }
 
     if (navigation.treatAsSameOriginNavigation())
@@ -2225,9 +2231,7 @@
                 // In the case where this WebProcess has a SuspendedPageProxy for this WebPage, we can throw it away to support
                 // WebProcess re-use.
                 // In the future it would be great to refactor-out this limitation (https://bugs.webkit.org/show_bug.cgi?id=191166).
-                m_suspendedPages.removeAllMatching([&](auto& suspendedPage) {
-                    return &suspendedPage->page() == &page && &suspendedPage->process() == process;
-                });
+                removeAllSuspendedPagesForPage(page, process);
 
                 return completionHandler(makeRef(*process), nullptr, reason);
             }
@@ -2263,10 +2267,10 @@
     m_suspendedPages.append(WTFMove(suspendedPage));
 }
 
-void WebProcessPool::removeAllSuspendedPagesForPage(WebPageProxy& page)
+void WebProcessPool::removeAllSuspendedPagesForPage(WebPageProxy& page, WebProcessProxy* process)
 {
-    m_suspendedPages.removeAllMatching([&page](auto& suspendedPage) {
-        return &suspendedPage->page() == &page;
+    m_suspendedPages.removeAllMatching([&page, process](auto& suspendedPage) {
+        return &suspendedPage->page() == &page && (!process || &suspendedPage->process() == process);
     });
 }
 
@@ -2294,10 +2298,10 @@
         m_suspendedPages.remove(it);
 }
 
-bool WebProcessPool::hasSuspendedPageFor(WebProcessProxy& process) const
+bool WebProcessPool::hasSuspendedPageFor(WebProcessProxy& process, WebPageProxy* page) const
 {
-    return m_suspendedPages.findIf([&process](auto& suspendedPage) {
-        return &suspendedPage->process() == &process;
+    return m_suspendedPages.findIf([&process, page](auto& suspendedPage) {
+        return &suspendedPage->process() == &process && (!page || &suspendedPage->page() == page);
     }) != m_suspendedPages.end();
 }
 

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (240724 => 240725)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.h	2019-01-30 20:08:16 UTC (rev 240724)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h	2019-01-30 20:27:37 UTC (rev 240725)
@@ -446,11 +446,11 @@
 
     // SuspendedPageProxy management.
     void addSuspendedPage(std::unique_ptr<SuspendedPageProxy>&&);
-    void removeAllSuspendedPagesForPage(WebPageProxy&);
+    void removeAllSuspendedPagesForPage(WebPageProxy&, WebProcessProxy* = nullptr);
     void closeFailedSuspendedPagesForPage(WebPageProxy&);
     std::unique_ptr<SuspendedPageProxy> takeSuspendedPage(SuspendedPageProxy&);
     void removeSuspendedPage(SuspendedPageProxy&);
-    bool hasSuspendedPageFor(WebProcessProxy&) const;
+    bool hasSuspendedPageFor(WebProcessProxy&, WebPageProxy* = nullptr) const;
     unsigned maxSuspendedPageCount() const { return m_maxSuspendedPageCount; }
 
     void didReachGoodTimeToPrewarm();

Modified: trunk/Tools/ChangeLog (240724 => 240725)


--- trunk/Tools/ChangeLog	2019-01-30 20:08:16 UTC (rev 240724)
+++ trunk/Tools/ChangeLog	2019-01-30 20:27:37 UTC (rev 240725)
@@ -1,3 +1,15 @@
+2019-01-30  Chris Dumez  <[email protected]>
+
+        Regression(PSON) Load hang can occur on history navigation
+        https://bugs.webkit.org/show_bug.cgi?id=194030
+        <rdar://problem/47656939>
+
+        Reviewed by Antti Koivisto.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+
 2019-01-30  Zalan Bujtas  <[email protected]>
 
         [LFC] Expand tests coverage.

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm (240724 => 240725)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2019-01-30 20:08:16 UTC (rev 240724)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2019-01-30 20:27:37 UTC (rev 240725)
@@ -2311,6 +2311,64 @@
     EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [backForwardList.forwardList[1].URL absoluteString]);
 }
 
+TEST(ProcessSwap, GoToSecondItemInBackHistory)
+{
+    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
+    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
+    auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
+
+    auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [webViewConfiguration setProcessPool:processPool.get()];
+    auto handler = adoptNS([[PSONScheme alloc] init]);
+    [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:withSubframesTestBytes];
+    [handler addMappingFromURLString:@"pson://www.webkit.org/main2.html" toData:withSubframesTestBytes];
+    [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:withSubframesTestBytes];
+    [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+    auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:delegate.get()];
+
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto webkitPID = [webView _webProcessIdentifier];
+
+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
+
+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto applePID = [webView _webProcessIdentifier];
+    EXPECT_NE(webkitPID, applePID);
+
+    [webView goToBackForwardListItem:webView.get().backForwardList.backList[0]];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
+    EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView URL] absoluteString]);
+
+    [webView goToBackForwardListItem:webView.get().backForwardList.forwardList[1]];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
+    EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]);
+}
+
 static const char* keepNavigatingFrameBytes = R"PSONRESOURCE(
 <body>
 <iframe id="testFrame1" src=""
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to