Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/worker_host/worker_service.h" | 5 #include "content/browser/worker_host/worker_service.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 77 const ViewHostMsg_CreateWorker_Params& params, | 77 const ViewHostMsg_CreateWorker_Params& params, |
| 78 int route_id, | 78 int route_id, |
| 79 WorkerMessageFilter* filter, | 79 WorkerMessageFilter* filter, |
| 80 const content::ResourceContext& resource_context) { | 80 const content::ResourceContext& resource_context) { |
| 81 // Generate a unique route id for the browser-worker communication that's | 81 // Generate a unique route id for the browser-worker communication that's |
| 82 // unique among all worker processes. That way when the worker process sends | 82 // unique among all worker processes. That way when the worker process sends |
| 83 // a wrapped IPC message through us, we know which WorkerProcessHost to give | 83 // a wrapped IPC message through us, we know which WorkerProcessHost to give |
| 84 // it to. | 84 // it to. |
| 85 WorkerProcessHost::WorkerInstance instance( | 85 WorkerProcessHost::WorkerInstance instance( |
| 86 params.url, | 86 params.url, |
| 87 params.is_shared, | |
| 88 params.name, | 87 params.name, |
| 89 next_worker_route_id(), | 88 next_worker_route_id(), |
| 90 params.is_shared ? 0 : filter->render_process_id(), | 89 0, |
| 91 params.is_shared ? 0 : params.parent_appcache_host_id, | 90 params.script_resource_appcache_id, |
| 92 params.is_shared ? params.script_resource_appcache_id : 0, | |
| 93 &resource_context); | 91 &resource_context); |
| 94 instance.AddFilter(filter, route_id); | 92 instance.AddFilter(filter, route_id); |
| 95 instance.worker_document_set()->Add( | 93 instance.worker_document_set()->Add( |
| 96 filter, params.document_id, filter->render_process_id(), | 94 filter, params.document_id, filter->render_process_id(), |
| 97 params.render_view_route_id); | 95 params.render_view_route_id); |
| 98 | 96 |
| 99 CreateWorkerFromInstance(instance); | 97 CreateWorkerFromInstance(instance); |
| 100 } | 98 } |
| 101 | 99 |
| 102 void WorkerService::LookupSharedWorker( | 100 void WorkerService::LookupSharedWorker( |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 134 // TODO(atwilson): This won't work if the message is from a worker process. | 132 // TODO(atwilson): This won't work if the message is from a worker process. |
| 135 // We don't support that yet though (this message is only sent from | 133 // We don't support that yet though (this message is only sent from |
| 136 // renderers) but when we do, we'll need to add code to pass in the current | 134 // renderers) but when we do, we'll need to add code to pass in the current |
| 137 // worker's document set for nested workers. | 135 // worker's document set for nested workers. |
| 138 instance->worker_document_set()->Add( | 136 instance->worker_document_set()->Add( |
| 139 filter, params.document_id, filter->render_process_id(), | 137 filter, params.document_id, filter->render_process_id(), |
| 140 params.render_view_route_id); | 138 params.render_view_route_id); |
| 141 } | 139 } |
| 142 } | 140 } |
| 143 | 141 |
| 144 void WorkerService::CancelCreateDedicatedWorker( | 142 void WorkerService::CancelCreateDedicatedWorker( |
|
jam
2011/10/26 22:25:38
i guess this is second round?
| |
| 145 int route_id, | 143 int route_id, |
| 146 WorkerMessageFilter* filter) { | 144 WorkerMessageFilter* filter) { |
| 147 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); | |
| 148 i != queued_workers_.end(); ++i) { | |
| 149 if (i->HasFilter(filter, route_id)) { | |
| 150 DCHECK(!i->shared()); | |
| 151 queued_workers_.erase(i); | |
| 152 return; | |
| 153 } | |
| 154 } | |
| 155 | 145 |
| 156 // There could be a race condition where the WebWorkerProxy told us to cancel | 146 NOTREACHED(); |
| 157 // the worker right as we sent it a message say it's been created. Look at | |
| 158 // the running workers. | |
| 159 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | |
| 160 !iter.Done(); ++iter) { | |
| 161 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | |
| 162 for (WorkerProcessHost::Instances::const_iterator instance = | |
| 163 worker->instances().begin(); | |
| 164 instance != worker->instances().end(); ++instance) { | |
| 165 if (instance->HasFilter(filter, route_id)) { | |
| 166 // Fake a worker destroyed message so that WorkerProcessHost cleans up | |
| 167 // properly. | |
| 168 WorkerMsg_TerminateWorkerContext message(route_id); | |
| 169 ForwardToWorker(message, filter); | |
| 170 return; | |
| 171 } | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 DCHECK(false) << "Couldn't find worker to cancel"; | |
| 176 } | 147 } |
| 177 | 148 |
| 178 void WorkerService::ForwardToWorker(const IPC::Message& message, | 149 void WorkerService::ForwardToWorker(const IPC::Message& message, |
| 179 WorkerMessageFilter* filter) { | 150 WorkerMessageFilter* filter) { |
| 180 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 151 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 181 !iter.Done(); ++iter) { | 152 !iter.Done(); ++iter) { |
| 182 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 153 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 183 if (worker->FilterMessage(message, filter)) | 154 if (worker->FilterMessage(message, filter)) |
| 184 return; | 155 return; |
| 185 } | 156 } |
| 186 | 157 |
| 187 // TODO(jabdelmalek): tell filter that callee is gone | 158 // TODO(jabdelmalek): tell filter that callee is gone |
| 188 } | 159 } |
| 189 | 160 |
| 190 void WorkerService::DocumentDetached(unsigned long long document_id, | 161 void WorkerService::DocumentDetached(unsigned long long document_id, |
| 191 WorkerMessageFilter* filter) { | 162 WorkerMessageFilter* filter) { |
| 192 // Any associated shared workers can be shut down. | 163 // Any associated shared workers can be shut down. |
| 193 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 164 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 194 !iter.Done(); ++iter) { | 165 !iter.Done(); ++iter) { |
| 195 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 166 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 196 worker->DocumentDetached(filter, document_id); | 167 worker->DocumentDetached(filter, document_id); |
| 197 } | 168 } |
| 198 | 169 |
| 199 // Remove any queued shared workers for this document. | 170 // Remove any queued shared workers for this document. |
| 200 for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin(); | 171 for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin(); |
| 201 iter != queued_workers_.end();) { | 172 iter != queued_workers_.end();) { |
| 202 if (iter->shared()) { | 173 |
| 203 iter->worker_document_set()->Remove(filter, document_id); | 174 iter->worker_document_set()->Remove(filter, document_id); |
| 204 if (iter->worker_document_set()->IsEmpty()) { | 175 if (iter->worker_document_set()->IsEmpty()) { |
| 205 iter = queued_workers_.erase(iter); | 176 iter = queued_workers_.erase(iter); |
| 206 continue; | 177 continue; |
| 207 } | |
| 208 } | 178 } |
| 209 ++iter; | 179 ++iter; |
| 210 } | 180 } |
| 211 | 181 |
| 212 // Remove the document from any pending shared workers. | 182 // Remove the document from any pending shared workers. |
| 213 for (WorkerProcessHost::Instances::iterator iter = | 183 for (WorkerProcessHost::Instances::iterator iter = |
| 214 pending_shared_workers_.begin(); | 184 pending_shared_workers_.begin(); |
| 215 iter != pending_shared_workers_.end(); ) { | 185 iter != pending_shared_workers_.end(); ) { |
| 216 iter->worker_document_set()->Remove(filter, document_id); | 186 iter->worker_document_set()->Remove(filter, document_id); |
| 217 if (iter->worker_document_set()->IsEmpty()) { | 187 if (iter->worker_document_set()->IsEmpty()) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 237 worker = GetProcessForDomain(instance.url()); | 207 worker = GetProcessForDomain(instance.url()); |
| 238 } else { // One process per worker. | 208 } else { // One process per worker. |
| 239 if (!CanCreateWorkerProcess(instance)) { | 209 if (!CanCreateWorkerProcess(instance)) { |
| 240 queued_workers_.push_back(instance); | 210 queued_workers_.push_back(instance); |
| 241 return true; | 211 return true; |
| 242 } | 212 } |
| 243 } | 213 } |
| 244 | 214 |
| 245 // Check to see if this shared worker is already running (two pages may have | 215 // Check to see if this shared worker is already running (two pages may have |
| 246 // tried to start up the worker simultaneously). | 216 // tried to start up the worker simultaneously). |
| 247 if (instance.shared()) { | 217 // See if a worker with this name already exists. |
| 248 // See if a worker with this name already exists. | 218 WorkerProcessHost::WorkerInstance* existing_instance = |
| 249 WorkerProcessHost::WorkerInstance* existing_instance = | 219 FindSharedWorkerInstance( |
| 250 FindSharedWorkerInstance( | 220 instance.url(), instance.name(), instance.resource_context()); |
| 251 instance.url(), instance.name(), instance.resource_context()); | 221 WorkerProcessHost::WorkerInstance::FilterInfo filter_info = |
| 252 WorkerProcessHost::WorkerInstance::FilterInfo filter_info = | 222 instance.GetFilter(); |
| 253 instance.GetFilter(); | 223 // If this worker is already running, no need to create a new copy. Just |
| 254 // If this worker is already running, no need to create a new copy. Just | 224 // inform the caller that the worker has been created. |
| 255 // inform the caller that the worker has been created. | 225 if (existing_instance) { |
| 256 if (existing_instance) { | 226 // Walk the worker's filter list to see if this client is listed. If not, |
| 257 // Walk the worker's filter list to see if this client is listed. If not, | 227 // then it means that the worker started by the client already exited so |
| 258 // then it means that the worker started by the client already exited so | 228 // we should not attach to this new one (http://crbug.com/29243). |
| 259 // we should not attach to this new one (http://crbug.com/29243). | 229 if (!existing_instance->HasFilter(filter_info.first, filter_info.second)) |
| 260 if (!existing_instance->HasFilter(filter_info.first, filter_info.second)) | 230 return false; |
| 261 return false; | 231 filter_info.first->Send(new ViewMsg_WorkerCreated(filter_info.second)); |
| 262 filter_info.first->Send(new ViewMsg_WorkerCreated(filter_info.second)); | 232 return true; |
| 263 return true; | 233 } |
| 264 } | |
| 265 | 234 |
| 266 // Look to see if there's a pending instance. | 235 // Look to see if there's a pending instance. |
| 267 WorkerProcessHost::WorkerInstance* pending = FindPendingInstance( | 236 WorkerProcessHost::WorkerInstance* pending = FindPendingInstance( |
| 268 instance.url(), instance.name(), instance.resource_context()); | 237 instance.url(), instance.name(), instance.resource_context()); |
| 269 // If there's no instance *and* no pending instance (or there is a pending | 238 // If there's no instance *and* no pending instance (or there is a pending |
| 270 // instance but it does not contain our filter info), then it means the | 239 // instance but it does not contain our filter info), then it means the |
| 271 // worker started up and exited already. Log a warning because this should | 240 // worker started up and exited already. Log a warning because this should |
| 272 // be a very rare occurrence and is probably a bug, but it *can* happen so | 241 // be a very rare occurrence and is probably a bug, but it *can* happen so |
| 273 // handle it gracefully. | 242 // handle it gracefully. |
| 274 if (!pending || | 243 if (!pending || |
| 275 !pending->HasFilter(filter_info.first, filter_info.second)) { | 244 !pending->HasFilter(filter_info.first, filter_info.second)) { |
| 276 DLOG(WARNING) << "Pending worker already exited"; | 245 DLOG(WARNING) << "Pending worker already exited"; |
| 277 return false; | 246 return false; |
| 278 } | 247 } |
| 279 | 248 |
| 280 // Assign the accumulated document set and filter list for this pending | 249 // Assign the accumulated document set and filter list for this pending |
| 281 // worker to the new instance. | 250 // worker to the new instance. |
| 282 DCHECK(!pending->worker_document_set()->IsEmpty()); | 251 DCHECK(!pending->worker_document_set()->IsEmpty()); |
| 283 instance.ShareDocumentSet(*pending); | 252 instance.ShareDocumentSet(*pending); |
| 284 for (WorkerProcessHost::WorkerInstance::FilterList::const_iterator i = | 253 for (WorkerProcessHost::WorkerInstance::FilterList::const_iterator i = |
| 285 pending->filters().begin(); | 254 pending->filters().begin(); |
| 286 i != pending->filters().end(); ++i) { | 255 i != pending->filters().end(); ++i) { |
| 287 instance.AddFilter(i->first, i->second); | 256 instance.AddFilter(i->first, i->second); |
| 288 } | 257 } |
| 289 RemovePendingInstances( | 258 RemovePendingInstances( |
| 290 instance.url(), instance.name(), instance.resource_context()); | 259 instance.url(), instance.name(), instance.resource_context()); |
| 291 | 260 |
| 292 // Remove any queued instances of this worker and copy over the filter to | 261 // Remove any queued instances of this worker and copy over the filter to |
| 293 // this instance. | 262 // this instance. |
| 294 for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin(); | 263 for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin(); |
| 295 iter != queued_workers_.end();) { | 264 iter != queued_workers_.end();) { |
| 296 if (iter->Matches(instance.url(), instance.name(), | 265 if (iter->Matches(instance.url(), instance.name(), |
| 297 instance.resource_context())) { | 266 instance.resource_context())) { |
| 298 DCHECK(iter->NumFilters() == 1); | 267 DCHECK(iter->NumFilters() == 1); |
| 299 WorkerProcessHost::WorkerInstance::FilterInfo filter_info = | 268 WorkerProcessHost::WorkerInstance::FilterInfo filter_info = |
| 300 iter->GetFilter(); | 269 iter->GetFilter(); |
| 301 instance.AddFilter(filter_info.first, filter_info.second); | 270 instance.AddFilter(filter_info.first, filter_info.second); |
| 302 iter = queued_workers_.erase(iter); | 271 iter = queued_workers_.erase(iter); |
| 303 } else { | 272 } else { |
| 304 ++iter; | 273 ++iter; |
| 305 } | |
| 306 } | 274 } |
| 307 } | 275 } |
| 308 | 276 |
| 309 if (!worker) { | 277 if (!worker) { |
| 310 WorkerMessageFilter* first_filter = instance.filters().begin()->first; | 278 WorkerMessageFilter* first_filter = instance.filters().begin()->first; |
| 311 worker = new WorkerProcessHost( | 279 worker = new WorkerProcessHost( |
| 312 instance.resource_context(), | 280 instance.resource_context(), |
| 313 first_filter->resource_dispatcher_host()); | 281 first_filter->resource_dispatcher_host()); |
| 314 // TODO(atwilson): This won't work if the message is from a worker process. | 282 // TODO(atwilson): This won't work if the message is from a worker process. |
| 315 // We don't support that yet though (this message is only sent from | 283 // We don't support that yet though (this message is only sent from |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 579 WorkerProcessHost::WorkerInstance* instance = | 547 WorkerProcessHost::WorkerInstance* instance = |
| 580 FindPendingInstance(url, name, resource_context); | 548 FindPendingInstance(url, name, resource_context); |
| 581 if (instance) | 549 if (instance) |
| 582 return instance; | 550 return instance; |
| 583 | 551 |
| 584 // No existing pending worker - create a new one. | 552 // No existing pending worker - create a new one. |
| 585 WorkerProcessHost::WorkerInstance pending(url, true, name, resource_context); | 553 WorkerProcessHost::WorkerInstance pending(url, true, name, resource_context); |
| 586 pending_shared_workers_.push_back(pending); | 554 pending_shared_workers_.push_back(pending); |
| 587 return &pending_shared_workers_.back(); | 555 return &pending_shared_workers_.back(); |
| 588 } | 556 } |
| OLD | NEW |