From eca3f81cfca1274263587bceb5c6546d23b83612 Mon Sep 17 00:00:00 2001 From: Alexey Proskuryakov Date: Tue, 11 Dec 2012 07:33:01 +0000 Subject: [PATCH] [WK2] Add a user default to limit the number of web processes https://bugs.webkit.org/show_bug.cgi?id=104606 Reviewed by Sam Weinig. When the limit is reached, we'll reuse an existing process with fewest pages. * UIProcess/WebContext.cpp: (WebKit::WebContext::WebContext): Initialize m_webProcessCountLimit. (WebKit::WebContext::platformInitialize): Added a hook for reading the preference, empty implementation on most platforms. (WebKit::WebContext::createNewWebProcess): Changed to return a raw pointer. The new process is put into a vector anyway, so there is no ownership transfer. (WebKit::WebContext::warmInitialProcess): Don't create a new process if that would exceed the limit. (WebKit::WebContext::createNewWebProcessRespectingProcessCountLimit): Added a new function that wither creates a new process, or picks an existing one. (WebKit::WebContext::createWebPage): Call the above new function instead of unconditionally creating a process. * UIProcess/WebContext.h: createNewWebProcess is no private. All clients should respect the process count limit. * UIProcess/WebPageProxy.cpp: (WebKit::WebPageProxy::reattachToWebProcess): Respect the process count limit. * UIProcess/mac/WebContextMac.mm: (WebKit::registerUserDefaultsIfNeeded): Register the new default. (WebKit::WebContext::platformInitialize): Read the default into a WebContext member variable. (WebKit::WebContext::platformInitializeWebProcess): Moved registerUserDefaultsIfNeeded() from here to platformInitialize(), as that's a better place for it. Also added a FIXME for an unrelated issue. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@137255 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- Source/WebKit2/ChangeLog | 36 +++++++++++++++ Source/WebKit2/UIProcess/WebContext.cpp | 40 ++++++++++++++--- Source/WebKit2/UIProcess/WebContext.h | 6 ++- Source/WebKit2/UIProcess/WebPageProxy.cpp | 2 +- Source/WebKit2/UIProcess/mac/WebContextMac.mm | 44 +++++++++++++------ 5 files changed, 105 insertions(+), 23 deletions(-) diff --git a/Source/WebKit2/ChangeLog b/Source/WebKit2/ChangeLog index fbd3d196c22ca..0b1db87ac7117 100644 --- a/Source/WebKit2/ChangeLog +++ b/Source/WebKit2/ChangeLog @@ -1,3 +1,39 @@ +2012-12-10 Alexey Proskuryakov + + [WK2] Add a user default to limit the number of web processes + https://bugs.webkit.org/show_bug.cgi?id=104606 + + Reviewed by Sam Weinig. + + When the limit is reached, we'll reuse an existing process with fewest pages. + + * UIProcess/WebContext.cpp: + (WebKit::WebContext::WebContext): Initialize m_webProcessCountLimit. + (WebKit::WebContext::platformInitialize): Added a hook for reading the preference, + empty implementation on most platforms. + (WebKit::WebContext::createNewWebProcess): Changed to return a raw pointer. The new + process is put into a vector anyway, so there is no ownership transfer. + (WebKit::WebContext::warmInitialProcess): Don't create a new process if that would + exceed the limit. + (WebKit::WebContext::createNewWebProcessRespectingProcessCountLimit): Added a new + function that wither creates a new process, or picks an existing one. + (WebKit::WebContext::createWebPage): Call the above new function instead of + unconditionally creating a process. + + * UIProcess/WebContext.h: createNewWebProcess is no private. All clients should + respect the process count limit. + + * UIProcess/WebPageProxy.cpp: (WebKit::WebPageProxy::reattachToWebProcess): + Respect the process count limit. + + * UIProcess/mac/WebContextMac.mm: + (WebKit::registerUserDefaultsIfNeeded): Register the new default. + (WebKit::WebContext::platformInitialize): Read the default into a WebContext + member variable. + (WebKit::WebContext::platformInitializeWebProcess): Moved registerUserDefaultsIfNeeded() + from here to platformInitialize(), as that's a better place for it. Also added a + FIXME for an unrelated issue. + 2012-12-10 Jon Lee Build fix. diff --git a/Source/WebKit2/UIProcess/WebContext.cpp b/Source/WebKit2/UIProcess/WebContext.cpp index 31b1c99acfc24..bd06ffae07e4b 100644 --- a/Source/WebKit2/UIProcess/WebContext.cpp +++ b/Source/WebKit2/UIProcess/WebContext.cpp @@ -120,6 +120,7 @@ const Vector& WebContext::allContexts() WebContext::WebContext(ProcessModel processModel, const String& injectedBundlePath) : m_processModel(processModel) + , m_webProcessCountLimit(UINT_MAX) , m_haveInitialEmptyProcess(false) , m_defaultPageGroup(WebPageGroup::create()) , m_injectedBundlePath(injectedBundlePath) @@ -139,6 +140,8 @@ WebContext::WebContext(ProcessModel processModel, const String& injectedBundlePa , m_usesNetworkProcess(false) #endif { + platformInitialize(); + addMessageReceiver(Messages::WebContext::messageReceiverName(), this); addMessageReceiver(CoreIPC::MessageKindTraits::messageReceiverName(), this); @@ -184,6 +187,12 @@ WebContext::WebContext(ProcessModel processModel, const String& injectedBundlePa #endif } +#if !PLATFORM(MAC) +void WebContext::platformInitialize() +{ +} +#endif + WebContext::~WebContext() { ASSERT(contexts().find(this) != notFound); @@ -388,7 +397,7 @@ WebProcessProxy* WebContext::ensureSharedWebProcess() return m_processes[0].get(); } -PassRefPtr WebContext::createNewWebProcess() +WebProcessProxy* WebContext::createNewWebProcess() { #if ENABLE(NETWORK_PROCESS) if (m_usesNetworkProcess) @@ -480,8 +489,7 @@ PassRefPtr WebContext::createNewWebProcess() } else ASSERT(m_messagesToInjectedBundlePostedToEmptyContext.isEmpty()); - - return process.release(); + return process.get(); } void WebContext::warmInitialProcess() @@ -491,6 +499,9 @@ void WebContext::warmInitialProcess() return; } + if (m_processes.size() >= m_webProcessCountLimit) + return; + createNewWebProcess(); m_haveInitialEmptyProcess = true; } @@ -615,6 +626,23 @@ void WebContext::disconnectProcess(WebProcessProxy* process) m_processes.remove(m_processes.find(process)); } +WebProcessProxy* WebContext::createNewWebProcessRespectingProcessCountLimit() +{ + if (m_processes.size() < m_webProcessCountLimit) + return createNewWebProcess(); + + // Choose a process with fewest pages, to achieve flat distribution. + WebProcessProxy* result = 0; + unsigned fewestPagesSeen = UINT_MAX; + for (unsigned i = 0; i < m_processes.size(); ++i) { + if (fewestPagesSeen > m_processes[i]->pages().size()) { + result = m_processes[i].get(); + fewestPagesSeen = m_processes[i]->pages().size(); + } + } + return result; +} + PassRefPtr WebContext::createWebPage(PageClient* pageClient, WebPageGroup* pageGroup, WebPageProxy* relatedPage) { RefPtr process; @@ -627,10 +655,8 @@ PassRefPtr WebContext::createWebPage(PageClient* pageClient, WebPa } else if (relatedPage) { // Sharing processes, e.g. when creating the page via window.open(). process = relatedPage->process(); - } else { - // FIXME (Multi-WebProcess): Consider limiting the number of web processes in per-tab process model. - process = createNewWebProcess(); - } + } else + process = createNewWebProcessRespectingProcessCountLimit(); } if (!pageGroup) diff --git a/Source/WebKit2/UIProcess/WebContext.h b/Source/WebKit2/UIProcess/WebContext.h index 849e77222166c..5181744564eea 100644 --- a/Source/WebKit2/UIProcess/WebContext.h +++ b/Source/WebKit2/UIProcess/WebContext.h @@ -220,7 +220,7 @@ class WebContext : public APIObject, private CoreIPC::MessageReceiver { void setCookieStorageDirectory(const String& dir) { m_overrideCookieStorageDirectory = dir; } WebProcessProxy* ensureSharedWebProcess(); - PassRefPtr createNewWebProcess(); + WebProcessProxy* createNewWebProcessRespectingProcessCountLimit(); // Will return an existing one if limit is met. void warmInitialProcess(); bool shouldTerminate(WebProcessProxy*); @@ -256,12 +256,15 @@ class WebContext : public APIObject, private CoreIPC::MessageReceiver { private: WebContext(ProcessModel, const String& injectedBundlePath); + void platformInitialize(); virtual Type type() const { return APIType; } void platformInitializeWebProcess(WebProcessCreationParameters&); void platformInvalidateContext(); + WebProcessProxy* createNewWebProcess(); + #if PLATFORM(MAC) void getPasteboardTypes(const String& pasteboardName, Vector& pasteboardTypes); void getPasteboardPathnamesForType(const String& pasteboardName, const String& pasteboardType, Vector& pathnames); @@ -318,6 +321,7 @@ class WebContext : public APIObject, private CoreIPC::MessageReceiver { void addPlugInAutoStartOriginHash(const String& pageOrigin, unsigned plugInOriginHash); ProcessModel m_processModel; + unsigned m_webProcessCountLimit; // The limit has no effect when process model is ProcessModelSharedSecondaryProcess. Vector > m_processes; bool m_haveInitialEmptyProcess; diff --git a/Source/WebKit2/UIProcess/WebPageProxy.cpp b/Source/WebKit2/UIProcess/WebPageProxy.cpp index 1406b3b4a7ba1..8a29b69dd7049 100644 --- a/Source/WebKit2/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit2/UIProcess/WebPageProxy.cpp @@ -385,7 +385,7 @@ void WebPageProxy::reattachToWebProcess() if (m_process->context()->processModel() == ProcessModelSharedSecondaryProcess) m_process = m_process->context()->ensureSharedWebProcess(); else - m_process = m_process->context()->createNewWebProcess(); + m_process = m_process->context()->createNewWebProcessRespectingProcessCountLimit(); m_process->addExistingWebPage(this, m_pageID); initializeWebPage(); diff --git a/Source/WebKit2/UIProcess/mac/WebContextMac.mm b/Source/WebKit2/UIProcess/mac/WebContextMac.mm index ce5bd29fbe4e2..d7f61e2618a60 100644 --- a/Source/WebKit2/UIProcess/mac/WebContextMac.mm +++ b/Source/WebKit2/UIProcess/mac/WebContextMac.mm @@ -47,6 +47,7 @@ NSString *WebKitLocalCacheDefaultsKey = @"WebKitLocalCache"; NSString *WebStorageDirectoryDefaultsKey = @"WebKitLocalStorageDatabasePathPreferenceKey"; NSString *WebKitKerningAndLigaturesEnabledByDefaultDefaultsKey = @"WebKitKerningAndLigaturesEnabledByDefault"; +NSString *WebKitWebProcessCountLimitDefaultsKey = @"WebKitWebProcessCountLimit"; static NSString *WebKitApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification = @"NSApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification"; @@ -60,6 +61,32 @@ bool WebContext::s_applicationIsOccluded = false; +static void registerUserDefaultsIfNeeded() +{ + static bool didRegister; + if (didRegister) + return; + + didRegister = true; + NSMutableDictionary *registrationDictionary = [NSMutableDictionary dictionary]; + + [registrationDictionary setObject:[NSNumber numberWithInteger:INT_MAX] forKey:WebKitWebProcessCountLimitDefaultsKey]; +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 + [registrationDictionary setObject:[NSNumber numberWithBool:YES] forKey:WebKitKerningAndLigaturesEnabledByDefaultDefaultsKey]; +#endif + + [[NSUserDefaults standardUserDefaults] registerDefaults:registrationDictionary]; +} + +void WebContext::platformInitialize() +{ + registerUserDefaultsIfNeeded(); + + m_webProcessCountLimit = [[NSUserDefaults standardUserDefaults] integerForKey:WebKitWebProcessCountLimitDefaultsKey]; + if (m_webProcessCountLimit <= 0) + m_webProcessCountLimit = 1; +} + String WebContext::applicationCacheDirectory() { NSString *appName = [[NSBundle mainBundle] bundleIdentifier]; @@ -82,18 +109,6 @@ return [cacheDir stringByAppendingPathComponent:appName]; } -static void registerUserDefaultsIfNeeded() -{ - static bool didRegister; - if (didRegister) - return; - - didRegister = true; -#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 - [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:WebKitKerningAndLigaturesEnabledByDefaultDefaultsKey]]; -#endif -} - void WebContext::platformInitializeWebProcess(WebProcessCreationParameters& parameters) { parameters.presenterApplicationPid = getpid(); @@ -102,7 +117,6 @@ static void registerUserDefaultsIfNeeded() parameters.nsURLCacheMemoryCapacity = [urlCache memoryCapacity]; parameters.nsURLCacheDiskCapacity = [urlCache diskCapacity]; - registerUserDefaultsIfNeeded(); #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 parameters.shouldForceScreenFontSubstitution = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSFontDefaultScreenFontSubstitutionEnabled"]; #endif @@ -123,7 +137,9 @@ static void registerUserDefaultsIfNeeded() NSArray *schemes = [[WKBrowsingContextController customSchemes] allObjects]; for (size_t i = 0; i < [schemes count]; ++i) parameters.urlSchemesRegisteredForCustomProtocols.append([schemes objectAtIndex:i]); - + + // FIXME(Multi-WebProcess): We register observers for every process that is created, which makes no sense. + m_customSchemeRegisteredObserver = [[NSNotificationCenter defaultCenter] addObserverForName:WebKit::SchemeForCustomProtocolRegisteredNotificationName object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) { NSString *scheme = [notification object]; ASSERT([scheme isKindOfClass:[NSString class]]);