<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[282229] branches/safari-612-branch</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/282229">282229</a></dd>
<dt>Author</dt> <dd>repstein@apple.com</dd>
<dt>Date</dt> <dd>2021-09-09 11:04:35 -0700 (Thu, 09 Sep 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>Cherry-pick <a href="http://trac.webkit.org/projects/webkit/changeset/282218">r282218</a>. rdar://problem/82931375

    Implement a WebProcess cap
    https://bugs.webkit.org/show_bug.cgi?id=230067
    <rdar://79479244>

    Reviewed by Geoffrey Garen.

    Source/WebKit:

    Implement a WebProcess cap to avoid getting into a state where we run out of resources and crash in various ways.
    The current limit is 400 and can be changed via an SPI. The limit is per UIProcess (not per process pool).
    When we try and launch a new WebProcess and the limit has been reached, we terminate the least recently used
    WebProcess to avoid going over the limit.

    * Shared/ProcessTerminationReason.h:
    * UIProcess/API/C/WKAPICast.h:
    (WebKit::toAPI):
    * UIProcess/API/Cocoa/WKProcessPool.mm:
    (+[WKProcessPool _setWebProcessCountLimit:]):
    * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
    * UIProcess/Cocoa/NavigationState.mm:
    (WebKit::wkProcessTerminationReason):
    * UIProcess/WebPageProxy.cpp:
    (WebKit::WebPageProxy::loadRequestWithNavigationShared):
    (WebKit::WebPageProxy::loadFile):
    (WebKit::WebPageProxy::loadDataWithNavigationShared):
    (WebKit::WebPageProxy::loadSimulatedRequest):
    (WebKit::WebPageProxy::loadAlternateHTML):
    (WebKit::WebPageProxy::loadWebArchiveData):
    (WebKit::WebPageProxy::reload):
    (WebKit::WebPageProxy::goToBackForwardItem):
    (WebKit::shouldReloadAfterProcessTermination):
    * UIProcess/WebProcessProxy.cpp:
    (WebKit::WebProcessProxy::setProcessCountLimit):
    (WebKit::WebProcessProxy::create):
    (WebKit::WebProcessProxy::~WebProcessProxy):
    (WebKit::WebProcessProxy::addProvisionalPageProxy):
    (WebKit::WebProcessProxy::addExistingWebPage):
    (WebKit::WebProcessProxy::processDidTerminateOrFailedToLaunch):
    (WebKit::WebProcessProxy::establishServiceWorkerContext):
    (WebKit::WebProcessProxy::markProcessAsRecentlyUsed):
    * UIProcess/WebProcessProxy.h:

    Tools:

    Add API test coverage.

    * TestWebKitAPI/Tests/WebKitCocoa/WebContentProcessDidTerminate.mm:
    (TEST):

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282218 268f45cc-cd09-0410-ab3c-d52691b4dbfc</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchessafari612branchSourceWebKitChangeLog">branches/safari-612-branch/Source/WebKit/ChangeLog</a></li>
<li><a href="#branchessafari612branchSourceWebKitSharedProcessTerminationReasonh">branches/safari-612-branch/Source/WebKit/Shared/ProcessTerminationReason.h</a></li>
<li><a href="#branchessafari612branchSourceWebKitUIProcessAPICWKAPICasth">branches/safari-612-branch/Source/WebKit/UIProcess/API/C/WKAPICast.h</a></li>
<li><a href="#branchessafari612branchSourceWebKitUIProcessAPICocoaWKProcessPoolmm">branches/safari-612-branch/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm</a></li>
<li><a href="#branchessafari612branchSourceWebKitUIProcessAPICocoaWKProcessPoolPrivateh">branches/safari-612-branch/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h</a></li>
<li><a href="#branchessafari612branchSourceWebKitUIProcessCocoaNavigationStatemm">branches/safari-612-branch/Source/WebKit/UIProcess/Cocoa/NavigationState.mm</a></li>
<li><a href="#branchessafari612branchSourceWebKitUIProcessWebPageProxycpp">branches/safari-612-branch/Source/WebKit/UIProcess/WebPageProxy.cpp</a></li>
<li><a href="#branchessafari612branchSourceWebKitUIProcessWebProcessPoolcpp">branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessPool.cpp</a></li>
<li><a href="#branchessafari612branchSourceWebKitUIProcessWebProcessProxycpp">branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessProxy.cpp</a></li>
<li><a href="#branchessafari612branchSourceWebKitUIProcessWebProcessProxyh">branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessProxy.h</a></li>
<li><a href="#branchessafari612branchToolsChangeLog">branches/safari-612-branch/Tools/ChangeLog</a></li>
<li><a href="#branchessafari612branchToolsTestWebKitAPITestsWebKitCocoaWebContentProcessDidTerminatemm">branches/safari-612-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebContentProcessDidTerminate.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchessafari612branchSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKit/ChangeLog (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKit/ChangeLog       2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Source/WebKit/ChangeLog  2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -1,5 +1,102 @@
</span><span class="cx"> 2021-09-09  Russell Epstein  <repstein@apple.com>
</span><span class="cx"> 
</span><ins>+        Cherry-pick r282218. rdar://problem/82931375
+
+    Implement a WebProcess cap
+    https://bugs.webkit.org/show_bug.cgi?id=230067
+    <rdar://79479244>
+    
+    Reviewed by Geoffrey Garen.
+    
+    Source/WebKit:
+    
+    Implement a WebProcess cap to avoid getting into a state where we run out of resources and crash in various ways.
+    The current limit is 400 and can be changed via an SPI. The limit is per UIProcess (not per process pool).
+    When we try and launch a new WebProcess and the limit has been reached, we terminate the least recently used
+    WebProcess to avoid going over the limit.
+    
+    * Shared/ProcessTerminationReason.h:
+    * UIProcess/API/C/WKAPICast.h:
+    (WebKit::toAPI):
+    * UIProcess/API/Cocoa/WKProcessPool.mm:
+    (+[WKProcessPool _setWebProcessCountLimit:]):
+    * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+    * UIProcess/Cocoa/NavigationState.mm:
+    (WebKit::wkProcessTerminationReason):
+    * UIProcess/WebPageProxy.cpp:
+    (WebKit::WebPageProxy::loadRequestWithNavigationShared):
+    (WebKit::WebPageProxy::loadFile):
+    (WebKit::WebPageProxy::loadDataWithNavigationShared):
+    (WebKit::WebPageProxy::loadSimulatedRequest):
+    (WebKit::WebPageProxy::loadAlternateHTML):
+    (WebKit::WebPageProxy::loadWebArchiveData):
+    (WebKit::WebPageProxy::reload):
+    (WebKit::WebPageProxy::goToBackForwardItem):
+    (WebKit::shouldReloadAfterProcessTermination):
+    * UIProcess/WebProcessProxy.cpp:
+    (WebKit::WebProcessProxy::setProcessCountLimit):
+    (WebKit::WebProcessProxy::create):
+    (WebKit::WebProcessProxy::~WebProcessProxy):
+    (WebKit::WebProcessProxy::addProvisionalPageProxy):
+    (WebKit::WebProcessProxy::addExistingWebPage):
+    (WebKit::WebProcessProxy::processDidTerminateOrFailedToLaunch):
+    (WebKit::WebProcessProxy::establishServiceWorkerContext):
+    (WebKit::WebProcessProxy::markProcessAsRecentlyUsed):
+    * UIProcess/WebProcessProxy.h:
+    
+    Tools:
+    
+    Add API test coverage.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/WebContentProcessDidTerminate.mm:
+    (TEST):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282218 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-09-09  Chris Dumez  <cdumez@apple.com>
+
+            Implement a WebProcess cap
+            https://bugs.webkit.org/show_bug.cgi?id=230067
+            <rdar://79479244>
+
+            Reviewed by Geoffrey Garen.
+
+            Implement a WebProcess cap to avoid getting into a state where we run out of resources and crash in various ways.
+            The current limit is 400 and can be changed via an SPI. The limit is per UIProcess (not per process pool).
+            When we try and launch a new WebProcess and the limit has been reached, we terminate the least recently used
+            WebProcess to avoid going over the limit.
+
+            * Shared/ProcessTerminationReason.h:
+            * UIProcess/API/C/WKAPICast.h:
+            (WebKit::toAPI):
+            * UIProcess/API/Cocoa/WKProcessPool.mm:
+            (+[WKProcessPool _setWebProcessCountLimit:]):
+            * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+            * UIProcess/Cocoa/NavigationState.mm:
+            (WebKit::wkProcessTerminationReason):
+            * UIProcess/WebPageProxy.cpp:
+            (WebKit::WebPageProxy::loadRequestWithNavigationShared):
+            (WebKit::WebPageProxy::loadFile):
+            (WebKit::WebPageProxy::loadDataWithNavigationShared):
+            (WebKit::WebPageProxy::loadSimulatedRequest):
+            (WebKit::WebPageProxy::loadAlternateHTML):
+            (WebKit::WebPageProxy::loadWebArchiveData):
+            (WebKit::WebPageProxy::reload):
+            (WebKit::WebPageProxy::goToBackForwardItem):
+            (WebKit::shouldReloadAfterProcessTermination):
+            * UIProcess/WebProcessProxy.cpp:
+            (WebKit::WebProcessProxy::setProcessCountLimit):
+            (WebKit::WebProcessProxy::create):
+            (WebKit::WebProcessProxy::~WebProcessProxy):
+            (WebKit::WebProcessProxy::addProvisionalPageProxy):
+            (WebKit::WebProcessProxy::addExistingWebPage):
+            (WebKit::WebProcessProxy::processDidTerminateOrFailedToLaunch):
+            (WebKit::WebProcessProxy::establishServiceWorkerContext):
+            (WebKit::WebProcessProxy::markProcessAsRecentlyUsed):
+            * UIProcess/WebProcessProxy.h:
+
+2021-09-09  Russell Epstein  <repstein@apple.com>
+
</ins><span class="cx">         Cherry-pick r282174. rdar://problem/82931245
</span><span class="cx"> 
</span><span class="cx">     Remove responsiveness timer in NetworkProcessProxy::getNetworkProcessConnection
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitSharedProcessTerminationReasonh"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKit/Shared/ProcessTerminationReason.h (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKit/Shared/ProcessTerminationReason.h       2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Source/WebKit/Shared/ProcessTerminationReason.h  2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> enum class ProcessTerminationReason {
</span><span class="cx">     ExceededMemoryLimit,
</span><span class="cx">     ExceededCPULimit,
</span><ins>+    ExceededProcessCountLimit,
</ins><span class="cx">     RequestedByClient,
</span><span class="cx">     Crash,
</span><span class="cx">     NavigationSwap,
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitUIProcessAPICWKAPICasth"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKit/UIProcess/API/C/WKAPICast.h (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKit/UIProcess/API/C/WKAPICast.h     2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Source/WebKit/UIProcess/API/C/WKAPICast.h        2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -243,6 +243,7 @@
</span><span class="cx">         FALLTHROUGH;
</span><span class="cx">     case ProcessTerminationReason::RequestedByClient:
</span><span class="cx">         return kWKProcessTerminationReasonRequestedByClient;
</span><ins>+    case ProcessTerminationReason::ExceededProcessCountLimit:
</ins><span class="cx">     case ProcessTerminationReason::RequestedByNetworkProcess:
</span><span class="cx">     case ProcessTerminationReason::RequestedByGPUProcess:
</span><span class="cx">     case ProcessTerminationReason::Crash:
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitUIProcessAPICocoaWKProcessPoolmm"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm    2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm       2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -565,6 +565,11 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>++ (void)_setWebProcessCountLimit:(unsigned)limit
+{
+    WebKit::WebProcessProxy::setProcessCountLimit(limit);
+}
+
</ins><span class="cx"> - (void)_garbageCollectJavaScriptObjectsForTesting
</span><span class="cx"> {
</span><span class="cx">     _processPool->garbageCollectJavaScriptObjects();
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitUIProcessAPICocoaWKProcessPoolPrivateh"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h      2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h 2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -73,6 +73,8 @@
</span><span class="cx"> + (NSURL *)_websiteDataURLForContainerWithURL:(NSURL *)containerURL bundleIdentifierIfNotInContainer:(NSString *)bundleIdentifier;
</span><span class="cx"> + (pid_t)_webAuthnProcessIdentifier WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
</span><span class="cx"> 
</span><ins>++ (void)_setWebProcessCountLimit:(unsigned)limit WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
</ins><span class="cx"> - (void)_warmInitialProcess WK_API_AVAILABLE(macos(10.12), ios(10.0));
</span><span class="cx"> - (void)_automationCapabilitiesDidChange WK_API_AVAILABLE(macos(10.12), ios(10.0));
</span><span class="cx"> - (void)_setAutomationSession:(_WKAutomationSession *)automationSession WK_API_AVAILABLE(macos(10.12), ios(10.0));
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitUIProcessCocoaNavigationStatemm"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKit/UIProcess/Cocoa/NavigationState.mm (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKit/UIProcess/Cocoa/NavigationState.mm      2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Source/WebKit/UIProcess/Cocoa/NavigationState.mm 2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -1060,6 +1060,7 @@
</span><span class="cx">         FALLTHROUGH;
</span><span class="cx">     case ProcessTerminationReason::RequestedByClient:
</span><span class="cx">         return _WKProcessTerminationReasonRequestedByClient;
</span><ins>+    case ProcessTerminationReason::ExceededProcessCountLimit:
</ins><span class="cx">     case ProcessTerminationReason::RequestedByNetworkProcess:
</span><span class="cx">     case ProcessTerminationReason::RequestedByGPUProcess:
</span><span class="cx">     case ProcessTerminationReason::Crash:
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitUIProcessWebPageProxycpp"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKit/UIProcess/WebPageProxy.cpp (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKit/UIProcess/WebPageProxy.cpp      2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Source/WebKit/UIProcess/WebPageProxy.cpp 2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -1412,6 +1412,8 @@
</span><span class="cx"> 
</span><span class="cx">     navigation.setIsLoadedWithNavigationShared(true);
</span><span class="cx"> 
</span><ins>+    process->markProcessAsRecentlyUsed();
+
</ins><span class="cx">     if (!process->isLaunching() || !url.isLocalFile())
</span><span class="cx">         process->send(Messages::WebPage::LoadRequest(loadParameters), webPageID);
</span><span class="cx">     else
</span><span class="lines">@@ -1473,6 +1475,7 @@
</span><span class="cx">     maybeInitializeSandboxExtensionHandle(m_process, fileURL, resourceDirectoryURL, loadParameters.sandboxExtensionHandle, checkAssumedReadAccessToResourceURL);
</span><span class="cx">     addPlatformLoadParameters(m_process, loadParameters);
</span><span class="cx"> 
</span><ins>+    m_process->markProcessAsRecentlyUsed();
</ins><span class="cx">     if (m_process->isLaunching())
</span><span class="cx">         send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(loadParameters, resourceDirectoryURL, m_identifier, checkAssumedReadAccessToResourceURL));
</span><span class="cx">     else
</span><span class="lines">@@ -1532,6 +1535,7 @@
</span><span class="cx">     loadParameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain;
</span><span class="cx">     addPlatformLoadParameters(process, loadParameters);
</span><span class="cx"> 
</span><ins>+    process->markProcessAsRecentlyUsed();
</ins><span class="cx">     process->assumeReadAccessToBaseURL(*this, baseURL);
</span><span class="cx">     process->send(Messages::WebPage::LoadData(loadParameters), webPageID);
</span><span class="cx">     process->startResponsivenessTimer();
</span><span class="lines">@@ -1589,6 +1593,7 @@
</span><span class="cx"> 
</span><span class="cx">     addPlatformLoadParameters(m_process, loadParameters);
</span><span class="cx"> 
</span><ins>+    m_process->markProcessAsRecentlyUsed();
</ins><span class="cx">     m_process->assumeReadAccessToBaseURL(*this, baseURL);
</span><span class="cx">     m_process->send(Messages::WebPage::LoadSimulatedRequestAndResponse(loadParameters, simulatedResponse), m_webPageID);
</span><span class="cx">     m_process->startResponsivenessTimer();
</span><span class="lines">@@ -1632,6 +1637,7 @@
</span><span class="cx">     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
</span><span class="cx">     addPlatformLoadParameters(process(), loadParameters);
</span><span class="cx"> 
</span><ins>+    m_process->markProcessAsRecentlyUsed();
</ins><span class="cx">     m_process->assumeReadAccessToBaseURL(*this, baseURL.string());
</span><span class="cx">     m_process->assumeReadAccessToBaseURL(*this, unreachableURL.string());
</span><span class="cx">     send(Messages::WebPage::LoadAlternateHTML(loadParameters));
</span><span class="lines">@@ -1661,6 +1667,7 @@
</span><span class="cx">     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
</span><span class="cx">     addPlatformLoadParameters(process(), loadParameters);
</span><span class="cx"> 
</span><ins>+    m_process->markProcessAsRecentlyUsed();
</ins><span class="cx">     send(Messages::WebPage::LoadData(loadParameters));
</span><span class="cx">     m_process->startResponsivenessTimer();
</span><span class="cx"> }
</span><span class="lines">@@ -1736,6 +1743,7 @@
</span><span class="cx">     if (options.contains(WebCore::ReloadOption::DisableContentBlockers))
</span><span class="cx">         navigation->setUserContentExtensionsEnabled(false);
</span><span class="cx"> 
</span><ins>+    m_process->markProcessAsRecentlyUsed();
</ins><span class="cx">     send(Messages::WebPage::Reload(navigation->navigationID(), options.toRaw(), sandboxExtensionHandle));
</span><span class="cx">     m_process->startResponsivenessTimer();
</span><span class="cx"> 
</span><span class="lines">@@ -1814,6 +1822,7 @@
</span><span class="cx">     auto transaction = m_pageLoadState.transaction();
</span><span class="cx">     m_pageLoadState.setPendingAPIRequest(transaction, { navigation ? navigation->navigationID() : 0, item.url() });
</span><span class="cx"> 
</span><ins>+    m_process->markProcessAsRecentlyUsed();
</ins><span class="cx">     send(Messages::WebPage::GoToBackForwardItem(navigation ? navigation->navigationID() : 0, item.itemID(), frameLoadType, ShouldTreatAsContinuingLoad::No, std::nullopt, m_lastNavigationWasAppInitiated));
</span><span class="cx">     m_process->startResponsivenessTimer();
</span><span class="cx"> 
</span><span class="lines">@@ -5172,6 +5181,7 @@
</span><span class="cx"> 
</span><span class="cx"> void WebPageProxy::viewIsBecomingVisible()
</span><span class="cx"> {
</span><ins>+    m_process->markProcessAsRecentlyUsed();
</ins><span class="cx"> #if ENABLE(MEDIA_STREAM)
</span><span class="cx">     if (m_userMediaPermissionRequestManager)
</span><span class="cx">         m_userMediaPermissionRequestManager->viewIsBecomingVisible();
</span><span class="lines">@@ -7710,6 +7720,7 @@
</span><span class="cx">     case ProcessTerminationReason::RequestedByGPUProcess:
</span><span class="cx">     case ProcessTerminationReason::Crash:
</span><span class="cx">         return true;
</span><ins>+    case ProcessTerminationReason::ExceededProcessCountLimit:
</ins><span class="cx">     case ProcessTerminationReason::NavigationSwap:
</span><span class="cx">     case ProcessTerminationReason::RequestedByClient:
</span><span class="cx">         break;
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitUIProcessWebProcessPoolcpp"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessPool.cpp (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessPool.cpp    2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessPool.cpp       2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -866,6 +866,9 @@
</span><span class="cx">     if (m_prewarmedProcess)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    if (WebProcessProxy::hasReachedProcessCountLimit())
+        return;
+
</ins><span class="cx">     WEBPROCESSPOOL_RELEASE_LOG(PerformanceLogging, "prewarmProcess: Prewarming a WebProcess for performance");
</span><span class="cx">     createNewWebProcess(nullptr, WebProcessProxy::IsPrewarmed::Yes);
</span><span class="cx"> }
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitUIProcessWebProcessProxycpp"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessProxy.cpp (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessProxy.cpp   2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessProxy.cpp      2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -108,6 +108,25 @@
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> using namespace WebCore;
</span><span class="cx"> 
</span><ins>+static unsigned s_maxProcessCount { 400 };
+
+static ListHashSet<WebProcessProxy*>& liveProcessesLRU()
+{
+    ASSERT(RunLoop::isMain());
+    static NeverDestroyed<ListHashSet<WebProcessProxy*>> processes;
+    return processes;
+}
+
+void WebProcessProxy::setProcessCountLimit(unsigned limit)
+{
+    s_maxProcessCount = limit;
+}
+
+bool WebProcessProxy::hasReachedProcessCountLimit()
+{
+    return liveProcessesLRU().size() >= s_maxProcessCount;
+}
+
</ins><span class="cx"> static bool isMainThreadOrCheckDisabled()
</span><span class="cx"> {
</span><span class="cx"> #if PLATFORM(IOS_FAMILY)
</span><span class="lines">@@ -150,8 +169,17 @@
</span><span class="cx"> Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, IsPrewarmed isPrewarmed, ShouldLaunchProcess shouldLaunchProcess)
</span><span class="cx"> {
</span><span class="cx">     auto proxy = adoptRef(*new WebProcessProxy(processPool, websiteDataStore, isPrewarmed));
</span><del>-    if (shouldLaunchProcess == ShouldLaunchProcess::Yes)
</del><ins>+    if (shouldLaunchProcess == ShouldLaunchProcess::Yes) {
+        if (liveProcessesLRU().size() >= s_maxProcessCount) {
+            for (auto& processPool : WebProcessPool::allProcessPools())
+                processPool->webProcessCache().clear();
+            if (liveProcessesLRU().size() >= s_maxProcessCount)
+                liveProcessesLRU().first()->requestTermination(ProcessTerminationReason::ExceededProcessCountLimit);
+        }
+        ASSERT(liveProcessesLRU().size() < s_maxProcessCount);
+        liveProcessesLRU().add(proxy.ptr());
</ins><span class="cx">         proxy->connect();
</span><ins>+    }
</ins><span class="cx">     return proxy;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -236,6 +264,8 @@
</span><span class="cx">     ASSERT(m_pageURLRetainCountMap.isEmpty());
</span><span class="cx">     WEBPROCESSPROXY_RELEASE_LOG(Process, "destructor:");
</span><span class="cx"> 
</span><ins>+    liveProcessesLRU().remove(this);
+
</ins><span class="cx">     for (auto identifier : m_speechRecognitionServerMap.keys())
</span><span class="cx">         removeMessageReceiver(Messages::SpeechRecognitionServer::messageReceiverName(), identifier);
</span><span class="cx"> 
</span><span class="lines">@@ -336,6 +366,7 @@
</span><span class="cx"> 
</span><span class="cx">     ASSERT(!m_isInProcessCache);
</span><span class="cx">     ASSERT(!m_provisionalPages.contains(&provisionalPage));
</span><ins>+    markProcessAsRecentlyUsed();
</ins><span class="cx">     m_provisionalPages.add(&provisionalPage);
</span><span class="cx">     updateRegistrationWithDataStore();
</span><span class="cx"> }
</span><span class="lines">@@ -557,6 +588,7 @@
</span><span class="cx">         m_processPool->pageBeginUsingWebsiteDataStore(webPage.identifier(), webPage.websiteDataStore());
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    markProcessAsRecentlyUsed();
</ins><span class="cx">     m_pageMap.set(webPage.identifier(), &webPage);
</span><span class="cx">     globalPageMap().set(webPage.identifier(), &webPage);
</span><span class="cx"> 
</span><span class="lines">@@ -888,6 +920,8 @@
</span><span class="cx">     // to be deleted before we can finish our work.
</span><span class="cx">     auto protectedThis = makeRef(*this);
</span><span class="cx"> 
</span><ins>+    liveProcessesLRU().remove(this);
+
</ins><span class="cx"> #if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
</span><span class="cx">     m_userMediaCaptureManagerProxy->clear();
</span><span class="cx"> #endif
</span><span class="lines">@@ -1850,6 +1884,7 @@
</span><span class="cx"> void WebProcessProxy::establishServiceWorkerContext(const WebPreferencesStore& store, CompletionHandler<void()>&& completionHandler)
</span><span class="cx"> {
</span><span class="cx">     WEBPROCESSPROXY_RELEASE_LOG(Loading, "establishServiceWorkerContext: Started");
</span><ins>+    markProcessAsRecentlyUsed();
</ins><span class="cx">     sendWithAsyncReply(Messages::WebProcess::EstablishWorkerContextConnectionToNetworkProcess { processPool().defaultPageGroup().pageGroupID(), m_serviceWorkerInformation->serviceWorkerPageProxyID, m_serviceWorkerInformation->serviceWorkerPageID, store, *m_registrableDomain, m_serviceWorkerInformation->initializationData }, [this, weakThis = makeWeakPtr(*this), completionHandler = WTFMove(completionHandler)]() mutable {
</span><span class="cx">         if (weakThis)
</span><span class="cx">             WEBPROCESSPROXY_RELEASE_LOG(Loading, "establishServiceWorkerContext: Finished");
</span><span class="lines">@@ -2000,6 +2035,12 @@
</span><span class="cx">     return !m_sleepDisablers.isEmpty();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebProcessProxy::markProcessAsRecentlyUsed()
+{
+    if (liveProcessesLRU().contains(this))
+        liveProcessesLRU().appendOrMoveToLast(this);
+}
+
</ins><span class="cx"> void WebProcessProxy::systemBeep()
</span><span class="cx"> {
</span><span class="cx">     PAL::systemBeep();
</span></span></pre></div>
<a id="branchessafari612branchSourceWebKitUIProcessWebProcessProxyh"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessProxy.h (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessProxy.h     2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Source/WebKit/UIProcess/WebProcessProxy.h        2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -164,6 +164,9 @@
</span><span class="cx">     
</span><span class="cx">     PAL::SessionID sessionID() const;
</span><span class="cx"> 
</span><ins>+    static bool hasReachedProcessCountLimit();
+    static void setProcessCountLimit(unsigned);
+
</ins><span class="cx">     static WebProcessProxy* processForIdentifier(WebCore::ProcessIdentifier);
</span><span class="cx">     static WebPageProxy* webPage(WebPageProxyIdentifier);
</span><span class="cx">     Ref<WebPageProxy> createWebPage(PageClient&, Ref<API::PageConfiguration>&&);
</span><span class="lines">@@ -408,6 +411,8 @@
</span><span class="cx">     static bool shouldEnableRemoteInspector();
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+    void markProcessAsRecentlyUsed();
+
</ins><span class="cx"> #if PLATFORM(MAC)
</span><span class="cx">     void platformSuspendProcess();
</span><span class="cx">     void platformResumeProcess();
</span></span></pre></div>
<a id="branchessafari612branchToolsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Tools/ChangeLog (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Tools/ChangeLog       2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Tools/ChangeLog  2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -1,3 +1,71 @@
</span><ins>+2021-09-09  Russell Epstein  <repstein@apple.com>
+
+        Cherry-pick r282218. rdar://problem/82931375
+
+    Implement a WebProcess cap
+    https://bugs.webkit.org/show_bug.cgi?id=230067
+    <rdar://79479244>
+    
+    Reviewed by Geoffrey Garen.
+    
+    Source/WebKit:
+    
+    Implement a WebProcess cap to avoid getting into a state where we run out of resources and crash in various ways.
+    The current limit is 400 and can be changed via an SPI. The limit is per UIProcess (not per process pool).
+    When we try and launch a new WebProcess and the limit has been reached, we terminate the least recently used
+    WebProcess to avoid going over the limit.
+    
+    * Shared/ProcessTerminationReason.h:
+    * UIProcess/API/C/WKAPICast.h:
+    (WebKit::toAPI):
+    * UIProcess/API/Cocoa/WKProcessPool.mm:
+    (+[WKProcessPool _setWebProcessCountLimit:]):
+    * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+    * UIProcess/Cocoa/NavigationState.mm:
+    (WebKit::wkProcessTerminationReason):
+    * UIProcess/WebPageProxy.cpp:
+    (WebKit::WebPageProxy::loadRequestWithNavigationShared):
+    (WebKit::WebPageProxy::loadFile):
+    (WebKit::WebPageProxy::loadDataWithNavigationShared):
+    (WebKit::WebPageProxy::loadSimulatedRequest):
+    (WebKit::WebPageProxy::loadAlternateHTML):
+    (WebKit::WebPageProxy::loadWebArchiveData):
+    (WebKit::WebPageProxy::reload):
+    (WebKit::WebPageProxy::goToBackForwardItem):
+    (WebKit::shouldReloadAfterProcessTermination):
+    * UIProcess/WebProcessProxy.cpp:
+    (WebKit::WebProcessProxy::setProcessCountLimit):
+    (WebKit::WebProcessProxy::create):
+    (WebKit::WebProcessProxy::~WebProcessProxy):
+    (WebKit::WebProcessProxy::addProvisionalPageProxy):
+    (WebKit::WebProcessProxy::addExistingWebPage):
+    (WebKit::WebProcessProxy::processDidTerminateOrFailedToLaunch):
+    (WebKit::WebProcessProxy::establishServiceWorkerContext):
+    (WebKit::WebProcessProxy::markProcessAsRecentlyUsed):
+    * UIProcess/WebProcessProxy.h:
+    
+    Tools:
+    
+    Add API test coverage.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/WebContentProcessDidTerminate.mm:
+    (TEST):
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@282218 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2021-09-09  Chris Dumez  <cdumez@apple.com>
+
+            Implement a WebProcess cap
+            https://bugs.webkit.org/show_bug.cgi?id=230067
+            <rdar://79479244>
+
+            Reviewed by Geoffrey Garen.
+
+            Add API test coverage.
+
+            * TestWebKitAPI/Tests/WebKitCocoa/WebContentProcessDidTerminate.mm:
+            (TEST):
+
</ins><span class="cx"> 2021-09-08  Alan Coon  <alancoon@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Cherry-pick r281965. rdar://problem/82877374
</span></span></pre></div>
<a id="branchessafari612branchToolsTestWebKitAPITestsWebKitCocoaWebContentProcessDidTerminatemm"></a>
<div class="modfile"><h4>Modified: branches/safari-612-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebContentProcessDidTerminate.mm (282228 => 282229)</h4>
<pre class="diff"><span>
<span class="info">--- branches/safari-612-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebContentProcessDidTerminate.mm        2021-09-09 18:04:30 UTC (rev 282228)
+++ branches/safari-612-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebContentProcessDidTerminate.mm   2021-09-09 18:04:35 UTC (rev 282229)
</span><span class="lines">@@ -376,3 +376,67 @@
</span><span class="cx">     kill([webView _webProcessIdentifier], 9);
</span><span class="cx">     TestWebKitAPI::Util::run(&done);
</span><span class="cx"> }
</span><ins>+
+TEST(WKNavigation, WebProcessLimit)
+{
+    constexpr unsigned maxProcessCount = 10;
+    [WKProcessPool _setWebProcessCountLimit:maxProcessCount];
+
+    auto navigationDelegate = adoptNS([[TestNavigationDelegate alloc] init]);
+    [navigationDelegate setDidFinishNavigation:^(WKWebView *, WKNavigation *) {
+        finishedLoad = true;
+    }];
+    auto createWebView = [&] {
+        auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+        auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]);
+        [webView setNavigationDelegate:navigationDelegate.get()];
+        finishedLoad = false;
+        [webView loadTestPageNamed:@"simple"];
+        TestWebKitAPI::Util::run(&finishedLoad);
+        return webView;
+    };
+
+    [navigationDelegate setWebContentProcessDidTerminate:^(WKWebView *) {
+        didCrash = true;
+    }];
+
+    Vector<RetainPtr<WKWebView>> views;
+    for (unsigned i = 0; i < maxProcessCount; ++i)
+        views.append(createWebView());
+    EXPECT_FALSE(didCrash);
+    for (auto& view : views)
+        EXPECT_NE([view _webProcessIdentifier], 0);
+
+    // We have now reached the WebProcess cap, let's try and launch a new one.
+    __block unsigned crashCount = 0;
+    [navigationDelegate setWebContentProcessDidTerminate:^(WKWebView * view) {
+        EXPECT_EQ(views[0], view);
+        ++crashCount;
+    }];
+    views.append(createWebView());
+
+    EXPECT_EQ(crashCount, 1U);
+    for (unsigned i = 0; i < views.size(); ++i) {
+        if (!i)
+            EXPECT_EQ([views[i] _webProcessIdentifier], 0);
+        else
+            EXPECT_NE([views[i] _webProcessIdentifier], 0);
+    }
+
+    crashCount = 0;
+    [navigationDelegate setWebContentProcessDidTerminate:^(WKWebView * view) {
+        EXPECT_EQ(views[1], view);
+        ++crashCount;
+    }];
+    views.append(createWebView());
+
+    EXPECT_EQ(crashCount, 1U);
+    for (unsigned i = 0; i < views.size(); ++i) {
+        if (i < 2)
+            EXPECT_EQ([views[i] _webProcessIdentifier], 0);
+        else
+            EXPECT_NE([views[i] _webProcessIdentifier], 0);
+    }
+
+    [WKProcessPool _setWebProcessCountLimit:400];
+}
</ins></span></pre>
</div>
</div>

</body>
</html>