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" |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } | |
OLD | NEW |