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 | |
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
-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 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 11 | ||||
-rw-r--r-- | chrome/renderer/webworker_proxy.cc | 39 | ||||
-rw-r--r-- | chrome/renderer/webworker_proxy.h | 2 | ||||
-rw-r--r-- | chrome/test/data/workers/many_workers.html | 12 | ||||
-rw-r--r-- | chrome/worker/DEPS | 1 | ||||
-rw-r--r-- | chrome/worker/worker_uitest.cc | 39 | ||||
-rw-r--r-- | webkit/glue/webworker_impl.cc | 3 |
13 files changed, 274 insertions, 63 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); }; diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 594d553..bd3c059 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -594,6 +594,10 @@ IPC_BEGIN_MESSAGES(View) // directory and verify that it is valid. IPC_MESSAGE_CONTROL1(UtilityMsg_UnpackExtension, FilePath /* extension_filename */) + + // Response message to ViewHostMsg_CreateDedicatedWorker. Sent when the + // worker has started. + IPC_MESSAGE_ROUTED0(ViewMsg_DedicatedWorkerCreated) IPC_END_MESSAGES(View) @@ -1371,6 +1375,13 @@ IPC_BEGIN_MESSAGES(ViewHost) int /* render_view_route_id */, int /* route_id */) + // Sent if the worker object has sent a ViewHostMsg_CreateDedicatedWorker + // message and not received a ViewMsg_DedicatedWorkerCreated reply, but in the + // mean time it's destroyed. This tells the browser to not create the queued + // worker. + IPC_MESSAGE_CONTROL1(ViewHostMsg_CancelCreateDedicatedWorker, + int /* route_id */) + // Wraps an IPC message that's destined to the worker on the renderer->browser // hop. IPC_MESSAGE_CONTROL1(ViewHostMsg_ForwardToWorker, diff --git a/chrome/renderer/webworker_proxy.cc b/chrome/renderer/webworker_proxy.cc index d5c5ede..6cec8cc 100644 --- a/chrome/renderer/webworker_proxy.cc +++ b/chrome/renderer/webworker_proxy.cc @@ -25,6 +25,15 @@ WebWorkerProxy::WebWorkerProxy( } WebWorkerProxy::~WebWorkerProxy() { + if (queued_messages_.empty()) + return; + + for (size_t i = 0; i < queued_messages_.size(); ++i) + delete queued_messages_[i]; + + // Tell the browser to not start our queued worker. + if (route_id_ != MSG_ROUTING_NONE) + child_thread_->Send(new ViewHostMsg_CancelCreateDedicatedWorker(route_id_)); } void WebWorkerProxy::startWorkerContext( @@ -37,14 +46,12 @@ void WebWorkerProxy::startWorkerContext( return; child_thread_->AddRoute(route_id_, this); - Send(new WorkerMsg_StartWorkerContext( - route_id_, script_url, user_agent, source_code)); - for (size_t i = 0; i < queued_messages_.size(); ++i) { - queued_messages_[i]->set_routing_id(route_id_); - Send(queued_messages_[i]); - } - queued_messages_.clear(); + // We make sure that the start message is the first, since postMessage might + // have already been called. + queued_messages_.insert(queued_messages_.begin(), + new WorkerMsg_StartWorkerContext( + route_id_, script_url, user_agent, source_code)); } void WebWorkerProxy::terminateWorkerContext() { @@ -66,7 +73,11 @@ void WebWorkerProxy::workerObjectDestroyed() { } bool WebWorkerProxy::Send(IPC::Message* message) { - if (route_id_ == MSG_ROUTING_NONE) { + // It's possible that postMessage is called before the worker is created, in + // which case route_id_ will be none. Or the worker object can be interacted + // with before the browser process told us that it started, in which case we + // also want to queue the message. + if (route_id_ == MSG_ROUTING_NONE || !queued_messages_.empty()) { queued_messages_.push_back(message); return true; } @@ -84,6 +95,8 @@ void WebWorkerProxy::OnMessageReceived(const IPC::Message& message) { return; IPC_BEGIN_MESSAGE_MAP(WebWorkerProxy, message) + IPC_MESSAGE_HANDLER(ViewMsg_DedicatedWorkerCreated, + OnDedicatedWorkerCreated) IPC_MESSAGE_FORWARD(WorkerHostMsg_PostMessageToWorkerObject, client_, WebWorkerClient::postMessageToWorkerObject) @@ -104,3 +117,13 @@ void WebWorkerProxy::OnMessageReceived(const IPC::Message& message) { WebWorkerClient::workerContextDestroyed) IPC_END_MESSAGE_MAP() } + +void WebWorkerProxy::OnDedicatedWorkerCreated() { + DCHECK(queued_messages_.size()); + std::vector<IPC::Message*> queued_messages = queued_messages_; + queued_messages_.clear(); + for (size_t i = 0; i < queued_messages.size(); ++i) { + queued_messages[i]->set_routing_id(route_id_); + Send(queued_messages[i]); + } +} diff --git a/chrome/renderer/webworker_proxy.h b/chrome/renderer/webworker_proxy.h index b2b361d..7dacf07 100644 --- a/chrome/renderer/webworker_proxy.h +++ b/chrome/renderer/webworker_proxy.h @@ -42,6 +42,8 @@ class WebWorkerProxy : public WebKit::WebWorker, private: bool Send(IPC::Message* message); + void OnDedicatedWorkerCreated(); + // The routing id used to reach WebWorkerClientProxy in the worker process. int route_id_; diff --git a/chrome/test/data/workers/many_workers.html b/chrome/test/data/workers/many_workers.html new file mode 100644 index 0000000..656df61 --- /dev/null +++ b/chrome/test/data/workers/many_workers.html @@ -0,0 +1,12 @@ +<html> +<script> +var url = document.location.toString(); +var num_workers = parseInt(url.substr(url.search("count=") + 6)); + +for (var i = 0; i < num_workers; ++i) + var worker = new Worker("worker_common.js"); +</script> + +<body> +</body> +</html> diff --git a/chrome/worker/DEPS b/chrome/worker/DEPS index cf8be8e..5d7c881 100644 --- a/chrome/worker/DEPS +++ b/chrome/worker/DEPS @@ -1,4 +1,5 @@ include_rules = [
+ "+chrome/browser/worker_host", # For UI test.
"+chrome/renderer",
"+chrome/worker",
"+sandbox/src",
diff --git a/chrome/worker/worker_uitest.cc b/chrome/worker/worker_uitest.cc index d4b5095..4cf9014 100644 --- a/chrome/worker/worker_uitest.cc +++ b/chrome/worker/worker_uitest.cc @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/browser/worker_host/worker_service.h" #include "chrome/common/chrome_switches.h" +#include "chrome/test/automation/browser_proxy.h" #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/ui/ui_test.h" @@ -37,3 +39,40 @@ TEST_F(WorkerTest, MultipleWorkers) { RunTest(L"multi_worker.html"); } +TEST_F(WorkerTest, LimitPerPage) { + int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate; + GURL url = GetTestUrl(L"workers", L"many_workers.html"); + url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab + 1)); + + scoped_refptr<TabProxy> tab(GetActiveTab()); + ASSERT_TRUE(tab->NavigateToURL(url)); + + EXPECT_EQ(max_workers_per_tab + 1 + (UITest::in_process_renderer() ? 0 : 1), + UITest::GetBrowserProcessCount()); +} + +TEST_F(WorkerTest, LimitTotal) { + int max_workers_per_tab = WorkerService::kMaxWorkersPerTabWhenSeparate; + int total_workers = WorkerService::kMaxWorkersWhenSeparate; + + int tab_count = (total_workers / max_workers_per_tab) + 1; + GURL url = GetTestUrl(L"workers", L"many_workers.html"); + url = GURL(url.spec() + StringPrintf("?count=%d", max_workers_per_tab)); + + scoped_refptr<TabProxy> tab(GetActiveTab()); + ASSERT_TRUE(tab->NavigateToURL(url)); + scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0)); + for (int i = 1; i < tab_count; ++i) + window->AppendTab(url); + + // Check that we didn't create more than the max number of workers. + EXPECT_EQ(total_workers + 1 + (UITest::in_process_renderer() ? 0 : tab_count), + UITest::GetBrowserProcessCount()); + + // Now close the first tab and check that the queued workers were started. + tab->Close(true); + tab->NavigateToURL(GetTestUrl(L"google", L"google.html")); + + EXPECT_EQ(total_workers + 1 + (UITest::in_process_renderer() ? 0 : tab_count), + UITest::GetBrowserProcessCount()); +} diff --git a/webkit/glue/webworker_impl.cc b/webkit/glue/webworker_impl.cc index 6cd3bd0..b648cf1 100644 --- a/webkit/glue/webworker_impl.cc +++ b/webkit/glue/webworker_impl.cc @@ -184,7 +184,8 @@ void WebWorkerImpl::startWorkerContext(const WebURL& script_url, } void WebWorkerImpl::terminateWorkerContext() { - worker_thread_->stop(); + if (worker_thread_) + worker_thread_->stop(); } void WebWorkerImpl::postMessageToWorkerContext(const WebString& message) { |