Index: content/browser/worker_host/worker_service_impl.cc |
diff --git a/content/browser/worker_host/worker_service_impl.cc b/content/browser/worker_host/worker_service_impl.cc |
index 5fb8e62bedb9f328f75e452f8455c52ebdd3a8e5..cd618f3ae7a64902b5d668385e17f88e97785bc3 100644 |
--- a/content/browser/worker_host/worker_service_impl.cc |
+++ b/content/browser/worker_host/worker_service_impl.cc |
@@ -393,85 +393,150 @@ void WorkerServiceImpl::DocumentDetached(unsigned long long document_id, |
} |
} |
-bool WorkerServiceImpl::CreateWorkerFromInstance( |
- WorkerProcessHost::WorkerInstance instance) { |
- if (!CanCreateWorkerProcess(instance)) { |
- queued_workers_.push_back(instance); |
- return true; |
- } |
+int WorkerServiceImpl::CreateAndStartEmbeddedWorker( |
+ ResourceContext* resource_context, |
+ const WorkerStoragePartition& partition, |
+ const GURL& url, |
+ const std::string& raw_handler_source, |
+ int64 associated_appcache_id) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
+ // 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. |
+ int worker_route_id = next_worker_route_id(); |
+ WorkerProcessHost::WorkerInstance instance( |
+ url, |
+ string16(), |
+ worker_route_id, |
+ 0, |
+ 0, // associated_appcache_id, |
+ resource_context, |
+ partition); |
+ instance.is_embedded_worker_ = true; |
+ CreateWorkerFromInstance(instance); |
+ SendToEmbeddedWorker( |
+ worker_route_id, |
+ new WorkerMsg_StartEmbeddedWorkerContext( |
+ worker_route_id, url, raw_handler_source)); |
+ return worker_route_id; |
+} |
- // Check to see if this shared worker is already running (two pages may have |
- // tried to start up the worker simultaneously). |
- // See if a worker with this name already exists. |
- WorkerProcessHost::WorkerInstance* existing_instance = |
- FindSharedWorkerInstance( |
- instance.url(), instance.name(), instance.partition(), |
- instance.resource_context()); |
- WorkerProcessHost::WorkerInstance::FilterInfo filter_info = |
- instance.GetFilter(); |
- // 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) { |
- // Walk the worker's filter list to see if this client is listed. If not, |
- // then it means that the worker started by the client already exited so |
- // we should not attach to this new one (http://crbug.com/29243). |
- if (!existing_instance->HasFilter(filter_info.first, filter_info.second)) |
- return false; |
- filter_info.first->Send(new ViewMsg_WorkerCreated(filter_info.second)); |
- return true; |
+namespace { |
+// Helper to get the WPH for a given embedded worker id. |
+WorkerProcessHost* FindEmbeddedWorkerProcessHost(int worker_route_id) { |
+ for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) { |
+ const WorkerProcessHost::Instances& instances = (*iter)->instances(); |
+ for (WorkerProcessHost::Instances::const_iterator i = instances.begin(); |
+ i != instances.end(); ++i) { |
+ if (i->is_embedded_worker_ && i->worker_route_id() == worker_route_id) { |
+ return *iter; |
+ } |
+ } |
} |
+ return NULL; |
+} |
+} // namespace |
- // Look to see if there's a pending instance. |
- WorkerProcessHost::WorkerInstance* pending = FindPendingInstance( |
- instance.url(), instance.name(), instance.partition(), |
- instance.resource_context()); |
- // If there's no instance *and* no pending instance (or there is a pending |
- // instance but it does not contain our filter info), 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 || |
- !pending->HasFilter(filter_info.first, filter_info.second)) { |
- DLOG(WARNING) << "Pending worker already exited"; |
+bool WorkerServiceImpl::SendToEmbeddedWorker( |
+ int worker_route_id, IPC::Message* message) { |
+ WorkerProcessHost* host = FindEmbeddedWorkerProcessHost(worker_route_id); |
+ if (!host) { |
+ delete message; |
return false; |
} |
+ return host->Send(message); |
+} |
- // Assign the accumulated document set and filter list for this pending |
- // worker to the new instance. |
- DCHECK(!pending->worker_document_set()->IsEmpty()); |
- instance.ShareDocumentSet(*pending); |
- for (WorkerProcessHost::WorkerInstance::FilterList::const_iterator i = |
- pending->filters().begin(); |
- i != pending->filters().end(); ++i) { |
- instance.AddFilter(i->first, i->second); |
- } |
- RemovePendingInstances(instance.url(), instance.name(), |
- instance.partition(), instance.resource_context()); |
+void WorkerServiceImpl::TerminateEmbeddedWorker(int worker_route_id) { |
+ WorkerProcessHost* host = FindEmbeddedWorkerProcessHost(worker_route_id); |
+ if (!host) |
+ return; |
+ host->TerminateWorker(worker_route_id); |
+} |
- // Remove any queued instances of this worker and copy over the filter to |
- // this instance. |
- for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin(); |
- iter != queued_workers_.end();) { |
- if (iter->Matches(instance.url(), instance.name(), |
- instance.partition(), instance.resource_context())) { |
- DCHECK(iter->NumFilters() == 1); |
- WorkerProcessHost::WorkerInstance::FilterInfo filter_info = |
- iter->GetFilter(); |
- instance.AddFilter(filter_info.first, filter_info.second); |
- iter = queued_workers_.erase(iter); |
- } else { |
- ++iter; |
+bool WorkerServiceImpl::CreateWorkerFromInstance( |
+ WorkerProcessHost::WorkerInstance instance) { |
+ if (!instance.is_embedded_worker_) { |
+ if (!CanCreateWorkerProcess(instance)) { |
+ queued_workers_.push_back(instance); |
+ return true; |
+ } |
+ |
+ // Check to see if this shared worker is already running (two pages may have |
+ // tried to start up the worker simultaneously). |
+ // See if a worker with this name already exists. |
+ WorkerProcessHost::WorkerInstance* existing_instance = |
+ FindSharedWorkerInstance( |
+ instance.url(), instance.name(), instance.partition(), |
+ instance.resource_context()); |
+ WorkerProcessHost::WorkerInstance::FilterInfo filter_info = |
+ instance.GetFilter(); |
+ // 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) { |
+ // Walk the worker's filter list to see if this client is listed. If not, |
+ // then it means that the worker started by the client already exited so |
+ // we should not attach to this new one (http://crbug.com/29243). |
+ if (!existing_instance->HasFilter(filter_info.first, filter_info.second)) |
+ return false; |
+ filter_info.first->Send(new ViewMsg_WorkerCreated(filter_info.second)); |
+ return true; |
+ } |
+ |
+ // Look to see if there's a pending instance. |
+ WorkerProcessHost::WorkerInstance* pending = FindPendingInstance( |
+ instance.url(), instance.name(), instance.partition(), |
+ instance.resource_context()); |
+ // If there's no instance *and* no pending instance (or there is a pending |
+ // instance but it does not contain our filter info), 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 || |
+ !pending->HasFilter(filter_info.first, filter_info.second)) { |
+ DLOG(WARNING) << "Pending worker already exited"; |
+ return false; |
+ } |
+ |
+ // Assign the accumulated document set and filter list for this pending |
+ // worker to the new instance. |
+ DCHECK(!pending->worker_document_set()->IsEmpty()); |
+ instance.ShareDocumentSet(*pending); |
+ for (WorkerProcessHost::WorkerInstance::FilterList::const_iterator i = |
+ pending->filters().begin(); |
+ i != pending->filters().end(); ++i) { |
+ instance.AddFilter(i->first, i->second); |
+ } |
+ RemovePendingInstances(instance.url(), instance.name(), |
+ instance.partition(), instance.resource_context()); |
+ |
+ // Remove any queued instances of this worker and copy over the filter to |
+ // this instance. |
+ for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin(); |
+ iter != queued_workers_.end();) { |
+ if (iter->Matches(instance.url(), instance.name(), |
+ instance.partition(), instance.resource_context())) { |
+ DCHECK(iter->NumFilters() == 1); |
+ WorkerProcessHost::WorkerInstance::FilterInfo filter_info = |
+ iter->GetFilter(); |
+ instance.AddFilter(filter_info.first, filter_info.second); |
+ iter = queued_workers_.erase(iter); |
+ } else { |
+ ++iter; |
+ } |
} |
+ DCHECK_EQ(instance.filters().begin()->first->render_process_id(), |
+ instance.parent_process_id()); |
} |
- WorkerMessageFilter* first_filter = instance.filters().begin()->first; |
WorkerProcessHost* worker = new WorkerProcessHost( |
instance.resource_context(), instance.partition()); |
// TODO(atwilson): This won't work if the message is from a worker process. |
// We don't support that yet though (this message is only sent from |
// renderers) but when we do, we'll need to add code to pass in the current |
// worker's document set for nested workers. |
- if (!worker->Init(first_filter->render_process_id())) { |
+ if (!worker->Init(instance.parent_process_id())) { |
delete worker; |
return false; |
} |
@@ -568,6 +633,7 @@ bool WorkerServiceImpl::GetRendererForWorker(int worker_process_id, |
continue; |
// This code assumes one worker per process, see function comment in header! |
+ // ^^^ gee, lovely ^^^ |
WorkerProcessHost::Instances::const_iterator first_instance = |
iter->instances().begin(); |
if (first_instance == iter->instances().end()) |