| Index: content/browser/renderer_host/render_process_host_impl.cc
|
| diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
|
| index 8e759337fd632a9af30667f8d2ec36c1a8890b58..a80a142f4d7fc71b4d3bc02d8cf44419537799b1 100644
|
| --- a/content/browser/renderer_host/render_process_host_impl.cc
|
| +++ b/content/browser/renderer_host/render_process_host_impl.cc
|
| @@ -35,6 +35,7 @@
|
| #include "base/rand_util.h"
|
| #include "base/stl_util.h"
|
| #include "base/string_util.h"
|
| +#include "base/supports_user_data.h"
|
| #include "base/sys_info.h"
|
| #include "base/threading/thread.h"
|
| #include "base/threading/thread_restrictions.h"
|
| @@ -91,6 +92,7 @@
|
| #include "content/public/browser/browser_context.h"
|
| #include "content/public/browser/content_browser_client.h"
|
| #include "content/public/browser/notification_service.h"
|
| +#include "content/public/browser/render_process_host_factory.h"
|
| #include "content/public/browser/resource_context.h"
|
| #include "content/public/browser/user_metrics.h"
|
| #include "content/public/browser/web_ui_controller_factory.h"
|
| @@ -122,6 +124,8 @@
|
|
|
| extern bool g_exited_main_message_loop;
|
|
|
| +static const char* kSiteProcessMapKeyName = "content_site_process_map";
|
| +
|
| namespace content {
|
|
|
| // This class creates the IO thread for the renderer when running in
|
| @@ -208,6 +212,61 @@ class RendererURLRequestContextSelector
|
| base::LazyInstance<IDMap<RenderProcessHost> >::Leaky
|
| g_all_hosts = LAZY_INSTANCE_INITIALIZER;
|
|
|
| +// Map of site to process, to ensure we only have one RenderProcessHost per
|
| +// site in process-per-site mode. Each map is specific to a BrowserContext.
|
| +class SiteProcessMap : public base::SupportsUserData::Data {
|
| + public:
|
| + typedef base::hash_map<std::string, RenderProcessHost*> SiteToProcessMap;
|
| + SiteProcessMap() {}
|
| +
|
| + void RegisterProcess(std::string site, RenderProcessHost* process) {
|
| + map_[site] = process;
|
| + }
|
| +
|
| + RenderProcessHost* FindProcess(std::string site) {
|
| + SiteToProcessMap::iterator i = map_.find(site);
|
| + if (i != map_.end())
|
| + return i->second;
|
| + return NULL;
|
| + }
|
| +
|
| + void RemoveProcess(RenderProcessHost* host) {
|
| + // Find all instances of this process in the map, then separately remove
|
| + // them.
|
| + std::set<std::string> sites;
|
| + for (SiteToProcessMap::const_iterator i = map_.begin();
|
| + i != map_.end();
|
| + i++) {
|
| + if (i->second == host)
|
| + sites.insert(i->first);
|
| + }
|
| + for (std::set<std::string>::iterator i = sites.begin();
|
| + i != sites.end();
|
| + i++) {
|
| + SiteToProcessMap::iterator iter = map_.find(*i);
|
| + if (iter != map_.end()) {
|
| + DCHECK_EQ(iter->second, host);
|
| + map_.erase(iter);
|
| + }
|
| + }
|
| + }
|
| +
|
| + private:
|
| + SiteToProcessMap map_;
|
| +};
|
| +
|
| +// Find the SiteProcessMap specific to the given context.
|
| +SiteProcessMap* GetSiteProcessMapForBrowserContext(BrowserContext* context) {
|
| + DCHECK(context);
|
| + SiteProcessMap* map = static_cast<SiteProcessMap*>(
|
| + context->GetUserData(kSiteProcessMapKeyName));
|
| + if (!map) {
|
| + map = new SiteProcessMap();
|
| + context->SetUserData(kSiteProcessMapKeyName, map);
|
| + }
|
| + return map;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // Stores the maximum number of renderer processes the content module can
|
| @@ -1071,7 +1130,7 @@ void RenderProcessHostImpl::Cleanup() {
|
|
|
| // Remove ourself from the list of renderer processes so that we can't be
|
| // reused in between now and when the Delete task runs.
|
| - g_all_hosts.Get().Remove(GetID());
|
| + UnregisterHost(GetID());
|
| }
|
| }
|
|
|
| @@ -1131,8 +1190,18 @@ void RenderProcessHostImpl::RegisterHost(int host_id, RenderProcessHost* host) {
|
|
|
| // static
|
| void RenderProcessHostImpl::UnregisterHost(int host_id) {
|
| - if (g_all_hosts.Get().Lookup(host_id))
|
| - g_all_hosts.Get().Remove(host_id);
|
| + RenderProcessHost* host = g_all_hosts.Get().Lookup(host_id);
|
| + if (!host)
|
| + return;
|
| +
|
| + g_all_hosts.Get().Remove(host_id);
|
| +
|
| + // Look up the map of site to process for the given browser_context,
|
| + // in case we need to remove this process from it. It will be registered
|
| + // under any sites it rendered that use process-per-site mode.
|
| + SiteProcessMap* map =
|
| + GetSiteProcessMapForBrowserContext(host->GetBrowserContext());
|
| + map->RemoveProcess(host);
|
| }
|
|
|
| // static
|
| @@ -1235,10 +1304,75 @@ RenderProcessHost* RenderProcessHost::GetExistingProcessHost(
|
| return NULL;
|
| }
|
|
|
| +// static
|
| +bool RenderProcessHostImpl::ShouldUseProcessPerSite(
|
| + BrowserContext* browser_context,
|
| + const GURL& url) {
|
| + // Returns true if we should use the process-per-site model. This will be
|
| + // the case if the --process-per-site switch is specified, or in
|
| + // process-per-site-instance for particular sites (e.g., WebUI).
|
| +
|
| + const CommandLine& command_line = *CommandLine::ForCurrentProcess();
|
| + if (command_line.HasSwitch(switches::kProcessPerSite))
|
| + return true;
|
| +
|
| + // We want to consolidate particular sites like WebUI when we are using
|
| + // process-per-tab or process-per-site-instance models.
|
| + // Note that --single-process is handled in ShouldTryToUseExistingProcessHost.
|
| +
|
| + if (content::GetContentClient()->browser()->
|
| + ShouldUseProcessPerSite(browser_context, url)) {
|
| + return true;
|
| + }
|
| +
|
| + // DevTools pages have WebUI type but should not reuse the same host.
|
| + WebUIControllerFactory* factory =
|
| + content::GetContentClient()->browser()->GetWebUIControllerFactory();
|
| + if (factory &&
|
| + factory->UseWebUIForURL(browser_context, url) &&
|
| + !url.SchemeIs(chrome::kChromeDevToolsScheme)) {
|
| + return true;
|
| + }
|
| +
|
| + // In all other cases, don't use process-per-site logic.
|
| + return false;
|
| +}
|
| +
|
| +// static
|
| +RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSite(
|
| + BrowserContext* browser_context,
|
| + const GURL& url) {
|
| + // Look up the map of site to process for the given browser_context.
|
| + SiteProcessMap* map =
|
| + GetSiteProcessMapForBrowserContext(browser_context);
|
| +
|
| + // See if we have an existing process for this site. If not, the caller
|
| + // should create a new process and register it.
|
| + std::string site = SiteInstanceImpl::GetSiteForURL(browser_context, url)
|
| + .possibly_invalid_spec();
|
| + return map->FindProcess(site);
|
| +}
|
| +
|
| +void RenderProcessHostImpl::RegisterProcessHostForSite(
|
| + BrowserContext* browser_context,
|
| + RenderProcessHost* process,
|
| + const GURL& url) {
|
| + // Look up the map of site to process for the given browser_context.
|
| + SiteProcessMap* map =
|
| + GetSiteProcessMapForBrowserContext(browser_context);
|
| +
|
| + // TODO(creis): Determine if it's better to allow registration of
|
| + // empty sites or not. For now, group anything from which we can't parse
|
| + // a site into the same process, when using --process-per-site.
|
| + std::string site = SiteInstanceImpl::GetSiteForURL(browser_context, url)
|
| + .possibly_invalid_spec();
|
| + map->RegisterProcess(site, process);
|
| +}
|
| +
|
| void RenderProcessHostImpl::ProcessDied(base::ProcessHandle handle,
|
| - base::TerminationStatus status,
|
| - int exit_code,
|
| - bool was_alive) {
|
| + base::TerminationStatus status,
|
| + int exit_code,
|
| + bool was_alive) {
|
| // Our child process has died. If we didn't expect it, it's a crash.
|
| // In any case, we need to let everyone know it's gone.
|
| // The OnChannelError notification can fire multiple times due to nested sync
|
|
|