OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "chrome/browser/worker_host/worker_service.h" | 5 #include "chrome/browser/worker_host/worker_service.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/singleton.h" | 8 #include "base/singleton.h" |
9 #include "base/sys_info.h" | 9 #include "base/sys_info.h" |
10 #include "base/thread.h" | 10 #include "base/thread.h" |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 // it to. | 60 // it to. |
61 WorkerProcessHost::WorkerInstance instance(url, | 61 WorkerProcessHost::WorkerInstance instance(url, |
62 is_shared, | 62 is_shared, |
63 off_the_record, | 63 off_the_record, |
64 name, | 64 name, |
65 next_worker_route_id()); | 65 next_worker_route_id()); |
66 instance.AddSender(sender, sender_route_id); | 66 instance.AddSender(sender, sender_route_id); |
67 instance.worker_document_set()->Add( | 67 instance.worker_document_set()->Add( |
68 sender, document_id, renderer_id, render_view_route_id); | 68 sender, document_id, renderer_id, render_view_route_id); |
69 | 69 |
| 70 return CreateWorkerFromInstance(instance); |
| 71 } |
| 72 |
| 73 bool WorkerService::CreateWorkerFromInstance( |
| 74 WorkerProcessHost::WorkerInstance instance) { |
| 75 |
70 WorkerProcessHost* worker = NULL; | 76 WorkerProcessHost* worker = NULL; |
71 if (CommandLine::ForCurrentProcess()->HasSwitch( | 77 if (CommandLine::ForCurrentProcess()->HasSwitch( |
72 switches::kWebWorkerProcessPerCore)) { | 78 switches::kWebWorkerProcessPerCore)) { |
73 worker = GetProcessToFillUpCores(); | 79 worker = GetProcessToFillUpCores(); |
74 } else if (CommandLine::ForCurrentProcess()->HasSwitch( | 80 } else if (CommandLine::ForCurrentProcess()->HasSwitch( |
75 switches::kWebWorkerShareProcesses)) { | 81 switches::kWebWorkerShareProcesses)) { |
76 worker = GetProcessForDomain(url); | 82 worker = GetProcessForDomain(instance.url()); |
77 } else { // One process per worker. | 83 } else { // One process per worker. |
78 if (!CanCreateWorkerProcess(instance)) { | 84 if (!CanCreateWorkerProcess(instance)) { |
79 queued_workers_.push_back(instance); | 85 queued_workers_.push_back(instance); |
80 return true; | 86 return true; |
81 } | 87 } |
82 } | 88 } |
83 | 89 |
84 // Check to see if this shared worker is already running (two pages may have | 90 // Check to see if this shared worker is already running (two pages may have |
85 // tried to start up the worker simultaneously). | 91 // tried to start up the worker simultaneously). |
86 if (is_shared) { | 92 if (instance.shared()) { |
87 // See if a worker with this name already exists. | 93 // See if a worker with this name already exists. |
88 WorkerProcessHost::WorkerInstance* existing_instance = | 94 WorkerProcessHost::WorkerInstance* existing_instance = |
89 FindSharedWorkerInstance(url, name, off_the_record); | 95 FindSharedWorkerInstance( |
| 96 instance.url(), instance.name(), instance.off_the_record()); |
90 // If this worker is already running, no need to create a new copy. Just | 97 // If this worker is already running, no need to create a new copy. Just |
91 // inform the caller that the worker has been created. | 98 // inform the caller that the worker has been created. |
92 if (existing_instance) { | 99 if (existing_instance) { |
93 // TODO(atwilson): Change this to scan the sender list (crbug.com/29243). | 100 // TODO(atwilson): Change this to scan the sender list (crbug.com/29243). |
94 existing_instance->AddSender(sender, sender_route_id); | 101 WorkerProcessHost::WorkerInstance::SenderInfo sender_info = |
95 sender->Send(new ViewMsg_WorkerCreated(sender_route_id)); | 102 instance.GetSender(); |
| 103 existing_instance->AddSender(sender_info.first, sender_info.second); |
| 104 sender_info.first->Send(new ViewMsg_WorkerCreated(sender_info.second)); |
96 return true; | 105 return true; |
97 } | 106 } |
98 | 107 |
99 // Look to see if there's a pending instance. | 108 // Look to see if there's a pending instance. |
100 WorkerProcessHost::WorkerInstance* pending = FindPendingInstance( | 109 WorkerProcessHost::WorkerInstance* pending = FindPendingInstance( |
101 url, name, off_the_record); | 110 instance.url(), instance.name(), instance.off_the_record()); |
102 // If there's no instance *and* no pending instance, then it means the | 111 // If there's no instance *and* no pending instance, then it means the |
103 // worker started up and exited already. Log a warning because this should | 112 // worker started up and exited already. Log a warning because this should |
104 // be a very rare occurrence and is probably a bug, but it *can* happen so | 113 // be a very rare occurrence and is probably a bug, but it *can* happen so |
105 // handle it gracefully. | 114 // handle it gracefully. |
106 if (!pending) { | 115 if (!pending) { |
107 DLOG(WARNING) << "Pending worker already exited"; | 116 DLOG(WARNING) << "Pending worker already exited"; |
108 return false; | 117 return false; |
109 } | 118 } |
110 | 119 |
111 // Assign the accumulated document set and sender list for this pending | 120 // Assign the accumulated document set and sender list for this pending |
112 // worker to the new instance. | 121 // worker to the new instance. |
113 DCHECK(!pending->worker_document_set()->IsEmpty()); | 122 DCHECK(!pending->worker_document_set()->IsEmpty()); |
114 instance.ShareDocumentSet(*pending); | 123 instance.ShareDocumentSet(*pending); |
115 RemovePendingInstance(url, name, off_the_record); | 124 RemovePendingInstances( |
| 125 instance.url(), instance.name(), instance.off_the_record()); |
| 126 |
| 127 // Remove any queued instances of this worker and copy over the sender to |
| 128 // this instance. |
| 129 for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin(); |
| 130 iter != queued_workers_.end();) { |
| 131 if (iter->Matches(instance.url(), instance.name(), |
| 132 instance.off_the_record())) { |
| 133 DCHECK(iter->NumSenders() == 1); |
| 134 WorkerProcessHost::WorkerInstance::SenderInfo sender_info = |
| 135 iter->GetSender(); |
| 136 instance.AddSender(sender_info.first, sender_info.second); |
| 137 iter = queued_workers_.erase(iter); |
| 138 } else { |
| 139 ++iter; |
| 140 } |
| 141 } |
116 } | 142 } |
117 | 143 |
118 if (!worker) { | 144 if (!worker) { |
119 worker = new WorkerProcessHost(resource_dispatcher_host_); | 145 worker = new WorkerProcessHost(resource_dispatcher_host_); |
120 if (!worker->Init()) { | 146 if (!worker->Init()) { |
121 delete worker; | 147 delete worker; |
122 return false; | 148 return false; |
123 } | 149 } |
124 } | 150 } |
125 | 151 |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 } | 422 } |
397 } | 423 } |
398 | 424 |
399 void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) { | 425 void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) { |
400 if (queued_workers_.empty()) | 426 if (queued_workers_.empty()) |
401 return; | 427 return; |
402 | 428 |
403 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); | 429 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); |
404 i != queued_workers_.end();) { | 430 i != queued_workers_.end();) { |
405 if (CanCreateWorkerProcess(*i)) { | 431 if (CanCreateWorkerProcess(*i)) { |
406 WorkerProcessHost* worker = | 432 WorkerProcessHost::WorkerInstance instance = *i; |
407 new WorkerProcessHost(resource_dispatcher_host_); | 433 queued_workers_.erase(i); |
408 if (!worker->Init()) { | 434 CreateWorkerFromInstance(instance); |
409 delete worker; | |
410 return; | |
411 } | |
412 | 435 |
413 worker->CreateWorker(*i); | 436 // CreateWorkerFromInstance can modify the queued_workers_ list when it |
414 i = queued_workers_.erase(i); | 437 // coalesces queued instances after starting a shared worker, so we |
| 438 // have to rescan the list from the beginning (our iterator is now |
| 439 // invalid). This is not a big deal as having any queued workers will be |
| 440 // rare in practice so the list will be small. |
| 441 i = queued_workers_.begin(); |
415 } else { | 442 } else { |
416 ++i; | 443 ++i; |
417 } | 444 } |
418 } | 445 } |
419 } | 446 } |
420 | 447 |
421 const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance( | 448 const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance( |
422 int worker_process_id) { | 449 int worker_process_id) { |
423 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 450 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
424 !iter.Done(); ++iter) { | 451 !iter.Done(); ++iter) { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 iter != pending_shared_workers_.end(); | 486 iter != pending_shared_workers_.end(); |
460 ++iter) { | 487 ++iter) { |
461 if (iter->Matches(url, name, off_the_record)) { | 488 if (iter->Matches(url, name, off_the_record)) { |
462 return &(*iter); | 489 return &(*iter); |
463 } | 490 } |
464 } | 491 } |
465 return NULL; | 492 return NULL; |
466 } | 493 } |
467 | 494 |
468 | 495 |
469 void WorkerService::RemovePendingInstance(const GURL& url, | 496 void WorkerService::RemovePendingInstances(const GURL& url, |
470 const string16& name, | 497 const string16& name, |
471 bool off_the_record) { | 498 bool off_the_record) { |
472 // Walk the pending instances looking for a matching pending worker. | 499 // Walk the pending instances looking for a matching pending worker. |
473 for (WorkerProcessHost::Instances::iterator iter = | 500 for (WorkerProcessHost::Instances::iterator iter = |
474 pending_shared_workers_.begin(); | 501 pending_shared_workers_.begin(); |
475 iter != pending_shared_workers_.end(); | 502 iter != pending_shared_workers_.end(); ) { |
476 ++iter) { | 503 // Pending workers should have no senders - only actively running worker |
| 504 // instances have senders. |
| 505 DCHECK(iter->NumSenders() == 0); |
477 if (iter->Matches(url, name, off_the_record)) { | 506 if (iter->Matches(url, name, off_the_record)) { |
478 pending_shared_workers_.erase(iter); | 507 iter = pending_shared_workers_.erase(iter); |
479 break; | 508 } else { |
| 509 ++iter; |
480 } | 510 } |
481 } | 511 } |
482 } | 512 } |
483 | 513 |
484 WorkerProcessHost::WorkerInstance* | 514 WorkerProcessHost::WorkerInstance* |
485 WorkerService::CreatePendingInstance(const GURL& url, | 515 WorkerService::CreatePendingInstance(const GURL& url, |
486 const string16& name, | 516 const string16& name, |
487 bool off_the_record) { | 517 bool off_the_record) { |
488 // Look for an existing pending worker. | 518 // Look for an existing pending worker. |
489 WorkerProcessHost::WorkerInstance* instance = | 519 WorkerProcessHost::WorkerInstance* instance = |
490 FindPendingInstance(url, name, off_the_record); | 520 FindPendingInstance(url, name, off_the_record); |
491 if (instance) | 521 if (instance) |
492 return instance; | 522 return instance; |
493 | 523 |
494 // No existing pending worker - create a new one. | 524 // No existing pending worker - create a new one. |
495 WorkerProcessHost::WorkerInstance pending( | 525 WorkerProcessHost::WorkerInstance pending( |
496 url, true, off_the_record, name, MSG_ROUTING_NONE); | 526 url, true, off_the_record, name, MSG_ROUTING_NONE); |
497 pending_shared_workers_.push_back(pending); | 527 pending_shared_workers_.push_back(pending); |
498 return &pending_shared_workers_.back(); | 528 return &pending_shared_workers_.back(); |
499 } | 529 } |
OLD | NEW |