diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-18 22:51:03 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-18 22:51:03 +0000 |
commit | 11de3e98153ad8dcb9e6628e527f7bfb2ca0a8ed (patch) | |
tree | 53cd07aaba6e6294b18a43a362980f8aa4a27142 /chrome/browser | |
parent | 51570ddfc079a32dc5e78887f730b7aa270b916e (diff) | |
download | chromium_src-11de3e98153ad8dcb9e6628e527f7bfb2ca0a8ed.zip chromium_src-11de3e98153ad8dcb9e6628e527f7bfb2ca0a8ed.tar.gz chromium_src-11de3e98153ad8dcb9e6628e527f7bfb2ca0a8ed.tar.bz2 |
Implement a max worker count of 16 per tab and 64 total. Any workers created after that are queued.
Review URL: http://codereview.chromium.org/125242
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18763 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 7 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 1 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_process_host.cc | 35 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_process_host.h | 33 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_service.cc | 131 | ||||
-rw-r--r-- | chrome/browser/worker_host/worker_service.h | 23 |
6 files changed, 176 insertions, 54 deletions
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 4db2831..2121378 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -258,6 +258,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) { OnOpenChannelToPlugin) IPC_MESSAGE_HANDLER(ViewHostMsg_CreateDedicatedWorker, OnCreateDedicatedWorker) + IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker, + OnCancelCreateDedicatedWorker) IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker, OnForwardToWorker) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SpellCheck, OnSpellCheck) @@ -537,6 +539,11 @@ void ResourceMessageFilter::OnCreateDedicatedWorker(const GURL& url, *route_id); } +void ResourceMessageFilter::OnCancelCreateDedicatedWorker(int route_id) { + WorkerService::GetInstance()->CancelCreateDedicatedWorker( + render_process_id_, route_id); +} + void ResourceMessageFilter::OnForwardToWorker(const IPC::Message& message) { WorkerService::GetInstance()->ForwardMessage(message, render_process_id_); } diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index d825dd2b..268b4fb 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -144,6 +144,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnCreateDedicatedWorker(const GURL& url, int render_view_route_id, int* route_id); + void OnCancelCreateDedicatedWorker(int route_id); void OnForwardToWorker(const IPC::Message& msg); void OnDownloadUrl(const IPC::Message& message, const GURL& url, diff --git a/chrome/browser/worker_host/worker_process_host.cc b/chrome/browser/worker_host/worker_process_host.cc index d720cff..34089c1 100644 --- a/chrome/browser/worker_host/worker_process_host.cc +++ b/chrome/browser/worker_host/worker_process_host.cc @@ -52,7 +52,8 @@ WorkerProcessHost::WorkerProcessHost( } WorkerProcessHost::~WorkerProcessHost() { - WorkerService::GetInstance()->NotifySenderShutdown(this); + WorkerService::GetInstance()->OnSenderShutdown(this); + WorkerService::GetInstance()->OnWorkerProcessDestroyed(this); // If we crashed, tell the RenderViewHost. MessageLoop* ui_loop = WorkerService::GetInstance()->ui_loop(); @@ -98,28 +99,17 @@ bool WorkerProcessHost::Init() { return true; } -void WorkerProcessHost::CreateWorker(const GURL& url, - int renderer_process_id, - int render_view_route_id, - int worker_route_id, - IPC::Message::Sender* sender, - int sender_pid, - int sender_route_id) { +void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) { ChildProcessSecurityPolicy::GetInstance()->GrantRequestURL( - GetProcessId(), url); - - WorkerInstance instance; - instance.url = url; - instance.renderer_process_id = renderer_process_id; - instance.render_view_route_id = render_view_route_id; - instance.worker_route_id = worker_route_id; - instance.sender = sender; - instance.sender_pid = sender_pid; - instance.sender_route_id = sender_route_id; + GetProcessId(), instance.url); + instances_.push_back(instance); - Send(new WorkerProcessMsg_CreateWorker(url, worker_route_id)); + Send(new WorkerProcessMsg_CreateWorker( + instance.url, instance.worker_route_id)); UpdateTitle(); + instances_.back().sender->Send( + new ViewMsg_DedicatedWorkerCreated(instance.sender_route_id)); } bool WorkerProcessHost::FilterMessage(const IPC::Message& message, @@ -148,6 +138,8 @@ void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(WorkerProcessHost, message) IPC_MESSAGE_HANDLER(ViewHostMsg_CreateDedicatedWorker, OnCreateDedicatedWorker) + IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker, + OnCancelCreateDedicatedWorker) IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker, OnForwardToWorker) IPC_MESSAGE_UNHANDLED(handled = false) @@ -216,6 +208,11 @@ void WorkerProcessHost::OnCreateDedicatedWorker(const GURL& url, instances_.front().render_view_route_id, this, GetProcessId(), *route_id); } +void WorkerProcessHost::OnCancelCreateDedicatedWorker(int route_id) { + WorkerService::GetInstance()->CancelCreateDedicatedWorker( + GetProcessId(), route_id); +} + void WorkerProcessHost::OnForwardToWorker(const IPC::Message& message) { WorkerService::GetInstance()->ForwardMessage(message, GetProcessId()); } diff --git a/chrome/browser/worker_host/worker_process_host.h b/chrome/browser/worker_host/worker_process_host.h index 5474724..fca046e 100644 --- a/chrome/browser/worker_host/worker_process_host.h +++ b/chrome/browser/worker_host/worker_process_host.h @@ -14,6 +14,18 @@ class WorkerProcessHost : public ChildProcessHost { public: + // Contains information about each worker instance, needed to forward messages + // between the renderer and worker processes. + struct WorkerInstance { + GURL url; + int renderer_process_id; + int render_view_route_id; + int worker_route_id; + IPC::Message::Sender* sender; + int sender_pid; + int sender_route_id; + }; + WorkerProcessHost(ResourceDispatcherHost* resource_dispatcher_host_); ~WorkerProcessHost(); @@ -21,13 +33,7 @@ class WorkerProcessHost : public ChildProcessHost { bool Init(); // Creates a worker object in the process. - void CreateWorker(const GURL& url, - int renderer_process_id, - int render_view_route_id, - int worker_route_id, - IPC::Message::Sender* sender, - int sender_pid, - int sender_route_id); + void CreateWorker(const WorkerInstance& instance); // Returns true iff the given message from a renderer process was forwarded to // the worker. @@ -38,18 +44,6 @@ class WorkerProcessHost : public ChildProcessHost { protected: friend class WorkerService; - // Contains information about each worker instance, needed to forward messages - // between the renderer and worker processes. - struct WorkerInstance { - GURL url; - int renderer_process_id; - int render_view_route_id; - int worker_route_id; - IPC::Message::Sender* sender; - int sender_pid; - int sender_route_id; - }; - typedef std::list<WorkerInstance> Instances; const Instances& instances() const { return instances_; } @@ -70,6 +64,7 @@ class WorkerProcessHost : public ChildProcessHost { void OnCreateDedicatedWorker(const GURL& url, int render_view_route_id, int* route_id); + void OnCancelCreateDedicatedWorker(int route_id); void OnForwardToWorker(const IPC::Message& message); Instances instances_; diff --git a/chrome/browser/worker_host/worker_service.cc b/chrome/browser/worker_host/worker_service.cc index 5968071..e67ae80 100644 --- a/chrome/browser/worker_host/worker_service.cc +++ b/chrome/browser/worker_host/worker_service.cc @@ -15,11 +15,12 @@ #include "chrome/browser/renderer_host/resource_message_filter.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/notification_service.h" +#include "chrome/common/worker_messages.h" #include "net/base/registry_controlled_domain.h" -namespace { -static const int kMaxWorkerProcesses = 10; -} +const int WorkerService::kMaxWorkerProcessesWhenSharing = 10; +const int WorkerService::kMaxWorkersWhenSeparate = 64; +const int WorkerService::kMaxWorkersPerTabWhenSeparate = 16; WorkerService* WorkerService::GetInstance() { return Singleton<WorkerService>::get(); @@ -49,14 +50,31 @@ bool WorkerService::CreateDedicatedWorker(const GURL &url, IPC::Message::Sender* sender, int sender_pid, int sender_route_id) { - WorkerProcessHost* worker = NULL; + // Generate a unique route id for the browser-worker communication that's + // unique among all worker processes. That way when the worker process sends + // a wrapped IPC message through us, we know which WorkerProcessHost to give + // it to. + WorkerProcessHost::WorkerInstance instance; + instance.url = url; + instance.renderer_process_id = renderer_process_id; + instance.render_view_route_id = render_view_route_id; + instance.worker_route_id = next_worker_route_id(); + instance.sender = sender; + instance.sender_pid = sender_pid; + instance.sender_route_id = sender_route_id; + WorkerProcessHost* worker = NULL; if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kWebWorkerProcessPerCore)) { worker = GetProcessToFillUpCores(); } else if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kWebWorkerShareProcesses)) { worker = GetProcessForDomain(url); + } else { // One process per worker. + if (!CanCreateWorkerProcess(instance)) { + queued_workers_.push_back(instance); + return true; + } } if (!worker) { @@ -67,17 +85,43 @@ bool WorkerService::CreateDedicatedWorker(const GURL &url, } } - // Generate a unique route id for the browser-worker communication that's - // unique among all worker processes. That way when the worker process sends - // a wrapped IPC message through us, we know which WorkerProcessHost to give - // it to. - worker->CreateWorker(url, renderer_process_id, render_view_route_id, - next_worker_route_id(), sender, sender_pid, - sender_route_id); - + worker->CreateWorker(instance); return true; } +void WorkerService::CancelCreateDedicatedWorker(int sender_pid, + int sender_route_id) { + for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); + i != queued_workers_.end(); ++i) { + if (i->sender_pid == sender_pid && i->sender_route_id == sender_route_id) { + queued_workers_.erase(i); + return; + } + } + + // There could be a race condition where the WebWorkerProxy told us to cancel + // the worker right as we sent it a message say it's been created. Look at + // the running workers. + for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); + !iter.Done(); ++iter) { + WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); + for (WorkerProcessHost::Instances::const_iterator instance = + worker->instances().begin(); + instance != worker->instances().end(); ++instance) { + if (instance->sender_pid == sender_pid && + instance->sender_route_id == sender_route_id) { + // Fake a worker destroyed message so that WorkerProcessHost cleans up + // properly. + WorkerHostMsg_WorkerContextDestroyed msg(sender_route_id); + ForwardMessage(msg, sender_pid); + return; + } + } + } + + DCHECK(false) << "Couldn't find worker to cancel"; +} + void WorkerService::ForwardMessage(const IPC::Message& message, int sender_pid) { for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); @@ -108,7 +152,7 @@ WorkerProcessHost* WorkerService::GetProcessForDomain(const GURL& url) { } } - if (num_processes >= kMaxWorkerProcesses) + if (num_processes >= kMaxWorkerProcessesWhenSharing) return GetLeastLoadedWorker(); return NULL; @@ -138,18 +182,75 @@ WorkerProcessHost* WorkerService::GetLeastLoadedWorker() { return smallest; } +bool WorkerService::CanCreateWorkerProcess( + const WorkerProcessHost::WorkerInstance& instance) { + int total_workers = 0; + int workers_per_tab = 0; + for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); + !iter.Done(); ++iter) { + WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); + for (WorkerProcessHost::Instances::const_iterator cur_instance = + worker->instances().begin(); + cur_instance != worker->instances().end(); ++cur_instance) { + total_workers++; + if (total_workers >= kMaxWorkersWhenSeparate) + return false; + if (cur_instance->renderer_process_id == instance.renderer_process_id && + cur_instance->render_view_route_id == instance.render_view_route_id) { + workers_per_tab++; + if (workers_per_tab >= kMaxWorkersPerTabWhenSeparate) + return false; + } + } + } + + return true; +} + void WorkerService::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { DCHECK(type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN); ResourceMessageFilter* filter = Source<ResourceMessageFilter>(source).ptr(); - NotifySenderShutdown(filter); + OnSenderShutdown(filter); } -void WorkerService::NotifySenderShutdown(IPC::Message::Sender* sender) { +void WorkerService::OnSenderShutdown(IPC::Message::Sender* sender) { for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); !iter.Done(); ++iter) { WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); worker->SenderShutdown(sender); } + + // See if that render process had any queued workers. + for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); + i != queued_workers_.end();) { + if (i->sender == sender) { + i = queued_workers_.erase(i); + } else { + ++i; + } + } +} + +void WorkerService::OnWorkerProcessDestroyed(WorkerProcessHost* process) { + if (queued_workers_.empty()) + return; + + for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); + i != queued_workers_.end();) { + if (CanCreateWorkerProcess(*i)) { + WorkerProcessHost* worker = + new WorkerProcessHost(resource_dispatcher_host_); + if (!worker->Init()) { + delete worker; + return; + } + + worker->CreateWorker(*i); + i = queued_workers_.erase(i); + } else { + ++i; + } + } } diff --git a/chrome/browser/worker_host/worker_service.h b/chrome/browser/worker_host/worker_service.h index e009679..ba5760f 100644 --- a/chrome/browser/worker_host/worker_service.h +++ b/chrome/browser/worker_host/worker_service.h @@ -9,6 +9,7 @@ #include "base/basictypes.h" #include "base/singleton.h" +#include "chrome/browser/worker_host/worker_process_host.h" #include "chrome/common/ipc_message.h" #include "chrome/common/notification_registrar.h" #include "googleurl/src/gurl.h" @@ -34,6 +35,9 @@ class WorkerService : public NotificationObserver { int sender_pid, int sender_route_id); + // Cancel creation of a dedicated worker that hasn't started yet. + void CancelCreateDedicatedWorker(int sender_pid, int sender_route_id); + // Called by the worker creator when a message arrives that should be // forwarded to the worker process. void ForwardMessage(const IPC::Message& message, int sender_pid); @@ -43,12 +47,23 @@ class WorkerService : public NotificationObserver { const NotificationSource& source, const NotificationDetails& details); - void NotifySenderShutdown(IPC::Message::Sender* sender); + // Notifies us that a process that's talking to a worker has shut down. + void OnSenderShutdown(IPC::Message::Sender* sender); + + // Notifies us that a worker process has closed. + void OnWorkerProcessDestroyed(WorkerProcessHost* process); MessageLoop* ui_loop() { return ui_loop_; } int next_worker_route_id() { return ++next_worker_route_id_; } + // Used when multiple workers can run in the same process. + static const int kMaxWorkerProcessesWhenSharing; + + // Used when we run each worker in a separate process. + static const int kMaxWorkersWhenSeparate; + static const int kMaxWorkersPerTabWhenSeparate; + private: friend struct DefaultSingletonTraits<WorkerService>; @@ -67,11 +82,17 @@ class WorkerService : public NotificationObserver { // number of worker instance running. WorkerProcessHost* GetLeastLoadedWorker(); + // Checks if we can create a worker process based on the process limit when + // we're using a strategy of one process per core. + bool CanCreateWorkerProcess(const WorkerProcessHost::WorkerInstance& instance); + NotificationRegistrar registrar_; int next_worker_route_id_; ResourceDispatcherHost* resource_dispatcher_host_; MessageLoop* ui_loop_; + WorkerProcessHost::Instances queued_workers_; + DISALLOW_COPY_AND_ASSIGN(WorkerService); }; |