summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-18 22:51:03 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-18 22:51:03 +0000
commit11de3e98153ad8dcb9e6628e527f7bfb2ca0a8ed (patch)
tree53cd07aaba6e6294b18a43a362980f8aa4a27142 /chrome/browser
parent51570ddfc079a32dc5e78887f730b7aa270b916e (diff)
downloadchromium_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.cc7
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h1
-rw-r--r--chrome/browser/worker_host/worker_process_host.cc35
-rw-r--r--chrome/browser/worker_host/worker_process_host.h33
-rw-r--r--chrome/browser/worker_host/worker_service.cc131
-rw-r--r--chrome/browser/worker_host/worker_service.h23
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);
};