Chromium Code Reviews| 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 |