Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: chrome/browser/worker_host/worker_service.cc

Issue 390017: Added lifecycle management and sharing support for SharedWorkers. SharedWorkers (Closed)
Patch Set: Changed WebWorkerBase not not call a virtual function from the destructor Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
11 #include "chrome/browser/browser_process.h" 11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/plugin_service.h" 12 #include "chrome/browser/plugin_service.h"
13 #include "chrome/browser/renderer_host/render_process_host.h" 13 #include "chrome/browser/renderer_host/render_process_host.h"
14 #include "chrome/browser/renderer_host/resource_message_filter.h" 14 #include "chrome/browser/renderer_host/resource_message_filter.h"
15 #include "chrome/browser/worker_host/worker_process_host.h" 15 #include "chrome/browser/worker_host/worker_process_host.h"
16 #include "chrome/common/chrome_switches.h" 16 #include "chrome/common/chrome_switches.h"
17 #include "chrome/common/notification_service.h" 17 #include "chrome/common/notification_service.h"
18 #include "chrome/common/render_messages.h"
18 #include "chrome/common/worker_messages.h" 19 #include "chrome/common/worker_messages.h"
19 #include "net/base/registry_controlled_domain.h" 20 #include "net/base/registry_controlled_domain.h"
20 21
21 const int WorkerService::kMaxWorkerProcessesWhenSharing = 10; 22 const int WorkerService::kMaxWorkerProcessesWhenSharing = 10;
22 const int WorkerService::kMaxWorkersWhenSeparate = 64; 23 const int WorkerService::kMaxWorkersWhenSeparate = 64;
23 const int WorkerService::kMaxWorkersPerTabWhenSeparate = 16; 24 const int WorkerService::kMaxWorkersPerTabWhenSeparate = 16;
24 25
25 WorkerService* WorkerService::GetInstance() { 26 WorkerService* WorkerService::GetInstance() {
26 return Singleton<WorkerService>::get(); 27 return Singleton<WorkerService>::get();
27 } 28 }
(...skipping 15 matching lines...) Expand all
43 44
44 WorkerService::~WorkerService() { 45 WorkerService::~WorkerService() {
45 } 46 }
46 47
47 bool WorkerService::CreateWorker(const GURL &url, 48 bool WorkerService::CreateWorker(const GURL &url,
48 bool is_shared, 49 bool is_shared,
49 const string16& name, 50 const string16& name,
50 int renderer_id, 51 int renderer_id,
51 int render_view_route_id, 52 int render_view_route_id,
52 IPC::Message::Sender* sender, 53 IPC::Message::Sender* sender,
53 int sender_id,
54 int sender_route_id) { 54 int sender_route_id) {
55 // Generate a unique route id for the browser-worker communication that's 55 // Generate a unique route id for the browser-worker communication that's
56 // unique among all worker processes. That way when the worker process sends 56 // unique among all worker processes. That way when the worker process sends
57 // a wrapped IPC message through us, we know which WorkerProcessHost to give 57 // a wrapped IPC message through us, we know which WorkerProcessHost to give
58 // it to. 58 // it to.
59 WorkerProcessHost::WorkerInstance instance; 59 WorkerProcessHost::WorkerInstance instance;
60 instance.url = url; 60 instance.url = url;
61 instance.name = name; 61 instance.name = name;
62 instance.renderer_id = renderer_id; 62 instance.renderer_id = renderer_id;
63 instance.render_view_route_id = render_view_route_id; 63 instance.render_view_route_id = render_view_route_id;
64 instance.worker_route_id = next_worker_route_id(); 64 instance.worker_route_id = next_worker_route_id();
65 instance.sender = sender;
66 instance.sender_id = sender_id;
67 instance.sender_route_id = sender_route_id;
68 instance.is_shared = is_shared; 65 instance.is_shared = is_shared;
69 66
67 instance.AddSender(sender, sender_route_id);
68
70 WorkerProcessHost* worker = NULL; 69 WorkerProcessHost* worker = NULL;
71 if (CommandLine::ForCurrentProcess()->HasSwitch( 70 if (CommandLine::ForCurrentProcess()->HasSwitch(
72 switches::kWebWorkerProcessPerCore)) { 71 switches::kWebWorkerProcessPerCore)) {
73 worker = GetProcessToFillUpCores(); 72 worker = GetProcessToFillUpCores();
74 } else if (CommandLine::ForCurrentProcess()->HasSwitch( 73 } else if (CommandLine::ForCurrentProcess()->HasSwitch(
75 switches::kWebWorkerShareProcesses)) { 74 switches::kWebWorkerShareProcesses)) {
76 worker = GetProcessForDomain(url); 75 worker = GetProcessForDomain(url);
77 } else { // One process per worker. 76 } else { // One process per worker.
78 if (!CanCreateWorkerProcess(instance)) { 77 if (!CanCreateWorkerProcess(instance)) {
79 queued_workers_.push_back(instance); 78 queued_workers_.push_back(instance);
80 return true; 79 return true;
81 } 80 }
82 } 81 }
83 82
83 // Check to see if this shared worker is already running (two pages may have
84 // tried to start up the worker simultaneously)
jam 2009/11/12 20:11:23 nit: period
85 if (is_shared) {
86 // See if a worker with this name already exists.
87 WorkerProcessHost::WorkerInstance* existing_instance =
88 FindSharedWorkerInstance(url, name);
89 // If this worker is already running, no need to create a new copy. Just
90 // inform the caller that the worker has been created.
91 if (existing_instance) {
92 existing_instance->AddSender(sender, sender_route_id);
93 sender->Send(new ViewMsg_WorkerCreated(sender_route_id));
94 return true;
95 }
96
97 // Look to see if there's a pending instance.
98 WorkerProcessHost::WorkerInstance* pending = FindPendingInstance(url, name);
99 // If there's no instance *and* no pending instance, then it means the
100 // worker started up and exited already. Log a warning because this should
101 // be a very rare occurrence and is probably a bug, but it *can* happen so
102 // handle it gracefully.
103 if (!pending) {
104 DLOG(WARNING) << "Pending worker already exited";
105 return false;
106 }
107
108 // Assign the accumulated document set and sender list for this pending
109 // worker to the new instance.
110 DCHECK(!pending->document_set.empty());
111 instance.document_set = pending->document_set;
112 RemovePendingInstance(url, name);
113 }
114
84 if (!worker) { 115 if (!worker) {
85 worker = new WorkerProcessHost(resource_dispatcher_host_); 116 worker = new WorkerProcessHost(resource_dispatcher_host_);
86 if (!worker->Init()) { 117 if (!worker->Init()) {
87 delete worker; 118 delete worker;
88 return false; 119 return false;
89 } 120 }
90 } 121 }
91 122
92 worker->CreateWorker(instance); 123 worker->CreateWorker(instance);
93 return true; 124 return true;
94 } 125 }
95 126
96 void WorkerService::CancelCreateDedicatedWorker(int sender_id, 127 bool WorkerService::LookupSharedWorker(const GURL &url,
128 const string16& name,
129 unsigned long long document_id,
130 IPC::Message::Sender* sender,
131 int sender_route_id,
132 bool* url_mismatch) {
133 bool found_instance = true;
134 WorkerProcessHost::WorkerInstance* instance =
135 FindSharedWorkerInstance(url, name);
136
137 if (!instance) {
138 // If no worker instance currently exists, we need to create a pending
139 // instance - this is to make sure that any subsequent lookups passing a
140 // mismatched URL get the appropriate url_mismatch error at lookup time.
141 // Having named shared workers was a Really Bad Idea due to details like
142 // this.
143 instance = CreatePendingInstance(url, name);
144 found_instance = false;
145 }
146
147 // Make sure the passed-in instance matches the URL - if not, return an
148 // error.
149 if (url != instance->url) {
150 *url_mismatch = true;
151 return false;
152 } else {
153 *url_mismatch = false;
154 }
155
156 // Add our route ID to the existing instance so we can send messages to it.
157 if (found_instance) {
jam 2009/11/12 20:11:23 nit: chrome style is to not use brace brackets for
158 instance->AddSender(sender, sender_route_id);
159 }
160 // Add the passed sender/document_id to the worker instance.
161 instance->AddToDocumentSet(sender, document_id);
162 return found_instance;
163 }
164
165 void WorkerService::DocumentDetached(IPC::Message::Sender* sender,
166 unsigned long long document_id) {
167 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
168 !iter.Done(); ++iter) {
169 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
170 worker->DocumentDetached(sender, document_id);
171 }
172
173 // Remove any queued shared workers for this document.
174 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
jam 2009/11/12 20:11:23 nit: in the loop above and below, you use "iter",
175 i != queued_workers_.end();) {
176 if (i->is_shared) {
177 i->RemoveFromDocumentSet(sender, document_id);
178 if (i->document_set.empty()) {
179 i = queued_workers_.erase(i);
180 continue;
181 }
182 }
183 ++i;
184 }
185
186 // Remove the document from any pending shared workers.
187 for (WorkerProcessHost::Instances::iterator iter =
188 pending_shared_workers_.begin();
189 iter != pending_shared_workers_.end(); ) {
190 iter->RemoveFromDocumentSet(sender, document_id);
191 if (iter->document_set.empty()) {
192 iter = pending_shared_workers_.erase(iter);
193 } else {
194 ++iter;
195 }
196 }
197
198 }
199
200 void WorkerService::CancelCreateDedicatedWorker(IPC::Message::Sender* sender,
97 int sender_route_id) { 201 int sender_route_id) {
98 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); 202 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
99 i != queued_workers_.end(); ++i) { 203 i != queued_workers_.end(); ++i) {
100 if (i->sender_id == sender_id && 204 if (i->HasSender(sender, sender_route_id)) {
101 i->sender_route_id == sender_route_id) { 205 DCHECK(!i->is_shared);
102 queued_workers_.erase(i); 206 queued_workers_.erase(i);
103 return; 207 return;
104 } 208 }
105 } 209 }
106 210
107 // There could be a race condition where the WebWorkerProxy told us to cancel 211 // There could be a race condition where the WebWorkerProxy told us to cancel
108 // the worker right as we sent it a message say it's been created. Look at 212 // the worker right as we sent it a message say it's been created. Look at
109 // the running workers. 213 // the running workers.
110 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); 214 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
111 !iter.Done(); ++iter) { 215 !iter.Done(); ++iter) {
112 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); 216 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
113 for (WorkerProcessHost::Instances::const_iterator instance = 217 for (WorkerProcessHost::Instances::const_iterator instance =
114 worker->instances().begin(); 218 worker->instances().begin();
115 instance != worker->instances().end(); ++instance) { 219 instance != worker->instances().end(); ++instance) {
116 if (instance->sender_id == sender_id && 220 if (instance->HasSender(sender, sender_route_id)) {
117 instance->sender_route_id == sender_route_id) {
118 // Fake a worker destroyed message so that WorkerProcessHost cleans up 221 // Fake a worker destroyed message so that WorkerProcessHost cleans up
119 // properly. 222 // properly.
120 WorkerHostMsg_WorkerContextDestroyed msg(sender_route_id); 223 WorkerHostMsg_WorkerContextDestroyed msg(sender_route_id);
121 ForwardMessage(msg, sender_id); 224 ForwardMessage(msg, sender);
122 return; 225 return;
123 } 226 }
124 } 227 }
125 } 228 }
126 229
127 DCHECK(false) << "Couldn't find worker to cancel"; 230 DCHECK(false) << "Couldn't find worker to cancel";
128 } 231 }
129 232
130 void WorkerService::ForwardMessage(const IPC::Message& message, 233 void WorkerService::ForwardMessage(const IPC::Message& message,
131 int sender_pid) { 234 IPC::Message::Sender* sender) {
132 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); 235 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
133 !iter.Done(); ++iter) { 236 !iter.Done(); ++iter) {
134 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); 237 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
135 if (worker->FilterMessage(message, sender_pid)) 238 if (worker->FilterMessage(message, sender))
136 return; 239 return;
137 } 240 }
138 241
139 // TODO(jabdelmalek): tell sender that callee is gone 242 // TODO(jabdelmalek): tell sender that callee is gone
140 } 243 }
141 244
142 WorkerProcessHost* WorkerService::GetProcessForDomain(const GURL& url) { 245 WorkerProcessHost* WorkerService::GetProcessForDomain(const GURL& url) {
143 int num_processes = 0; 246 int num_processes = 0;
144 std::string domain = 247 std::string domain =
145 net::RegistryControlledDomainService::GetDomainAndRegistry(url); 248 net::RegistryControlledDomainService::GetDomainAndRegistry(url);
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 void WorkerService::SenderShutdown(IPC::Message::Sender* sender) { 333 void WorkerService::SenderShutdown(IPC::Message::Sender* sender) {
231 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); 334 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
232 !iter.Done(); ++iter) { 335 !iter.Done(); ++iter) {
233 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); 336 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
234 worker->SenderShutdown(sender); 337 worker->SenderShutdown(sender);
235 } 338 }
236 339
237 // See if that render process had any queued workers. 340 // See if that render process had any queued workers.
238 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); 341 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
239 i != queued_workers_.end();) { 342 i != queued_workers_.end();) {
240 if (i->sender == sender) { 343 i->RemoveSenders(sender);
344 if (i->senders.empty()) {
241 i = queued_workers_.erase(i); 345 i = queued_workers_.erase(i);
242 } else { 346 } else {
243 ++i; 347 ++i;
244 } 348 }
245 } 349 }
350
351 // Also, see if that render process had any pending shared workers.
352 for (WorkerProcessHost::Instances::iterator iter =
353 pending_shared_workers_.begin();
354 iter != pending_shared_workers_.end(); ) {
355 iter->RemoveAllAssociatedDocuments(sender);
356 if (iter->document_set.empty()) {
357 iter = pending_shared_workers_.erase(iter);
358 } else {
359 ++iter;
360 }
361 }
246 } 362 }
247 363
248 void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) { 364 void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) {
249 if (queued_workers_.empty()) 365 if (queued_workers_.empty())
250 return; 366 return;
251 367
252 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); 368 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
253 i != queued_workers_.end();) { 369 i != queued_workers_.end();) {
254 if (CanCreateWorkerProcess(*i)) { 370 if (CanCreateWorkerProcess(*i)) {
255 WorkerProcessHost* worker = 371 WorkerProcessHost* worker =
(...skipping 18 matching lines...) Expand all
274 if (iter->id() != worker_process_id) 390 if (iter->id() != worker_process_id)
275 continue; 391 continue;
276 392
277 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); 393 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
278 WorkerProcessHost::Instances::const_iterator instance = 394 WorkerProcessHost::Instances::const_iterator instance =
279 worker->instances().begin(); 395 worker->instances().begin();
280 return instance == worker->instances().end() ? NULL : &*instance; 396 return instance == worker->instances().end() ? NULL : &*instance;
281 } 397 }
282 return NULL; 398 return NULL;
283 } 399 }
400
401 WorkerProcessHost::WorkerInstance*
402 WorkerService::FindSharedWorkerInstance(const GURL& url, const string16& name) {
403 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
404 !iter.Done(); ++iter) {
405 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter);
406 for (WorkerProcessHost::Instances::iterator instance_iter =
407 worker->mutable_instances().begin();
408 instance_iter != worker->mutable_instances().end();
409 ++instance_iter) {
410 if (instance_iter->Matches(url, name))
411 return &(*instance_iter);
412 }
413 }
414 return NULL;
415 }
416
417 WorkerProcessHost::WorkerInstance*
418 WorkerService::FindPendingInstance(const GURL& url, const string16& name) {
419 // Walk the pending instances looking for a matching pending worker.
420 for (WorkerProcessHost::Instances::iterator iter =
421 pending_shared_workers_.begin();
422 iter != pending_shared_workers_.end();
423 ++iter) {
424 if (iter->Matches(url, name)) {
425 return &(*iter);
426 }
427 }
428 return NULL;
429 }
430
431
432 void WorkerService::RemovePendingInstance(const GURL& url,
433 const string16& name) {
434 // Walk the pending instances looking for a matching pending worker.
435 for (WorkerProcessHost::Instances::iterator iter =
436 pending_shared_workers_.begin();
437 iter != pending_shared_workers_.end();
438 ++iter) {
439 if (iter->Matches(url, name)) {
440 pending_shared_workers_.erase(iter);
441 break;
442 }
443 }
444 }
445
446 WorkerProcessHost::WorkerInstance*
447 WorkerService::CreatePendingInstance(const GURL& url,
448 const string16& name) {
449 // Look for an existing pending worker.
450 WorkerProcessHost::WorkerInstance* instance =
451 FindPendingInstance(url, name);
452 if (instance)
453 return instance;
454
455 // No existing pending worker - create a new one.
456 WorkerProcessHost::WorkerInstance pending;
457 pending.url = url;
458 pending.name = name;
459 pending.is_shared = true;
460 pending_shared_workers_.push_back(pending);
461 return &pending_shared_workers_.back();
462 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698