diff options
author | atwilson@chromium.org <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-13 01:13:37 +0000 |
---|---|---|
committer | atwilson@chromium.org <atwilson@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-13 01:13:37 +0000 |
commit | 30447b6a5d6109d455f2c6262454105d5adf8f94 (patch) | |
tree | 3ef69964f7cf3e10d662af94f88e05288e16ad8c /chrome | |
parent | 6eca5f19ffabd672349df42595551e7a4b1da987 (diff) | |
download | chromium_src-30447b6a5d6109d455f2c6262454105d5adf8f94.zip chromium_src-30447b6a5d6109d455f2c6262454105d5adf8f94.tar.gz chromium_src-30447b6a5d6109d455f2c6262454105d5adf8f94.tar.bz2 |
Added lifecycle management and sharing support for SharedWorkers. SharedWorkers
can now outlive their parent pages and can be shared by multiple instances
across multiple tabs.
BUG=26233
TEST=ui tests
Review URL: http://codereview.chromium.org/390017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31868 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
22 files changed, 656 insertions, 110 deletions
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc index 01aa313..35ba9be 100644 --- a/chrome/browser/renderer_host/resource_dispatcher_host.cc +++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc @@ -1505,8 +1505,8 @@ bool ResourceDispatcherHost::RenderViewForRequest(const URLRequest* request, *render_view_host_id = -1; return false; } - *render_process_host_id = worker_instance->renderer_id; - *render_view_host_id = worker_instance->render_view_route_id; + *render_process_host_id = worker_instance->renderer_id(); + *render_view_host_id = worker_instance->render_view_route_id(); } else { *render_process_host_id = info->child_id(); *render_view_host_id = info->route_id(); diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index a7d53c0..d40e247 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -310,6 +310,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) { OnOpenChannelToPlugin) IPC_MESSAGE_HANDLER(ViewHostMsg_LaunchNaCl, OnLaunchNaCl) IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWorker, OnCreateWorker) + IPC_MESSAGE_HANDLER(ViewHostMsg_LookupSharedWorker, OnLookupSharedWorker) + IPC_MESSAGE_HANDLER(ViewHostMsg_DocumentDetached, OnDocumentDetached) IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker, OnCancelCreateDedicatedWorker) IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker, @@ -654,15 +656,32 @@ void ResourceMessageFilter::OnCreateWorker(const GURL& url, int* route_id) { *route_id = render_widget_helper_->GetNextRoutingID(); WorkerService::GetInstance()->CreateWorker( - url, is_shared, name, id(), render_view_route_id, this, id(), *route_id); + url, is_shared, name, id(), render_view_route_id, this, *route_id); +} + +void ResourceMessageFilter::OnLookupSharedWorker(const GURL& url, + const string16& name, + unsigned long long document_id, + int* route_id, + bool* url_mismatch) { + int new_route_id = render_widget_helper_->GetNextRoutingID(); + bool worker_found = WorkerService::GetInstance()->LookupSharedWorker( + url, name, document_id, this, new_route_id, url_mismatch); + *route_id = worker_found ? new_route_id : MSG_ROUTING_NONE; +} + +void ResourceMessageFilter::OnDocumentDetached(unsigned long long document_id) { + // Notify the WorkerService that the passed document was detached so any + // associated shared workers can be shut down. + WorkerService::GetInstance()->DocumentDetached(this, document_id); } void ResourceMessageFilter::OnCancelCreateDedicatedWorker(int route_id) { - WorkerService::GetInstance()->CancelCreateDedicatedWorker(id(), route_id); + WorkerService::GetInstance()->CancelCreateDedicatedWorker(this, route_id); } void ResourceMessageFilter::OnForwardToWorker(const IPC::Message& message) { - WorkerService::GetInstance()->ForwardMessage(message, id()); + WorkerService::GetInstance()->ForwardMessage(message, this); } void ResourceMessageFilter::OnDownloadUrl(const IPC::Message& message, diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 577e14a..31f87d4 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -173,6 +173,12 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, const string16& name, int render_view_route_id, int* route_id); + void OnLookupSharedWorker(const GURL& url, + const string16& name, + unsigned long long document_id, + int* route_id, + bool* url_error); + void OnDocumentDetached(unsigned long long document_id); void OnCancelCreateDedicatedWorker(int route_id); void OnForwardToWorker(const IPC::Message& msg); void OnDownloadUrl(const IPC::Message& message, diff --git a/chrome/browser/renderer_host/resource_request_details.h b/chrome/browser/renderer_host/resource_request_details.h index bf84964..c34af0f 100644 --- a/chrome/browser/renderer_host/resource_request_details.h +++ b/chrome/browser/renderer_host/resource_request_details.h @@ -47,7 +47,7 @@ class ResourceRequestDetails { const WorkerProcessHost::WorkerInstance* worker_instance = WorkerService::GetInstance()->FindWorkerInstance(info->child_id()); origin_child_id_ = - worker_instance ? worker_instance->renderer_id : info->child_id(); + worker_instance ? worker_instance->renderer_id() : info->child_id(); } virtual ~ResourceRequestDetails() {} diff --git a/chrome/browser/worker_host/worker_process_host.cc b/chrome/browser/worker_host/worker_process_host.cc index a5cbbb8..de292e9 100644 --- a/chrome/browser/worker_host/worker_process_host.cc +++ b/chrome/browser/worker_host/worker_process_host.cc @@ -80,7 +80,7 @@ WorkerProcessHost::~WorkerProcessHost() { for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) { ChromeThread::PostTask( ChromeThread::UI, FROM_HERE, - new WorkerCrashTask(i->renderer_id, i->render_view_route_id)); + new WorkerCrashTask(i->renderer_id(), i->render_view_route_id())); } ChildProcessSecurityPolicy::GetInstance()->Remove(id()); @@ -141,26 +141,25 @@ bool WorkerProcessHost::Init() { void WorkerProcessHost::CreateWorker(const WorkerInstance& instance) { ChildProcessSecurityPolicy::GetInstance()->GrantRequestURL( - id(), instance.url); + id(), instance.url()); instances_.push_back(instance); - Send(new WorkerProcessMsg_CreateWorker(instance.url, - instance.is_shared, - instance.name, - instance.worker_route_id)); + Send(new WorkerProcessMsg_CreateWorker(instance.url(), + instance.is_shared(), + instance.name(), + instance.worker_route_id())); UpdateTitle(); - instances_.back().sender->Send( - new ViewMsg_WorkerCreated(instance.sender_route_id)); + WorkerInstance::SenderInfo info = instances_.back().GetSender(); + info.first->Send(new ViewMsg_WorkerCreated(info.second)); } bool WorkerProcessHost::FilterMessage(const IPC::Message& message, - int sender_pid) { + IPC::Message::Sender* sender) { for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) { - if (i->sender_id == sender_pid && - i->sender_route_id == message.routing_id()) { + if (!i->is_closed() && i->HasSender(sender, message.routing_id())) { RelayMessage( - message, this, i->worker_route_id, next_route_id_callback_.get()); + message, this, i->worker_route_id(), next_route_id_callback_.get()); return true; } } @@ -174,6 +173,20 @@ URLRequestContext* WorkerProcessHost::GetRequestContext( return NULL; } +// Sent to notify the browser process when a worker context invokes close(), so +// no new connections are sent to shared workers. +void WorkerProcessHost::OnWorkerContextClosed(int worker_route_id) { + for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) { + if (i->worker_route_id() == worker_route_id) { + // Set the closed flag - this will stop any further messages from + // being sent to the worker (messages can still be sent from the worker, + // for exception reporting, etc). + i->set_closed(true); + break; + } + } +} + void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) { bool msg_is_ok = true; bool handled = MessagePortDispatcher::GetInstance()->OnMessageReceived( @@ -183,8 +196,11 @@ void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) { handled = true; IPC_BEGIN_MESSAGE_MAP_EX(WorkerProcessHost, message, msg_is_ok) IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWorker, OnCreateWorker) + IPC_MESSAGE_HANDLER(ViewHostMsg_LookupSharedWorker, OnLookupSharedWorker) IPC_MESSAGE_HANDLER(ViewHostMsg_CancelCreateDedicatedWorker, OnCancelCreateDedicatedWorker) + IPC_MESSAGE_HANDLER(WorkerHostMsg_WorkerContextClosed, + OnWorkerContextClosed); IPC_MESSAGE_HANDLER(ViewHostMsg_ForwardToWorker, OnForwardToWorker) IPC_MESSAGE_UNHANDLED(handled = false) @@ -200,10 +216,15 @@ void WorkerProcessHost::OnMessageReceived(const IPC::Message& message) { return; for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) { - if (i->worker_route_id == message.routing_id()) { - CallbackWithReturnValue<int>::Type* next_route_id = - GetNextRouteIdCallback(i->sender); - RelayMessage(message, i->sender, i->sender_route_id, next_route_id); + if (i->worker_route_id() == message.routing_id()) { + if (!i->is_shared()) { + // Don't relay messages from shared workers (all communication is via + // the message port). + WorkerInstance::SenderInfo info = i->GetSender(); + CallbackWithReturnValue<int>::Type* next_route_id = + GetNextRouteIdCallback(info.first); + RelayMessage(message, info.first, info.second, next_route_id); + } if (message.type() == WorkerHostMsg_WorkerContextDestroyed::ID) { instances_.erase(i); @@ -293,8 +314,18 @@ void WorkerProcessHost::RelayMessage( void WorkerProcessHost::SenderShutdown(IPC::Message::Sender* sender) { for (Instances::iterator i = instances_.begin(); i != instances_.end();) { - if (i->sender == sender) { - Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id)); + bool shutdown = false; + i->RemoveSenders(sender); + if (i->is_shared()) { + i->RemoveAllAssociatedDocuments(sender); + if (i->IsDocumentSetEmpty()) { + shutdown = true; + } + } else if (i->NumSenders() == 0) { + shutdown = true; + } + if (shutdown) { + Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id())); i = instances_.erase(i); } else { ++i; @@ -306,13 +337,13 @@ void WorkerProcessHost::UpdateTitle() { std::set<std::string> titles; for (Instances::iterator i = instances_.begin(); i != instances_.end(); ++i) { std::string title = - net::RegistryControlledDomainService::GetDomainAndRegistry(i->url); + net::RegistryControlledDomainService::GetDomainAndRegistry(i->url()); // Use the host name if the domain is empty, i.e. localhost or IP address. if (title.empty()) - title = i->url.host(); + title = i->url().host(); // If the host name is empty, i.e. file url, use the path. if (title.empty()) - title = i->url.path(); + title = i->url().path(); titles.insert(title); } @@ -327,6 +358,17 @@ void WorkerProcessHost::UpdateTitle() { set_name(ASCIIToWide(display_title)); } +void WorkerProcessHost::OnLookupSharedWorker(const GURL& url, + const string16& name, + unsigned long long document_id, + int* route_id, + bool* url_mismatch) { + int new_route_id = WorkerService::GetInstance()->next_worker_route_id(); + bool worker_found = WorkerService::GetInstance()->LookupSharedWorker( + url, name, document_id, this, new_route_id, url_mismatch); + *route_id = worker_found ? new_route_id : MSG_ROUTING_NONE; +} + void WorkerProcessHost::OnCreateWorker(const GURL& url, bool is_shared, const string16& name, @@ -335,14 +377,149 @@ void WorkerProcessHost::OnCreateWorker(const GURL& url, DCHECK(instances_.size() == 1); // Only called when one process per worker. *route_id = WorkerService::GetInstance()->next_worker_route_id(); WorkerService::GetInstance()->CreateWorker( - url, is_shared, name, instances_.front().renderer_id, - instances_.front().render_view_route_id, this, id(), *route_id); + url, is_shared, name, instances_.front().renderer_id(), + instances_.front().render_view_route_id(), this, *route_id); } void WorkerProcessHost::OnCancelCreateDedicatedWorker(int route_id) { - WorkerService::GetInstance()->CancelCreateDedicatedWorker(id(), route_id); + WorkerService::GetInstance()->CancelCreateDedicatedWorker(this, route_id); } void WorkerProcessHost::OnForwardToWorker(const IPC::Message& message) { - WorkerService::GetInstance()->ForwardMessage(message, id()); + WorkerService::GetInstance()->ForwardMessage(message, this); +} + +void WorkerProcessHost::DocumentDetached(IPC::Message::Sender* parent, + unsigned long long document_id) +{ + // Walk all instances and remove the document from their document set. + for (Instances::iterator i = instances_.begin(); i != instances_.end();) { + if (!i->is_shared()) { + ++i; + } else { + i->RemoveFromDocumentSet(parent, document_id); + if (i->IsDocumentSetEmpty()) { + // This worker has no more associated documents - shut it down. + Send(new WorkerMsg_TerminateWorkerContext(i->worker_route_id())); + i = instances_.erase(i); + } else { + ++i; + } + } + } +} + +WorkerProcessHost::WorkerInstance::WorkerInstance(const GURL& url, + bool is_shared, + const string16& name, + int renderer_id, + int render_view_route_id, + int worker_route_id) + : url_(url), + shared_(is_shared), + closed_(false), + name_(name), + renderer_id_(renderer_id), + render_view_route_id_(render_view_route_id), + worker_route_id_(worker_route_id) { +} + +// Compares an instance based on the algorithm in the WebWorkers spec - an +// instance matches if the origins of the URLs match, and: +// a) the names are non-empty and equal +// -or- +// b) the names are both empty, and the urls are equal +bool WorkerProcessHost::WorkerInstance::Matches( + const GURL& match_url, const string16& match_name) const { + // Only match open shared workers. + if (!shared_ || closed_) + return false; + + if (url_.GetOrigin() != match_url.GetOrigin()) + return false; + + if (name_.empty() && match_name.empty()) + return url_ == match_url; + + return name_ == match_name; +} + +void WorkerProcessHost::WorkerInstance::AddToDocumentSet( + IPC::Message::Sender* parent, unsigned long long document_id) { + DocumentInfo info(parent, document_id); + document_set_.insert(info); +} + +bool WorkerProcessHost::WorkerInstance::IsInDocumentSet( + IPC::Message::Sender* parent, unsigned long long document_id) const { + DocumentInfo info(parent, document_id); + return document_set_.find(info) != document_set_.end(); +} + +void WorkerProcessHost::WorkerInstance::RemoveFromDocumentSet( + IPC::Message::Sender* parent, unsigned long long document_id) { + DocumentInfo info(parent, document_id); + document_set_.erase(info); } + +void WorkerProcessHost::WorkerInstance::RemoveAllAssociatedDocuments( + IPC::Message::Sender* parent) { + for (DocumentSet::iterator i = document_set_.begin(); + i != document_set_.end();) { + // Windows set.erase() has a non-standard API (invalidates the iter). +#if defined(OS_WIN) + if (i->first == parent) + i = document_set_.erase(i); + else + ++i; +#else + if (i->first == parent) + document_set_.erase(i); + ++i; +#endif + } +} + +void WorkerProcessHost::WorkerInstance::AddSender(IPC::Message::Sender* sender, + int sender_route_id) { + SenderInfo info(sender, sender_route_id); + senders_.insert(info); + // Only shared workers can have more than one associated sender. + DCHECK(shared_ || senders_.size() == 1); +} + +void WorkerProcessHost::WorkerInstance::RemoveSender( + IPC::Message::Sender* sender, int sender_route_id) { + SenderInfo info(sender, sender_route_id); + senders_.erase(info); +} + +void WorkerProcessHost::WorkerInstance::RemoveSenders( + IPC::Message::Sender* sender) { + for (SenderSet::iterator i = senders_.begin(); i != senders_.end();) { + // Windows set.erase() has a non-standard API (invalidates the iter). +#if defined(OS_WIN) + if (i->first == sender) + i = senders_.erase(i); + else + ++i; +#else + if (i->first == sender) + senders_.erase(i); + ++i; +#endif + } +} + +bool WorkerProcessHost::WorkerInstance::HasSender( + IPC::Message::Sender* sender, int sender_route_id) const { + SenderInfo info(sender, sender_route_id); + return senders_.find(info) != senders_.end(); +} + +WorkerProcessHost::WorkerInstance::SenderInfo +WorkerProcessHost::WorkerInstance::GetSender() const { + DCHECK(NumSenders() == 1); + return *senders_.begin(); +} + diff --git a/chrome/browser/worker_host/worker_process_host.h b/chrome/browser/worker_host/worker_process_host.h index 1fae373..16ddd13 100644 --- a/chrome/browser/worker_host/worker_process_host.h +++ b/chrome/browser/worker_host/worker_process_host.h @@ -17,16 +17,82 @@ 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; - bool is_shared; - string16 name; - int renderer_id; - int render_view_route_id; - int worker_route_id; - IPC::Message::Sender* sender; - int sender_id; - int sender_route_id; + class WorkerInstance { + public: + WorkerInstance(const GURL& url, + bool is_shared, + const string16& name, + int renderer_id, + int render_view_route_id, + int worker_route_id); + + // Unique identifier for a worker client. + typedef std::pair<IPC::Message::Sender*, int> SenderInfo; + + // APIs to manage the sender list for a given instance. + void AddSender(IPC::Message::Sender* sender, int sender_route_id); + void RemoveSender(IPC::Message::Sender* sender, int sender_route_id); + void RemoveSenders(IPC::Message::Sender* sender); + bool HasSender(IPC::Message::Sender* sender, int sender_route_id) const; + int NumSenders() const { return senders_.size(); } + // Returns the single sender (must only be one). + SenderInfo GetSender() const; + + // Checks if this WorkerInstance matches the passed url/name params + // (per the comparison algorithm in the WebWorkers spec). This API only + // applies to shared workers. + bool Matches(const GURL& url, const string16& name) const; + + // Adds a document to a shared worker's document set. + void AddToDocumentSet(IPC::Message::Sender* parent, + unsigned long long document_id); + + // Checks to see if a document is in a shared worker's document set. + bool IsInDocumentSet(IPC::Message::Sender* parent, + unsigned long long document_id) const; + + // Removes a specific document from a shared worker's document set when + // that document is detached. + void RemoveFromDocumentSet(IPC::Message::Sender* parent, + unsigned long long document_id); + + // Copies the document set from one instance to another + void CopyDocumentSet(const WorkerInstance& instance) { + document_set_ = instance.document_set_; + }; + + // Invoked when a render process exits, to remove all associated documents + // from a shared worker's document set. + void RemoveAllAssociatedDocuments(IPC::Message::Sender* parent); + + bool IsDocumentSetEmpty() const { return document_set_.empty(); } + + + // Accessors + bool is_shared() const { return shared_; } + bool is_closed() const { return closed_; } + void set_closed(bool closed) { closed_ = closed; } + const GURL& url() const { return url_; } + const string16 name() const { return name_; } + int renderer_id() const { return renderer_id_; } + int render_view_route_id() const { return render_view_route_id_; } + int worker_route_id() const { return worker_route_id_; } + + private: + // Unique identifier for an associated document. + typedef std::pair<IPC::Message::Sender*, unsigned long long> DocumentInfo; + typedef std::set<DocumentInfo> DocumentSet; + // Set of all senders (clients) associated with this worker. + typedef std::set<SenderInfo> SenderSet; + GURL url_; + bool shared_; + bool closed_; + string16 name_; + int renderer_id_; + int render_view_route_id_; + int worker_route_id_; + SenderSet senders_; + DocumentSet document_set_; }; WorkerProcessHost(ResourceDispatcherHost* resource_dispatcher_host_); @@ -40,15 +106,21 @@ class WorkerProcessHost : public ChildProcessHost { // Returns true iff the given message from a renderer process was forwarded to // the worker. - bool FilterMessage(const IPC::Message& message, int sender_pid); + bool FilterMessage(const IPC::Message& message, IPC::Message::Sender* sender); void SenderShutdown(IPC::Message::Sender* sender); + // Shuts down any shared workers that are no longer referenced by active + // documents. + void DocumentDetached(IPC::Message::Sender* sender, + unsigned long long document_id); + protected: friend class WorkerService; typedef std::list<WorkerInstance> Instances; const Instances& instances() const { return instances_; } + Instances& mutable_instances() { return instances_; } private: // ResourceDispatcherHost::Receiver implementation: @@ -59,6 +131,16 @@ class WorkerProcessHost : public ChildProcessHost { // Called when a message arrives from the worker process. void OnMessageReceived(const IPC::Message& message); + // Called when the app invokes close() from within worker context. + void OnWorkerContextClosed(int worker_route_id); + + // Called if a worker tries to connect to a shared worker. + void OnLookupSharedWorker(const GURL& url, + const string16& name, + unsigned long long document_id, + int* route_id, + bool* url_error); + // Given a Sender, returns the callback that generates a new routing id. static CallbackWithReturnValue<int>::Type* GetNextRouteIdCallback( IPC::Message::Sender* sender); diff --git a/chrome/browser/worker_host/worker_service.cc b/chrome/browser/worker_host/worker_service.cc index 334917f..404f0a7 100644 --- a/chrome/browser/worker_host/worker_service.cc +++ b/chrome/browser/worker_host/worker_service.cc @@ -15,6 +15,7 @@ #include "chrome/browser/worker_host/worker_process_host.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/notification_service.h" +#include "chrome/common/render_messages.h" #include "chrome/common/worker_messages.h" #include "net/base/registry_controlled_domain.h" @@ -50,22 +51,18 @@ bool WorkerService::CreateWorker(const GURL &url, int renderer_id, int render_view_route_id, IPC::Message::Sender* sender, - int sender_id, int sender_route_id) { // 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.name = name; - instance.renderer_id = renderer_id; - instance.render_view_route_id = render_view_route_id; - instance.worker_route_id = next_worker_route_id(); - instance.sender = sender; - instance.sender_id = sender_id; - instance.sender_route_id = sender_route_id; - instance.is_shared = is_shared; + WorkerProcessHost::WorkerInstance instance(url, + is_shared, + name, + renderer_id, + render_view_route_id, + next_worker_route_id()); + instance.AddSender(sender, sender_route_id); WorkerProcessHost* worker = NULL; if (CommandLine::ForCurrentProcess()->HasSwitch( @@ -81,6 +78,38 @@ bool WorkerService::CreateWorker(const GURL &url, } } + // Check to see if this shared worker is already running (two pages may have + // tried to start up the worker simultaneously). + if (is_shared) { + // See if a worker with this name already exists. + WorkerProcessHost::WorkerInstance* existing_instance = + FindSharedWorkerInstance(url, name); + // If this worker is already running, no need to create a new copy. Just + // inform the caller that the worker has been created. + if (existing_instance) { + existing_instance->AddSender(sender, sender_route_id); + sender->Send(new ViewMsg_WorkerCreated(sender_route_id)); + return true; + } + + // Look to see if there's a pending instance. + WorkerProcessHost::WorkerInstance* pending = FindPendingInstance(url, name); + // If there's no instance *and* no pending instance, then it means the + // worker started up and exited already. Log a warning because this should + // be a very rare occurrence and is probably a bug, but it *can* happen so + // handle it gracefully. + if (!pending) { + DLOG(WARNING) << "Pending worker already exited"; + return false; + } + + // Assign the accumulated document set and sender list for this pending + // worker to the new instance. + DCHECK(!pending->IsDocumentSetEmpty()); + instance.CopyDocumentSet(*pending); + RemovePendingInstance(url, name); + } + if (!worker) { worker = new WorkerProcessHost(resource_dispatcher_host_); if (!worker->Init()) { @@ -93,15 +122,88 @@ bool WorkerService::CreateWorker(const GURL &url, return true; } -void WorkerService::CancelCreateDedicatedWorker(int sender_id, +bool WorkerService::LookupSharedWorker(const GURL &url, + const string16& name, + unsigned long long document_id, + IPC::Message::Sender* sender, + int sender_route_id, + bool* url_mismatch) { + bool found_instance = true; + WorkerProcessHost::WorkerInstance* instance = + FindSharedWorkerInstance(url, name); + + if (!instance) { + // If no worker instance currently exists, we need to create a pending + // instance - this is to make sure that any subsequent lookups passing a + // mismatched URL get the appropriate url_mismatch error at lookup time. + // Having named shared workers was a Really Bad Idea due to details like + // this. + instance = CreatePendingInstance(url, name); + found_instance = false; + } + + // Make sure the passed-in instance matches the URL - if not, return an + // error. + if (url != instance->url()) { + *url_mismatch = true; + return false; + } else { + *url_mismatch = false; + } + + // Add our route ID to the existing instance so we can send messages to it. + if (found_instance) + instance->AddSender(sender, sender_route_id); + + // Add the passed sender/document_id to the worker instance. + instance->AddToDocumentSet(sender, document_id); + return found_instance; +} + +void WorkerService::DocumentDetached(IPC::Message::Sender* sender, + unsigned long long document_id) { + for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); + !iter.Done(); ++iter) { + WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); + worker->DocumentDetached(sender, document_id); + } + + // Remove any queued shared workers for this document. + for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin(); + iter != queued_workers_.end();) { + if (iter->is_shared()) { + iter->RemoveFromDocumentSet(sender, document_id); + if (iter->IsDocumentSetEmpty()) { + iter = queued_workers_.erase(iter); + continue; + } + } + ++iter; + } + + // Remove the document from any pending shared workers. + for (WorkerProcessHost::Instances::iterator iter = + pending_shared_workers_.begin(); + iter != pending_shared_workers_.end(); ) { + iter->RemoveFromDocumentSet(sender, document_id); + if (iter->IsDocumentSetEmpty()) { + iter = pending_shared_workers_.erase(iter); + } else { + ++iter; + } + } + +} + +void WorkerService::CancelCreateDedicatedWorker(IPC::Message::Sender* sender, int sender_route_id) { for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); i != queued_workers_.end(); ++i) { - if (i->sender_id == sender_id && - i->sender_route_id == sender_route_id) { - queued_workers_.erase(i); - return; - } + if (i->HasSender(sender, sender_route_id)) { + DCHECK(!i->is_shared()); + queued_workers_.erase(i); + return; + } } // There could be a race condition where the WebWorkerProxy told us to cancel @@ -113,12 +215,11 @@ void WorkerService::CancelCreateDedicatedWorker(int sender_id, for (WorkerProcessHost::Instances::const_iterator instance = worker->instances().begin(); instance != worker->instances().end(); ++instance) { - if (instance->sender_id == sender_id && - instance->sender_route_id == sender_route_id) { + if (instance->HasSender(sender, sender_route_id)) { // Fake a worker destroyed message so that WorkerProcessHost cleans up // properly. WorkerHostMsg_WorkerContextDestroyed msg(sender_route_id); - ForwardMessage(msg, sender_id); + ForwardMessage(msg, sender); return; } } @@ -128,11 +229,11 @@ void WorkerService::CancelCreateDedicatedWorker(int sender_id, } void WorkerService::ForwardMessage(const IPC::Message& message, - int sender_pid) { + IPC::Message::Sender* sender) { for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); !iter.Done(); ++iter) { WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); - if (worker->FilterMessage(message, sender_pid)) + if (worker->FilterMessage(message, sender)) return; } @@ -151,7 +252,7 @@ WorkerProcessHost* WorkerService::GetProcessForDomain(const GURL& url) { worker->instances().begin(); instance != worker->instances().end(); ++instance) { if (net::RegistryControlledDomainService::GetDomainAndRegistry( - instance->url) == domain) { + instance->url()) == domain) { return worker; } } @@ -200,8 +301,9 @@ bool WorkerService::CanCreateWorkerProcess( total_workers++; if (total_workers >= kMaxWorkersWhenSeparate) return false; - if (cur_instance->renderer_id == instance.renderer_id && - cur_instance->render_view_route_id == instance.render_view_route_id) { + if (cur_instance->renderer_id() == instance.renderer_id() && + cur_instance->render_view_route_id() == + instance.render_view_route_id()) { workers_per_tab++; if (workers_per_tab >= kMaxWorkersPerTabWhenSeparate) return false; @@ -237,12 +339,25 @@ void WorkerService::SenderShutdown(IPC::Message::Sender* 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->RemoveSenders(sender); + if (i->NumSenders() == 0) { i = queued_workers_.erase(i); } else { ++i; } } + + // Also, see if that render process had any pending shared workers. + for (WorkerProcessHost::Instances::iterator iter = + pending_shared_workers_.begin(); + iter != pending_shared_workers_.end(); ) { + iter->RemoveAllAssociatedDocuments(sender); + if (iter->IsDocumentSetEmpty()) { + iter = pending_shared_workers_.erase(iter); + } else { + ++iter; + } + } } void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) { @@ -281,3 +396,64 @@ const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance( } return NULL; } + +WorkerProcessHost::WorkerInstance* +WorkerService::FindSharedWorkerInstance(const GURL& url, const string16& name) { + for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); + !iter.Done(); ++iter) { + WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); + for (WorkerProcessHost::Instances::iterator instance_iter = + worker->mutable_instances().begin(); + instance_iter != worker->mutable_instances().end(); + ++instance_iter) { + if (instance_iter->Matches(url, name)) + return &(*instance_iter); + } + } + return NULL; +} + +WorkerProcessHost::WorkerInstance* +WorkerService::FindPendingInstance(const GURL& url, const string16& name) { + // Walk the pending instances looking for a matching pending worker. + for (WorkerProcessHost::Instances::iterator iter = + pending_shared_workers_.begin(); + iter != pending_shared_workers_.end(); + ++iter) { + if (iter->Matches(url, name)) { + return &(*iter); + } + } + return NULL; +} + + +void WorkerService::RemovePendingInstance(const GURL& url, + const string16& name) { + // Walk the pending instances looking for a matching pending worker. + for (WorkerProcessHost::Instances::iterator iter = + pending_shared_workers_.begin(); + iter != pending_shared_workers_.end(); + ++iter) { + if (iter->Matches(url, name)) { + pending_shared_workers_.erase(iter); + break; + } + } +} + +WorkerProcessHost::WorkerInstance* +WorkerService::CreatePendingInstance(const GURL& url, + const string16& name) { + // Look for an existing pending worker. + WorkerProcessHost::WorkerInstance* instance = + FindPendingInstance(url, name); + if (instance) + return instance; + + // No existing pending worker - create a new one. + WorkerProcessHost::WorkerInstance pending( + url, true, name, 0, MSG_ROUTING_NONE, MSG_ROUTING_NONE); + pending_shared_workers_.push_back(pending); + return &pending_shared_workers_.back(); +} diff --git a/chrome/browser/worker_host/worker_service.h b/chrome/browser/worker_host/worker_service.h index 40267aa..0de4121 100644 --- a/chrome/browser/worker_host/worker_service.h +++ b/chrome/browser/worker_host/worker_service.h @@ -32,15 +32,32 @@ class WorkerService : public NotificationObserver { int renderer_pid, int render_view_route_id, IPC::Message::Sender* sender, - int sender_id, int sender_route_id); + // Validates the passed URL and checks for the existence of matching shared + // worker. Returns true if the url was found, and sets the url_mismatch out + // param to true/false depending on whether there's a url mismatch with an + // existing shared worker with the same name. + bool LookupSharedWorker(const GURL &url, + const string16& name, + unsigned long long document_id, + IPC::Message::Sender* sender, + int sender_route_id, + bool* url_mismatch); + + // Notification from the renderer that a given document has detached, so any + // associated shared workers can be shut down. + void DocumentDetached(IPC::Message::Sender* sender, + unsigned long long document_id); + // Cancel creation of a dedicated worker that hasn't started yet. - void CancelCreateDedicatedWorker(int sender_id, int sender_route_id); + void CancelCreateDedicatedWorker(IPC::Message::Sender* sender, + 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_id); + void ForwardMessage(const IPC::Message& message, + IPC::Message::Sender* sender); int next_worker_route_id() { return ++next_worker_route_id_; } @@ -49,6 +66,9 @@ class WorkerService : public NotificationObserver { const WorkerProcessHost::WorkerInstance* FindWorkerInstance( int worker_process_id); + WorkerProcessHost::WorkerInstance* FindSharedWorkerInstance( + const GURL& url, const string16& name); + // Used when multiple workers can run in the same process. static const int kMaxWorkerProcessesWhenSharing; @@ -90,12 +110,24 @@ class WorkerService : public NotificationObserver { // Notifies us that a worker process has closed. void WorkerProcessDestroyed(WorkerProcessHost* process); + // APIs for manipulating our set of pending shared worker instances. + WorkerProcessHost::WorkerInstance* CreatePendingInstance( + const GURL& url, const string16& name); + WorkerProcessHost::WorkerInstance* FindPendingInstance( + const GURL& url, const string16& name); + void RemovePendingInstance(const GURL& url, const string16& name); + NotificationRegistrar registrar_; int next_worker_route_id_; ResourceDispatcherHost* resource_dispatcher_host_; WorkerProcessHost::Instances queued_workers_; + // These are shared workers that have been looked up, but not created yet. + // We need to keep a list of these to synchronously detect shared worker + // URL mismatches when two pages launch shared workers simultaneously. + WorkerProcessHost::Instances pending_shared_workers_; + DISALLOW_COPY_AND_ASSIGN(WorkerService); }; diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 2ad32ab..a5c5f35 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1745,6 +1745,27 @@ IPC_BEGIN_MESSAGES(ViewHost) int /* render_view_route_id */, int /* route_id */) + // This message is sent to the browser to see if an instance of this shared + // worker already exists (returns route_id != MSG_ROUTING_NONE). This route + // id can be used to forward messages to the worker via ForwardToWorker. If a + // non-empty name is passed, also validates that the url matches the url of + // the existing worker. If a matching worker is found, the passed-in + // document_id is associated with that worker, to ensure that the worker + // stays alive until the document is detached. + IPC_SYNC_MESSAGE_CONTROL3_2(ViewHostMsg_LookupSharedWorker, + GURL /* url */, + string16 /* name */, + unsigned long long /* document_id */, + int /* route_id */, + bool /* url_mismatch */) + + // A renderer sends this to the browser process when a document has been + // detached. The browser will use this to constrain the lifecycle of worker + // processes (SharedWorkers are shut down when their last associated document + // is detached). + IPC_MESSAGE_CONTROL1(ViewHostMsg_DocumentDetached, + unsigned long long /* document_id */) + // A message sent to the browser on behalf of a renderer which wants to show // a desktop notification. IPC_MESSAGE_ROUTED3(ViewHostMsg_ShowDesktopNotification, diff --git a/chrome/common/worker_messages_internal.h b/chrome/common/worker_messages_internal.h index 04c983c..be0f271 100644 --- a/chrome/common/worker_messages_internal.h +++ b/chrome/common/worker_messages_internal.h @@ -123,5 +123,7 @@ IPC_BEGIN_MESSAGES(WorkerHost) IPC_MESSAGE_ROUTED1(WorkerHostMsg_ReportPendingActivity, bool /* bool has_pending_activity */) + IPC_MESSAGE_CONTROL1(WorkerHostMsg_WorkerContextClosed, + int /* worker_route_id */) IPC_MESSAGE_ROUTED0(WorkerHostMsg_WorkerContextDestroyed) IPC_END_MESSAGES(WorkerHost) diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 006ae43..aa8d86d 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -1805,13 +1805,19 @@ WebWorker* RenderView::createWorker(WebFrame* frame, WebWorkerClient* client) { WebSharedWorker* RenderView::createSharedWorker( WebFrame* frame, const WebURL& url, const WebString& name, - unsigned long long documentId) { + unsigned long long document_id) { - // TODO(atwilson): Call to the browser process to check if there's an existing - // worker (passing MSG_ROUTING_NONE for now, to indicate no existing worker). - int worker_route_id = MSG_ROUTING_NONE; - return new WebSharedWorkerProxy( - RenderThread::current(), worker_route_id, routing_id_); + int route_id = MSG_ROUTING_NONE; + bool url_mismatch = false; + Send(new ViewHostMsg_LookupSharedWorker( + url, name, document_id, &route_id, &url_mismatch)); + if (url_mismatch) { + return NULL; + } else { + return new WebSharedWorkerProxy(RenderThread::current(), + route_id, + routing_id_); + } } WebMediaPlayer* RenderView::createMediaPlayer( diff --git a/chrome/renderer/websharedworker_proxy.cc b/chrome/renderer/websharedworker_proxy.cc index 7ad1f61..1d5425f 100644 --- a/chrome/renderer/websharedworker_proxy.cc +++ b/chrome/renderer/websharedworker_proxy.cc @@ -13,7 +13,7 @@ WebSharedWorkerProxy::WebSharedWorkerProxy(ChildThread* child_thread, int route_id, int render_view_route_id) : WebWorkerBase(child_thread, route_id, render_view_route_id), - m_connectListener(NULL) { + connect_listener_(NULL) { } bool WebSharedWorkerProxy::isStarted() { @@ -25,6 +25,7 @@ void WebSharedWorkerProxy::startWorkerContext( const WebKit::WebString& name, const WebKit::WebString& user_agent, const WebKit::WebString& source_code) { + DCHECK(!isStarted()); CreateWorkerContext(script_url, true, name, user_agent, source_code); } @@ -49,7 +50,7 @@ void WebSharedWorkerProxy::connect(WebKit::WebMessagePortChannel* channel, Send(new WorkerMsg_Connect(route_id_, message_port_id, MSG_ROUTING_NONE)); if (HasQueuedMessages()) { - m_connectListener = listener; + connect_listener_ = listener; } else { listener->connected(); // The listener may free this object, so do not access the object after @@ -70,8 +71,7 @@ void WebSharedWorkerProxy::OnWorkerCreated() { // Inform any listener that the pending connect event has been sent // (this can result in this object being freed). - if (m_connectListener) { - m_connectListener->connected(); + if (connect_listener_) { + connect_listener_->connected(); } } - diff --git a/chrome/renderer/websharedworker_proxy.h b/chrome/renderer/websharedworker_proxy.h index 68dab47..c3143db 100644 --- a/chrome/renderer/websharedworker_proxy.h +++ b/chrome/renderer/websharedworker_proxy.h @@ -20,6 +20,7 @@ class ChildThread; class WebSharedWorkerProxy : public WebKit::WebSharedWorker, private WebWorkerBase { public: + // If the worker not loaded yet, route_id == MSG_ROUTING_NONE WebSharedWorkerProxy(ChildThread* child_thread, int route_id, int render_view_route_id); @@ -35,13 +36,13 @@ class WebSharedWorkerProxy : public WebKit::WebSharedWorker, virtual void terminateWorkerContext(); virtual void clientDestroyed(); - // IPC::Channel::Listener proxyementation. + // IPC::Channel::Listener implementation. void OnMessageReceived(const IPC::Message& message); private: void OnWorkerCreated(); - ConnectListener* m_connectListener; + ConnectListener* connect_listener_; DISALLOW_COPY_AND_ASSIGN(WebSharedWorkerProxy); }; diff --git a/chrome/renderer/websharedworkerrepository_impl.cc b/chrome/renderer/websharedworkerrepository_impl.cc index 24664b7..99f2a3b 100644 --- a/chrome/renderer/websharedworkerrepository_impl.cc +++ b/chrome/renderer/websharedworkerrepository_impl.cc @@ -4,21 +4,24 @@ #include "chrome/renderer/websharedworkerrepository_impl.h" +#include "chrome/common/render_messages.h" +#include "chrome/renderer/render_thread.h" #include "chrome/renderer/websharedworker_proxy.h" void WebSharedWorkerRepositoryImpl::addSharedWorker( WebKit::WebSharedWorker* worker, DocumentID document) { - // TODO(atwilson): Track shared worker creation here. + shared_worker_parents_.insert(document); } -void WebSharedWorkerRepositoryImpl::documentDetached( - DocumentID document) { - // TODO(atwilson): Update this to call to WorkerService to shutdown any - // associated SharedWorkers. +void WebSharedWorkerRepositoryImpl::documentDetached(DocumentID document) { + DocumentSet::iterator iter = shared_worker_parents_.find(document); + if (iter != shared_worker_parents_.end()) { + // Notify the browser process that the document has shut down. + ChildThread::current()->Send(new ViewHostMsg_DocumentDetached(document)); + shared_worker_parents_.erase(iter); + } } -bool WebSharedWorkerRepositoryImpl::hasSharedWorkers( - DocumentID document) { - // TODO(atwilson): Update this when we track shared worker creation. - return false; +bool WebSharedWorkerRepositoryImpl::hasSharedWorkers(DocumentID document) { + return shared_worker_parents_.find(document) != shared_worker_parents_.end(); } diff --git a/chrome/renderer/websharedworkerrepository_impl.h b/chrome/renderer/websharedworkerrepository_impl.h index d8cec99..5806485 100644 --- a/chrome/renderer/websharedworkerrepository_impl.h +++ b/chrome/renderer/websharedworkerrepository_impl.h @@ -7,14 +7,24 @@ #include "third_party/WebKit/WebKit/chromium/public/WebSharedWorkerRepository.h" +#include "base/hash_tables.h" + namespace WebKit { class WebSharedWorker; } class WebSharedWorkerRepositoryImpl : public WebKit::WebSharedWorkerRepository { + public: virtual void addSharedWorker(WebKit::WebSharedWorker*, DocumentID document); virtual void documentDetached(DocumentID document); + + // Returns true if the document has created a SharedWorker (used by the + // WebKit code to determine if the document can be suspended). virtual bool hasSharedWorkers(DocumentID document); + private: + // The set of documents that have created a SharedWorker. + typedef base::hash_set<DocumentID> DocumentSet; + DocumentSet shared_worker_parents_; }; #endif // CHROME_RENDERER_WEB_SHARED_WORKER_REPOSITORY_IMPL_H_ diff --git a/chrome/renderer/webworker_base.h b/chrome/renderer/webworker_base.h index 0693863..fe5becc 100644 --- a/chrome/renderer/webworker_base.h +++ b/chrome/renderer/webworker_base.h @@ -36,7 +36,7 @@ class WebWorkerBase : public IPC::Channel::Listener { bool IsStarted(); // Disconnects the worker (stops listening for incoming messages). - virtual void Disconnect(); + void Disconnect(); // Sends a message to the worker thread (forwarded via the RenderViewHost). // If WorkerStarted() has not yet been called, message is queued. diff --git a/chrome/renderer/webworker_proxy.cc b/chrome/renderer/webworker_proxy.cc index a263565..fdcc9f1 100644 --- a/chrome/renderer/webworker_proxy.cc +++ b/chrome/renderer/webworker_proxy.cc @@ -26,16 +26,18 @@ WebWorkerProxy::WebWorkerProxy( client_(client) { } -void WebWorkerProxy::Disconnect() { +WebWorkerProxy::~WebWorkerProxy() { + // If we're midway through starting a worker, cancel it. + CancelCreation(); +} + +void WebWorkerProxy::CancelCreation() { if (route_id_ == MSG_ROUTING_NONE) return; // Tell the browser to not start our queued worker. if (!IsStarted()) child_thread_->Send(new ViewHostMsg_CancelCreateDedicatedWorker(route_id_)); - - // Call our superclass to shutdown the routing - WebWorkerBase::Disconnect(); } void WebWorkerProxy::startWorkerContext( @@ -48,6 +50,7 @@ void WebWorkerProxy::startWorkerContext( void WebWorkerProxy::terminateWorkerContext() { if (route_id_ != MSG_ROUTING_NONE) { Send(new WorkerMsg_TerminateWorkerContext(route_id_)); + CancelCreation(); Disconnect(); } } diff --git a/chrome/renderer/webworker_proxy.h b/chrome/renderer/webworker_proxy.h index fb2db3ed..112b561 100644 --- a/chrome/renderer/webworker_proxy.h +++ b/chrome/renderer/webworker_proxy.h @@ -27,6 +27,7 @@ class WebWorkerProxy : public WebKit::WebWorker, private WebWorkerBase { WebWorkerProxy(WebKit::WebWorkerClient* client, ChildThread* child_thread, int render_view_route_id); + ~WebWorkerProxy(); // WebWorker implementation. virtual void startWorkerContext(const WebKit::WebURL& script_url, @@ -43,8 +44,7 @@ class WebWorkerProxy : public WebKit::WebWorker, private WebWorkerBase { void OnMessageReceived(const IPC::Message& message); private: - virtual void Disconnect(); - + void CancelCreation(); void OnWorkerCreated(); void OnWorkerContextDestroyed(); void OnPostMessage(const string16& message, diff --git a/chrome/worker/websharedworker_stub.cc b/chrome/worker/websharedworker_stub.cc index 3c7aa3e..7c9646e 100644 --- a/chrome/worker/websharedworker_stub.cc +++ b/chrome/worker/websharedworker_stub.cc @@ -13,7 +13,8 @@ WebSharedWorkerStub::WebSharedWorkerStub( const string16& name, int route_id) : WebWorkerStubBase(route_id), - name_(name) { + name_(name), + started_(false) { // TODO(atwilson): Add support for NaCl when they support MessagePorts. impl_ = WebKit::WebSharedWorker::create(client()); @@ -35,10 +36,16 @@ void WebSharedWorkerStub::OnMessageReceived(const IPC::Message& message) { void WebSharedWorkerStub::OnStartWorkerContext( const GURL& url, const string16& user_agent, const string16& source_code) { + // Ignore multiple attempts to start this worker (can happen if two pages + // try to start it simultaneously). + if (started_) + return; impl_->startWorkerContext(url, name_, user_agent, source_code); + started_ = true; } void WebSharedWorkerStub::OnConnect(int sent_message_port_id, int routing_id) { + DCHECK(started_); WebKit::WebMessagePortChannel* channel = new WebMessagePortChannelImpl(routing_id, sent_message_port_id); impl_->connect(channel, NULL); @@ -49,4 +56,5 @@ void WebSharedWorkerStub::OnTerminateWorkerContext() { // Call the client to make sure context exits. EnsureWorkerContextTerminates(); + started_ = false; } diff --git a/chrome/worker/websharedworker_stub.h b/chrome/worker/websharedworker_stub.h index f7a26f3..426aaad 100644 --- a/chrome/worker/websharedworker_stub.h +++ b/chrome/worker/websharedworker_stub.h @@ -33,6 +33,7 @@ class WebSharedWorkerStub : public WebWorkerStubBase { WebKit::WebSharedWorker* impl_; string16 name_; + bool started_; DISALLOW_COPY_AND_ASSIGN(WebSharedWorkerStub); }; diff --git a/chrome/worker/webworkerclient_proxy.cc b/chrome/worker/webworkerclient_proxy.cc index 8519c23..6ba589f 100644 --- a/chrome/worker/webworkerclient_proxy.cc +++ b/chrome/worker/webworkerclient_proxy.cc @@ -92,8 +92,7 @@ void WebWorkerClientProxy::reportPendingActivity(bool has_pending_activity) { } void WebWorkerClientProxy::workerContextClosed() { - // TODO(atwilson): Notify WorkerProcessHost that the worker context is closing - // (needed for shared workers so we don't allow new connections). + Send(new WorkerHostMsg_WorkerContextClosed(route_id_)); } void WebWorkerClientProxy::workerContextDestroyed() { diff --git a/chrome/worker/worker_uitest.cc b/chrome/worker/worker_uitest.cc index 793f889..7b46995 100644 --- a/chrome/worker/worker_uitest.cc +++ b/chrome/worker/worker_uitest.cc @@ -116,25 +116,25 @@ TEST_F(WorkerTest, WorkerFastLayoutTests) { RunLayoutTest(kLayoutTestFiles[i], false); } -TEST_F(WorkerTest, SharedWorkerFastLayoutTests) { +TEST_F(WorkerTest, DISABLED_SharedWorkerFastLayoutTests) { static const char* kLayoutTestFiles[] = { "shared-worker-constructor.html", - // Enable remaining SharedWorker tests when functionality is - // complete (http://crbug.com/26899) "shared-worker-context-gc.html", "shared-worker-event-listener.html", - //"shared-worker-exception.html", - //"shared-worker-frame-lifecycle.html", + "shared-worker-exception.html", "shared-worker-gc.html", + // Lifecycle tests rely on layoutTestController.workerThreadCount which is + // not currently implemented. + //"shared-worker-frame-lifecycle.html", //"shared-worker-lifecycle.html", "shared-worker-load-error.html", "shared-worker-location.html", - //"shared-worker-name.html", + "shared-worker-name.html", "shared-worker-navigator.html", "shared-worker-replace-global-constructor.html", "shared-worker-replace-self.html", "shared-worker-script-error.html", - //"shared-worker-shared.html", + "shared-worker-shared.html", "shared-worker-simple.html", }; |