OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_impl.h" | 5 #include "content/browser/worker_host/worker_service_impl.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" |
11 #include "base/sys_info.h" | |
12 #include "base/threading/thread.h" | 11 #include "base/threading/thread.h" |
13 #include "content/browser/debugger/worker_devtools_manager.h" | 12 #include "content/browser/debugger/worker_devtools_manager.h" |
14 #include "content/browser/worker_host/worker_message_filter.h" | 13 #include "content/browser/worker_host/worker_message_filter.h" |
15 #include "content/browser/worker_host/worker_process_host.h" | 14 #include "content/browser/worker_host/worker_process_host.h" |
16 #include "content/common/view_messages.h" | 15 #include "content/common/view_messages.h" |
17 #include "content/common/worker_messages.h" | 16 #include "content/common/worker_messages.h" |
18 #include "content/public/browser/child_process_data.h" | 17 #include "content/public/browser/child_process_data.h" |
19 #include "content/public/browser/resource_context.h" | 18 #include "content/public/browser/resource_context.h" |
20 #include "content/public/browser/worker_service_observer.h" | 19 #include "content/public/browser/worker_service_observer.h" |
21 #include "content/public/common/content_switches.h" | 20 #include "content/public/common/content_switches.h" |
22 #include "content/public/common/process_type.h" | 21 #include "content/public/common/process_type.h" |
23 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | |
24 | 22 |
25 namespace content { | 23 namespace content { |
26 | 24 |
27 const int WorkerServiceImpl::kMaxWorkerProcessesWhenSharing = 10; | |
28 const int WorkerServiceImpl::kMaxWorkersWhenSeparate = 64; | 25 const int WorkerServiceImpl::kMaxWorkersWhenSeparate = 64; |
29 const int WorkerServiceImpl::kMaxWorkersPerTabWhenSeparate = 16; | 26 const int WorkerServiceImpl::kMaxWorkersPerTabWhenSeparate = 16; |
30 | 27 |
31 WorkerService* WorkerService::GetInstance() { | 28 WorkerService* WorkerService::GetInstance() { |
32 return WorkerServiceImpl::GetInstance(); | 29 return WorkerServiceImpl::GetInstance(); |
33 } | 30 } |
34 | 31 |
35 WorkerServiceImpl* WorkerServiceImpl::GetInstance() { | 32 WorkerServiceImpl* WorkerServiceImpl::GetInstance() { |
36 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 33 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
37 return Singleton<WorkerServiceImpl>::get(); | 34 return Singleton<WorkerServiceImpl>::get(); |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 if (iter->worker_document_set()->IsEmpty()) { | 203 if (iter->worker_document_set()->IsEmpty()) { |
207 iter = pending_shared_workers_.erase(iter); | 204 iter = pending_shared_workers_.erase(iter); |
208 } else { | 205 } else { |
209 ++iter; | 206 ++iter; |
210 } | 207 } |
211 } | 208 } |
212 } | 209 } |
213 | 210 |
214 bool WorkerServiceImpl::CreateWorkerFromInstance( | 211 bool WorkerServiceImpl::CreateWorkerFromInstance( |
215 WorkerProcessHost::WorkerInstance instance) { | 212 WorkerProcessHost::WorkerInstance instance) { |
216 // TODO(michaeln): We need to ensure that a process is working | 213 if (!CanCreateWorkerProcess(instance)) { |
217 // on behalf of a single browser context. The process sharing logic below | 214 queued_workers_.push_back(instance); |
218 // does not ensure that. Consider making WorkerService a per browser context | 215 return true; |
219 // object to help with this. | |
220 WorkerProcessHost* worker = NULL; | |
221 if (CommandLine::ForCurrentProcess()->HasSwitch( | |
222 switches::kWebWorkerProcessPerCore)) { | |
223 worker = GetProcessToFillUpCores(); | |
224 } else if (CommandLine::ForCurrentProcess()->HasSwitch( | |
225 switches::kWebWorkerShareProcesses)) { | |
226 worker = GetProcessForDomain(instance.url()); | |
227 } else { // One process per worker. | |
228 if (!CanCreateWorkerProcess(instance)) { | |
229 queued_workers_.push_back(instance); | |
230 return true; | |
231 } | |
232 } | 216 } |
233 | 217 |
234 // Check to see if this shared worker is already running (two pages may have | 218 // Check to see if this shared worker is already running (two pages may have |
235 // tried to start up the worker simultaneously). | 219 // tried to start up the worker simultaneously). |
236 // See if a worker with this name already exists. | 220 // See if a worker with this name already exists. |
237 WorkerProcessHost::WorkerInstance* existing_instance = | 221 WorkerProcessHost::WorkerInstance* existing_instance = |
238 FindSharedWorkerInstance( | 222 FindSharedWorkerInstance( |
239 instance.url(), instance.name(), instance.partition(), | 223 instance.url(), instance.name(), instance.partition(), |
240 instance.resource_context()); | 224 instance.resource_context()); |
241 WorkerProcessHost::WorkerInstance::FilterInfo filter_info = | 225 WorkerProcessHost::WorkerInstance::FilterInfo filter_info = |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 DCHECK(iter->NumFilters() == 1); | 272 DCHECK(iter->NumFilters() == 1); |
289 WorkerProcessHost::WorkerInstance::FilterInfo filter_info = | 273 WorkerProcessHost::WorkerInstance::FilterInfo filter_info = |
290 iter->GetFilter(); | 274 iter->GetFilter(); |
291 instance.AddFilter(filter_info.first, filter_info.second); | 275 instance.AddFilter(filter_info.first, filter_info.second); |
292 iter = queued_workers_.erase(iter); | 276 iter = queued_workers_.erase(iter); |
293 } else { | 277 } else { |
294 ++iter; | 278 ++iter; |
295 } | 279 } |
296 } | 280 } |
297 | 281 |
298 if (!worker) { | 282 WorkerMessageFilter* first_filter = instance.filters().begin()->first; |
299 WorkerMessageFilter* first_filter = instance.filters().begin()->first; | 283 WorkerProcessHost* worker = new WorkerProcessHost( |
300 worker = new WorkerProcessHost(instance.resource_context(), | 284 instance.resource_context(), instance.partition()); |
301 instance.partition()); | 285 // TODO(atwilson): This won't work if the message is from a worker process. |
302 // TODO(atwilson): This won't work if the message is from a worker process. | 286 // We don't support that yet though (this message is only sent from |
303 // We don't support that yet though (this message is only sent from | 287 // renderers) but when we do, we'll need to add code to pass in the current |
304 // renderers) but when we do, we'll need to add code to pass in the current | 288 // worker's document set for nested workers. |
305 // worker's document set for nested workers. | 289 if (!worker->Init(first_filter->render_process_id())) { |
306 if (!worker->Init(first_filter->render_process_id())) { | 290 delete worker; |
307 delete worker; | 291 return false; |
308 return false; | |
309 } | |
310 } | 292 } |
311 | 293 |
312 // TODO(michaeln): As written, test can fail per my earlier comment in | |
313 // this method, but that's a bug. | |
314 // DCHECK(worker->request_context() == instance.GetRequestContext()); | |
315 | |
316 worker->CreateWorker(instance); | 294 worker->CreateWorker(instance); |
317 FOR_EACH_OBSERVER( | 295 FOR_EACH_OBSERVER( |
318 WorkerServiceObserver, observers_, | 296 WorkerServiceObserver, observers_, |
319 WorkerCreated(instance.url(), instance.name(), worker->GetData().id, | 297 WorkerCreated(instance.url(), instance.name(), worker->GetData().id, |
320 instance.worker_route_id())); | 298 instance.worker_route_id())); |
321 WorkerDevToolsManager::GetInstance()->WorkerCreated(worker, instance); | 299 WorkerDevToolsManager::GetInstance()->WorkerCreated(worker, instance); |
322 return true; | 300 return true; |
323 } | 301 } |
324 | 302 |
325 WorkerProcessHost* WorkerServiceImpl::GetProcessForDomain(const GURL& url) { | |
326 int num_processes = 0; | |
327 std::string domain = | |
328 net::RegistryControlledDomainService::GetDomainAndRegistry(url); | |
329 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) { | |
330 num_processes++; | |
331 for (WorkerProcessHost::Instances::const_iterator instance = | |
332 iter->instances().begin(); | |
333 instance != iter->instances().end(); ++instance) { | |
334 if (net::RegistryControlledDomainService::GetDomainAndRegistry( | |
335 instance->url()) == domain) { | |
336 return *iter; | |
337 } | |
338 } | |
339 } | |
340 | |
341 if (num_processes >= kMaxWorkerProcessesWhenSharing) | |
342 return GetLeastLoadedWorker(); | |
343 | |
344 return NULL; | |
345 } | |
346 | |
347 WorkerProcessHost* WorkerServiceImpl::GetProcessToFillUpCores() { | |
348 int num_processes = 0; | |
349 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) | |
350 num_processes++; | |
351 | |
352 if (num_processes >= base::SysInfo::NumberOfProcessors()) | |
353 return GetLeastLoadedWorker(); | |
354 | |
355 return NULL; | |
356 } | |
357 | |
358 WorkerProcessHost* WorkerServiceImpl::GetLeastLoadedWorker() { | |
359 WorkerProcessHost* smallest = NULL; | |
360 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) { | |
361 if (!smallest || iter->instances().size() < smallest->instances().size()) | |
362 smallest = *iter; | |
363 } | |
364 | |
365 return smallest; | |
366 } | |
367 | |
368 bool WorkerServiceImpl::CanCreateWorkerProcess( | 303 bool WorkerServiceImpl::CanCreateWorkerProcess( |
369 const WorkerProcessHost::WorkerInstance& instance) { | 304 const WorkerProcessHost::WorkerInstance& instance) { |
370 // Worker can be fired off if *any* parent has room. | 305 // Worker can be fired off if *any* parent has room. |
371 const WorkerDocumentSet::DocumentInfoSet& parents = | 306 const WorkerDocumentSet::DocumentInfoSet& parents = |
372 instance.worker_document_set()->documents(); | 307 instance.worker_document_set()->documents(); |
373 | 308 |
374 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter = | 309 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter = |
375 parents.begin(); | 310 parents.begin(); |
376 parent_iter != parents.end(); ++parent_iter) { | 311 parent_iter != parents.end(); ++parent_iter) { |
377 bool hit_total_worker_limit = false; | 312 bool hit_total_worker_limit = false; |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
585 return instance; | 520 return instance; |
586 | 521 |
587 // No existing pending worker - create a new one. | 522 // No existing pending worker - create a new one. |
588 WorkerProcessHost::WorkerInstance pending( | 523 WorkerProcessHost::WorkerInstance pending( |
589 url, true, name, resource_context, partition); | 524 url, true, name, resource_context, partition); |
590 pending_shared_workers_.push_back(pending); | 525 pending_shared_workers_.push_back(pending); |
591 return &pending_shared_workers_.back(); | 526 return &pending_shared_workers_.back(); |
592 } | 527 } |
593 | 528 |
594 } // namespace content | 529 } // namespace content |
OLD | NEW |