| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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.h" | 5 #include "content/browser/worker_host/worker_service.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/sys_info.h" | 11 #include "base/sys_info.h" |
| 11 #include "base/threading/thread.h" | 12 #include "base/threading/thread.h" |
| 12 #include "chrome/common/chrome_switches.h" | 13 #include "chrome/common/chrome_switches.h" |
| 13 #include "content/browser/worker_host/worker_message_filter.h" | 14 #include "content/browser/worker_host/worker_message_filter.h" |
| 14 #include "content/browser/worker_host/worker_process_host.h" | 15 #include "content/browser/worker_host/worker_process_host.h" |
| 15 #include "content/common/view_messages.h" | 16 #include "content/common/view_messages.h" |
| 16 #include "content/common/worker_messages.h" | 17 #include "content/common/worker_messages.h" |
| 17 #include "net/base/registry_controlled_domain.h" | 18 #include "net/base/registry_controlled_domain.h" |
| 18 | 19 |
| 19 const int WorkerService::kMaxWorkerProcessesWhenSharing = 10; | 20 const int WorkerService::kMaxWorkerProcessesWhenSharing = 10; |
| 20 const int WorkerService::kMaxWorkersWhenSeparate = 64; | 21 const int WorkerService::kMaxWorkersWhenSeparate = 64; |
| 21 const int WorkerService::kMaxWorkersPerTabWhenSeparate = 16; | 22 const int WorkerService::kMaxWorkersPerTabWhenSeparate = 16; |
| 22 | 23 |
| 23 WorkerService* WorkerService::GetInstance() { | 24 WorkerService* WorkerService::GetInstance() { |
| 25 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 24 return Singleton<WorkerService>::get(); | 26 return Singleton<WorkerService>::get(); |
| 25 } | 27 } |
| 26 | 28 |
| 27 WorkerService::WorkerService() : next_worker_route_id_(0) { | 29 WorkerService::WorkerService() : next_worker_route_id_(0) { |
| 28 } | 30 } |
| 29 | 31 |
| 30 WorkerService::~WorkerService() { | 32 WorkerService::~WorkerService() { |
| 33 // Since we're a Singleton, we are deleted on the UI thread instead. |
| 34 DetachFromThread(); |
| 31 } | 35 } |
| 32 | 36 |
| 33 void WorkerService::OnWorkerMessageFilterClosing(WorkerMessageFilter* filter) { | 37 void WorkerService::OnWorkerMessageFilterClosing(WorkerMessageFilter* filter) { |
| 38 DCHECK(CalledOnValidThread()); |
| 34 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 39 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 35 !iter.Done(); ++iter) { | 40 !iter.Done(); ++iter) { |
| 36 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 41 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 37 worker->FilterShutdown(filter); | 42 worker->FilterShutdown(filter); |
| 38 } | 43 } |
| 39 | 44 |
| 40 // See if that process had any queued workers. | 45 // See if that process had any queued workers. |
| 41 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); | 46 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); |
| 42 i != queued_workers_.end();) { | 47 i != queued_workers_.end();) { |
| 43 i->RemoveFilters(filter); | 48 i->RemoveFilters(filter); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 64 // the queued workers, or a renderer has shut down, in which case it doesn't | 69 // the queued workers, or a renderer has shut down, in which case it doesn't |
| 65 // affect anything. We call this function in both scenarios because then we | 70 // affect anything. We call this function in both scenarios because then we |
| 66 // don't have to keep track which filters are from worker processes. | 71 // don't have to keep track which filters are from worker processes. |
| 67 TryStartingQueuedWorker(); | 72 TryStartingQueuedWorker(); |
| 68 } | 73 } |
| 69 | 74 |
| 70 void WorkerService::CreateWorker( | 75 void WorkerService::CreateWorker( |
| 71 const ViewHostMsg_CreateWorker_Params& params, | 76 const ViewHostMsg_CreateWorker_Params& params, |
| 72 int route_id, | 77 int route_id, |
| 73 WorkerMessageFilter* filter, | 78 WorkerMessageFilter* filter, |
| 74 net::URLRequestContextGetter* request_context) { | 79 net::URLRequestContextGetter* request_context_getter, |
| 75 | 80 const content::ResourceContext& resource_context) { |
| 81 DCHECK(CalledOnValidThread()); |
| 82 // TODO(willchan): Eliminate the need for this downcast. |
| 76 ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>( | 83 ChromeURLRequestContext* context = static_cast<ChromeURLRequestContext*>( |
| 77 request_context->GetURLRequestContext()); | 84 request_context_getter->GetURLRequestContext()); |
| 78 | 85 |
| 79 // Generate a unique route id for the browser-worker communication that's | 86 // Generate a unique route id for the browser-worker communication that's |
| 80 // unique among all worker processes. That way when the worker process sends | 87 // unique among all worker processes. That way when the worker process sends |
| 81 // a wrapped IPC message through us, we know which WorkerProcessHost to give | 88 // a wrapped IPC message through us, we know which WorkerProcessHost to give |
| 82 // it to. | 89 // it to. |
| 83 WorkerProcessHost::WorkerInstance instance( | 90 WorkerProcessHost::WorkerInstance instance( |
| 84 params.url, | 91 params.url, |
| 85 params.is_shared, | 92 params.is_shared, |
| 86 context->is_incognito(), | 93 context->is_incognito(), |
| 87 params.name, | 94 params.name, |
| 88 next_worker_route_id(), | 95 next_worker_route_id(), |
| 89 params.is_shared ? 0 : filter->render_process_id(), | 96 params.is_shared ? 0 : filter->render_process_id(), |
| 90 params.is_shared ? 0 : params.parent_appcache_host_id, | 97 params.is_shared ? 0 : params.parent_appcache_host_id, |
| 91 params.is_shared ? params.script_resource_appcache_id : 0, | 98 params.is_shared ? params.script_resource_appcache_id : 0, |
| 92 request_context); | 99 request_context_getter, |
| 100 resource_context); |
| 93 instance.AddFilter(filter, route_id); | 101 instance.AddFilter(filter, route_id); |
| 94 instance.worker_document_set()->Add( | 102 instance.worker_document_set()->Add( |
| 95 filter, params.document_id, filter->render_process_id(), | 103 filter, params.document_id, filter->render_process_id(), |
| 96 params.render_view_route_id); | 104 params.render_view_route_id); |
| 97 | 105 |
| 98 CreateWorkerFromInstance(instance); | 106 CreateWorkerFromInstance(instance); |
| 99 } | 107 } |
| 100 | 108 |
| 101 void WorkerService::LookupSharedWorker( | 109 void WorkerService::LookupSharedWorker( |
| 102 const ViewHostMsg_CreateWorker_Params& params, | 110 const ViewHostMsg_CreateWorker_Params& params, |
| 103 int route_id, | 111 int route_id, |
| 104 WorkerMessageFilter* filter, | 112 WorkerMessageFilter* filter, |
| 105 bool incognito, | 113 bool incognito, |
| 106 bool* exists, | 114 bool* exists, |
| 107 bool* url_mismatch) { | 115 bool* url_mismatch) { |
| 108 | 116 DCHECK(CalledOnValidThread()); |
| 109 *exists = true; | 117 *exists = true; |
| 110 WorkerProcessHost::WorkerInstance* instance = FindSharedWorkerInstance( | 118 WorkerProcessHost::WorkerInstance* instance = FindSharedWorkerInstance( |
| 111 params.url, params.name, incognito); | 119 params.url, params.name, incognito); |
| 112 | 120 |
| 113 if (!instance) { | 121 if (!instance) { |
| 114 // If no worker instance currently exists, we need to create a pending | 122 // If no worker instance currently exists, we need to create a pending |
| 115 // instance - this is to make sure that any subsequent lookups passing a | 123 // instance - this is to make sure that any subsequent lookups passing a |
| 116 // mismatched URL get the appropriate url_mismatch error at lookup time. | 124 // mismatched URL get the appropriate url_mismatch error at lookup time. |
| 117 // Having named shared workers was a Really Bad Idea due to details like | 125 // Having named shared workers was a Really Bad Idea due to details like |
| 118 // this. | 126 // this. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 137 // worker's document set for nested workers. | 145 // worker's document set for nested workers. |
| 138 instance->worker_document_set()->Add( | 146 instance->worker_document_set()->Add( |
| 139 filter, params.document_id, filter->render_process_id(), | 147 filter, params.document_id, filter->render_process_id(), |
| 140 params.render_view_route_id); | 148 params.render_view_route_id); |
| 141 } | 149 } |
| 142 } | 150 } |
| 143 | 151 |
| 144 void WorkerService::CancelCreateDedicatedWorker( | 152 void WorkerService::CancelCreateDedicatedWorker( |
| 145 int route_id, | 153 int route_id, |
| 146 WorkerMessageFilter* filter) { | 154 WorkerMessageFilter* filter) { |
| 155 DCHECK(CalledOnValidThread()); |
| 147 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); | 156 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); |
| 148 i != queued_workers_.end(); ++i) { | 157 i != queued_workers_.end(); ++i) { |
| 149 if (i->HasFilter(filter, route_id)) { | 158 if (i->HasFilter(filter, route_id)) { |
| 150 DCHECK(!i->shared()); | 159 DCHECK(!i->shared()); |
| 151 queued_workers_.erase(i); | 160 queued_workers_.erase(i); |
| 152 return; | 161 return; |
| 153 } | 162 } |
| 154 } | 163 } |
| 155 | 164 |
| 156 // There could be a race condition where the WebWorkerProxy told us to cancel | 165 // There could be a race condition where the WebWorkerProxy told us to cancel |
| (...skipping 13 matching lines...) Expand all Loading... |
| 170 return; | 179 return; |
| 171 } | 180 } |
| 172 } | 181 } |
| 173 } | 182 } |
| 174 | 183 |
| 175 DCHECK(false) << "Couldn't find worker to cancel"; | 184 DCHECK(false) << "Couldn't find worker to cancel"; |
| 176 } | 185 } |
| 177 | 186 |
| 178 void WorkerService::ForwardToWorker(const IPC::Message& message, | 187 void WorkerService::ForwardToWorker(const IPC::Message& message, |
| 179 WorkerMessageFilter* filter) { | 188 WorkerMessageFilter* filter) { |
| 189 DCHECK(CalledOnValidThread()); |
| 180 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 190 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 181 !iter.Done(); ++iter) { | 191 !iter.Done(); ++iter) { |
| 182 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 192 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 183 if (worker->FilterMessage(message, filter)) | 193 if (worker->FilterMessage(message, filter)) |
| 184 return; | 194 return; |
| 185 } | 195 } |
| 186 | 196 |
| 187 // TODO(jabdelmalek): tell filter that callee is gone | 197 // TODO(jabdelmalek): tell filter that callee is gone |
| 188 } | 198 } |
| 189 | 199 |
| 190 void WorkerService::DocumentDetached(unsigned long long document_id, | 200 void WorkerService::DocumentDetached(unsigned long long document_id, |
| 191 WorkerMessageFilter* filter) { | 201 WorkerMessageFilter* filter) { |
| 202 DCHECK(CalledOnValidThread()); |
| 192 // Any associated shared workers can be shut down. | 203 // Any associated shared workers can be shut down. |
| 193 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 204 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 194 !iter.Done(); ++iter) { | 205 !iter.Done(); ++iter) { |
| 195 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 206 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 196 worker->DocumentDetached(filter, document_id); | 207 worker->DocumentDetached(filter, document_id); |
| 197 } | 208 } |
| 198 | 209 |
| 199 // Remove any queued shared workers for this document. | 210 // Remove any queued shared workers for this document. |
| 200 for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin(); | 211 for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin(); |
| 201 iter != queued_workers_.end();) { | 212 iter != queued_workers_.end();) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 217 if (iter->worker_document_set()->IsEmpty()) { | 228 if (iter->worker_document_set()->IsEmpty()) { |
| 218 iter = pending_shared_workers_.erase(iter); | 229 iter = pending_shared_workers_.erase(iter); |
| 219 } else { | 230 } else { |
| 220 ++iter; | 231 ++iter; |
| 221 } | 232 } |
| 222 } | 233 } |
| 223 } | 234 } |
| 224 | 235 |
| 225 bool WorkerService::CreateWorkerFromInstance( | 236 bool WorkerService::CreateWorkerFromInstance( |
| 226 WorkerProcessHost::WorkerInstance instance) { | 237 WorkerProcessHost::WorkerInstance instance) { |
| 238 DCHECK(CalledOnValidThread()); |
| 227 // TODO(michaeln): We need to ensure that a process is working | 239 // TODO(michaeln): We need to ensure that a process is working |
| 228 // on behalf of a single profile. The process sharing logic below | 240 // on behalf of a single profile. The process sharing logic below |
| 229 // does not ensure that. Consider making WorkerService a per profile | 241 // does not ensure that. Consider making WorkerService a per profile |
| 230 // object to help with this. | 242 // object to help with this. |
| 231 WorkerProcessHost* worker = NULL; | 243 WorkerProcessHost* worker = NULL; |
| 232 if (CommandLine::ForCurrentProcess()->HasSwitch( | 244 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 233 switches::kWebWorkerProcessPerCore)) { | 245 switches::kWebWorkerProcessPerCore)) { |
| 234 worker = GetProcessToFillUpCores(); | 246 worker = GetProcessToFillUpCores(); |
| 235 } else if (CommandLine::ForCurrentProcess()->HasSwitch( | 247 } else if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 236 switches::kWebWorkerShareProcesses)) { | 248 switches::kWebWorkerShareProcesses)) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 iter = queued_workers_.erase(iter); | 314 iter = queued_workers_.erase(iter); |
| 303 } else { | 315 } else { |
| 304 ++iter; | 316 ++iter; |
| 305 } | 317 } |
| 306 } | 318 } |
| 307 } | 319 } |
| 308 | 320 |
| 309 if (!worker) { | 321 if (!worker) { |
| 310 WorkerMessageFilter* first_filter = instance.filters().begin()->first; | 322 WorkerMessageFilter* first_filter = instance.filters().begin()->first; |
| 311 worker = new WorkerProcessHost( | 323 worker = new WorkerProcessHost( |
| 312 first_filter->resource_dispatcher_host(), | 324 instance.request_context_getter(), |
| 313 instance.request_context()); | 325 instance.resource_context(), |
| 326 first_filter->resource_dispatcher_host()); |
| 314 // TODO(atwilson): This won't work if the message is from a worker process. | 327 // TODO(atwilson): This won't work if the message is from a worker process. |
| 315 // We don't support that yet though (this message is only sent from | 328 // We don't support that yet though (this message is only sent from |
| 316 // renderers) but when we do, we'll need to add code to pass in the current | 329 // renderers) but when we do, we'll need to add code to pass in the current |
| 317 // worker's document set for nested workers. | 330 // worker's document set for nested workers. |
| 318 if (!worker->Init(first_filter->render_process_id())) { | 331 if (!worker->Init(first_filter->render_process_id())) { |
| 319 delete worker; | 332 delete worker; |
| 320 return false; | 333 return false; |
| 321 } | 334 } |
| 322 } | 335 } |
| 323 | 336 |
| 324 // TODO(michaeln): As written, test can fail per my earlier comment in | 337 // TODO(michaeln): As written, test can fail per my earlier comment in |
| 325 // this method, but that's a bug. | 338 // this method, but that's a bug. |
| 326 // DCHECK(worker->request_context() == instance.request_context()); | 339 // DCHECK(worker->request_context() == instance.request_context()); |
| 327 | 340 |
| 328 worker->CreateWorker(instance); | 341 worker->CreateWorker(instance); |
| 329 return true; | 342 return true; |
| 330 } | 343 } |
| 331 | 344 |
| 332 WorkerProcessHost* WorkerService::GetProcessForDomain(const GURL& url) { | 345 WorkerProcessHost* WorkerService::GetProcessForDomain(const GURL& url) { |
| 346 DCHECK(CalledOnValidThread()); |
| 333 int num_processes = 0; | 347 int num_processes = 0; |
| 334 std::string domain = | 348 std::string domain = |
| 335 net::RegistryControlledDomainService::GetDomainAndRegistry(url); | 349 net::RegistryControlledDomainService::GetDomainAndRegistry(url); |
| 336 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 350 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 337 !iter.Done(); ++iter) { | 351 !iter.Done(); ++iter) { |
| 338 num_processes++; | 352 num_processes++; |
| 339 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 353 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 340 for (WorkerProcessHost::Instances::const_iterator instance = | 354 for (WorkerProcessHost::Instances::const_iterator instance = |
| 341 worker->instances().begin(); | 355 worker->instances().begin(); |
| 342 instance != worker->instances().end(); ++instance) { | 356 instance != worker->instances().end(); ++instance) { |
| 343 if (net::RegistryControlledDomainService::GetDomainAndRegistry( | 357 if (net::RegistryControlledDomainService::GetDomainAndRegistry( |
| 344 instance->url()) == domain) { | 358 instance->url()) == domain) { |
| 345 return worker; | 359 return worker; |
| 346 } | 360 } |
| 347 } | 361 } |
| 348 } | 362 } |
| 349 | 363 |
| 350 if (num_processes >= kMaxWorkerProcessesWhenSharing) | 364 if (num_processes >= kMaxWorkerProcessesWhenSharing) |
| 351 return GetLeastLoadedWorker(); | 365 return GetLeastLoadedWorker(); |
| 352 | 366 |
| 353 return NULL; | 367 return NULL; |
| 354 } | 368 } |
| 355 | 369 |
| 356 WorkerProcessHost* WorkerService::GetProcessToFillUpCores() { | 370 WorkerProcessHost* WorkerService::GetProcessToFillUpCores() { |
| 371 DCHECK(CalledOnValidThread()); |
| 357 int num_processes = 0; | 372 int num_processes = 0; |
| 358 BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 373 BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 359 for (; !iter.Done(); ++iter) | 374 for (; !iter.Done(); ++iter) |
| 360 num_processes++; | 375 num_processes++; |
| 361 | 376 |
| 362 if (num_processes >= base::SysInfo::NumberOfProcessors()) | 377 if (num_processes >= base::SysInfo::NumberOfProcessors()) |
| 363 return GetLeastLoadedWorker(); | 378 return GetLeastLoadedWorker(); |
| 364 | 379 |
| 365 return NULL; | 380 return NULL; |
| 366 } | 381 } |
| 367 | 382 |
| 368 WorkerProcessHost* WorkerService::GetLeastLoadedWorker() { | 383 WorkerProcessHost* WorkerService::GetLeastLoadedWorker() { |
| 384 DCHECK(CalledOnValidThread()); |
| 369 WorkerProcessHost* smallest = NULL; | 385 WorkerProcessHost* smallest = NULL; |
| 370 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 386 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 371 !iter.Done(); ++iter) { | 387 !iter.Done(); ++iter) { |
| 372 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 388 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 373 if (!smallest || worker->instances().size() < smallest->instances().size()) | 389 if (!smallest || worker->instances().size() < smallest->instances().size()) |
| 374 smallest = worker; | 390 smallest = worker; |
| 375 } | 391 } |
| 376 | 392 |
| 377 return smallest; | 393 return smallest; |
| 378 } | 394 } |
| 379 | 395 |
| 380 bool WorkerService::CanCreateWorkerProcess( | 396 bool WorkerService::CanCreateWorkerProcess( |
| 381 const WorkerProcessHost::WorkerInstance& instance) { | 397 const WorkerProcessHost::WorkerInstance& instance) { |
| 398 DCHECK(CalledOnValidThread()); |
| 382 // Worker can be fired off if *any* parent has room. | 399 // Worker can be fired off if *any* parent has room. |
| 383 const WorkerDocumentSet::DocumentInfoSet& parents = | 400 const WorkerDocumentSet::DocumentInfoSet& parents = |
| 384 instance.worker_document_set()->documents(); | 401 instance.worker_document_set()->documents(); |
| 385 | 402 |
| 386 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter = | 403 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter = |
| 387 parents.begin(); | 404 parents.begin(); |
| 388 parent_iter != parents.end(); ++parent_iter) { | 405 parent_iter != parents.end(); ++parent_iter) { |
| 389 bool hit_total_worker_limit = false; | 406 bool hit_total_worker_limit = false; |
| 390 if (TabCanCreateWorkerProcess(parent_iter->render_process_id(), | 407 if (TabCanCreateWorkerProcess(parent_iter->render_process_id(), |
| 391 parent_iter->render_view_id(), | 408 parent_iter->render_view_id(), |
| 392 &hit_total_worker_limit)) { | 409 &hit_total_worker_limit)) { |
| 393 return true; | 410 return true; |
| 394 } | 411 } |
| 395 // Return false if already at the global worker limit (no need to continue | 412 // Return false if already at the global worker limit (no need to continue |
| 396 // checking parent tabs). | 413 // checking parent tabs). |
| 397 if (hit_total_worker_limit) | 414 if (hit_total_worker_limit) |
| 398 return false; | 415 return false; |
| 399 } | 416 } |
| 400 // If we've reached here, none of the parent tabs is allowed to create an | 417 // If we've reached here, none of the parent tabs is allowed to create an |
| 401 // instance. | 418 // instance. |
| 402 return false; | 419 return false; |
| 403 } | 420 } |
| 404 | 421 |
| 405 bool WorkerService::TabCanCreateWorkerProcess(int render_process_id, | 422 bool WorkerService::TabCanCreateWorkerProcess(int render_process_id, |
| 406 int render_view_id, | 423 int render_view_id, |
| 407 bool* hit_total_worker_limit) { | 424 bool* hit_total_worker_limit) { |
| 425 DCHECK(CalledOnValidThread()); |
| 408 int total_workers = 0; | 426 int total_workers = 0; |
| 409 int workers_per_tab = 0; | 427 int workers_per_tab = 0; |
| 410 *hit_total_worker_limit = false; | 428 *hit_total_worker_limit = false; |
| 411 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 429 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 412 !iter.Done(); ++iter) { | 430 !iter.Done(); ++iter) { |
| 413 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 431 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 414 for (WorkerProcessHost::Instances::const_iterator cur_instance = | 432 for (WorkerProcessHost::Instances::const_iterator cur_instance = |
| 415 worker->instances().begin(); | 433 worker->instances().begin(); |
| 416 cur_instance != worker->instances().end(); ++cur_instance) { | 434 cur_instance != worker->instances().end(); ++cur_instance) { |
| 417 total_workers++; | 435 total_workers++; |
| 418 if (total_workers >= kMaxWorkersWhenSeparate) { | 436 if (total_workers >= kMaxWorkersWhenSeparate) { |
| 419 *hit_total_worker_limit = true; | 437 *hit_total_worker_limit = true; |
| 420 return false; | 438 return false; |
| 421 } | 439 } |
| 422 if (cur_instance->RendererIsParent(render_process_id, render_view_id)) { | 440 if (cur_instance->RendererIsParent(render_process_id, render_view_id)) { |
| 423 workers_per_tab++; | 441 workers_per_tab++; |
| 424 if (workers_per_tab >= kMaxWorkersPerTabWhenSeparate) | 442 if (workers_per_tab >= kMaxWorkersPerTabWhenSeparate) |
| 425 return false; | 443 return false; |
| 426 } | 444 } |
| 427 } | 445 } |
| 428 } | 446 } |
| 429 | 447 |
| 430 return true; | 448 return true; |
| 431 } | 449 } |
| 432 | 450 |
| 433 void WorkerService::TryStartingQueuedWorker() { | 451 void WorkerService::TryStartingQueuedWorker() { |
| 452 DCHECK(CalledOnValidThread()); |
| 434 if (queued_workers_.empty()) | 453 if (queued_workers_.empty()) |
| 435 return; | 454 return; |
| 436 | 455 |
| 437 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); | 456 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); |
| 438 i != queued_workers_.end();) { | 457 i != queued_workers_.end();) { |
| 439 if (CanCreateWorkerProcess(*i)) { | 458 if (CanCreateWorkerProcess(*i)) { |
| 440 WorkerProcessHost::WorkerInstance instance = *i; | 459 WorkerProcessHost::WorkerInstance instance = *i; |
| 441 queued_workers_.erase(i); | 460 queued_workers_.erase(i); |
| 442 CreateWorkerFromInstance(instance); | 461 CreateWorkerFromInstance(instance); |
| 443 | 462 |
| 444 // CreateWorkerFromInstance can modify the queued_workers_ list when it | 463 // CreateWorkerFromInstance can modify the queued_workers_ list when it |
| 445 // coalesces queued instances after starting a shared worker, so we | 464 // coalesces queued instances after starting a shared worker, so we |
| 446 // have to rescan the list from the beginning (our iterator is now | 465 // have to rescan the list from the beginning (our iterator is now |
| 447 // invalid). This is not a big deal as having any queued workers will be | 466 // invalid). This is not a big deal as having any queued workers will be |
| 448 // rare in practice so the list will be small. | 467 // rare in practice so the list will be small. |
| 449 i = queued_workers_.begin(); | 468 i = queued_workers_.begin(); |
| 450 } else { | 469 } else { |
| 451 ++i; | 470 ++i; |
| 452 } | 471 } |
| 453 } | 472 } |
| 454 } | 473 } |
| 455 | 474 |
| 456 bool WorkerService::GetRendererForWorker(int worker_process_id, | 475 bool WorkerService::GetRendererForWorker(int worker_process_id, |
| 457 int* render_process_id, | 476 int* render_process_id, |
| 458 int* render_view_id) const { | 477 int* render_view_id) const { |
| 478 DCHECK(CalledOnValidThread()); |
| 459 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 479 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 460 !iter.Done(); ++iter) { | 480 !iter.Done(); ++iter) { |
| 461 if (iter->id() != worker_process_id) | 481 if (iter->id() != worker_process_id) |
| 462 continue; | 482 continue; |
| 463 | 483 |
| 464 // This code assumes one worker per process, see function comment in header! | 484 // This code assumes one worker per process, see function comment in header! |
| 465 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 485 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 466 WorkerProcessHost::Instances::const_iterator first_instance = | 486 WorkerProcessHost::Instances::const_iterator first_instance = |
| 467 worker->instances().begin(); | 487 worker->instances().begin(); |
| 468 if (first_instance == worker->instances().end()) | 488 if (first_instance == worker->instances().end()) |
| 469 return false; | 489 return false; |
| 470 | 490 |
| 471 WorkerDocumentSet::DocumentInfoSet::const_iterator info = | 491 WorkerDocumentSet::DocumentInfoSet::const_iterator info = |
| 472 first_instance->worker_document_set()->documents().begin(); | 492 first_instance->worker_document_set()->documents().begin(); |
| 473 *render_process_id = info->render_process_id(); | 493 *render_process_id = info->render_process_id(); |
| 474 *render_view_id = info->render_view_id(); | 494 *render_view_id = info->render_view_id(); |
| 475 return true; | 495 return true; |
| 476 } | 496 } |
| 477 return false; | 497 return false; |
| 478 } | 498 } |
| 479 | 499 |
| 480 const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance( | 500 const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance( |
| 481 int worker_process_id) { | 501 int worker_process_id) { |
| 502 DCHECK(CalledOnValidThread()); |
| 482 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 503 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 483 !iter.Done(); ++iter) { | 504 !iter.Done(); ++iter) { |
| 484 if (iter->id() != worker_process_id) | 505 if (iter->id() != worker_process_id) |
| 485 continue; | 506 continue; |
| 486 | 507 |
| 487 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 508 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 488 WorkerProcessHost::Instances::const_iterator instance = | 509 WorkerProcessHost::Instances::const_iterator instance = |
| 489 worker->instances().begin(); | 510 worker->instances().begin(); |
| 490 return instance == worker->instances().end() ? NULL : &*instance; | 511 return instance == worker->instances().end() ? NULL : &*instance; |
| 491 } | 512 } |
| 492 return NULL; | 513 return NULL; |
| 493 } | 514 } |
| 494 | 515 |
| 495 WorkerProcessHost::WorkerInstance* | 516 WorkerProcessHost::WorkerInstance* |
| 496 WorkerService::FindSharedWorkerInstance(const GURL& url, const string16& name, | 517 WorkerService::FindSharedWorkerInstance(const GURL& url, const string16& name, |
| 497 bool incognito) { | 518 bool incognito) { |
| 519 DCHECK(CalledOnValidThread()); |
| 498 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 520 for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); |
| 499 !iter.Done(); ++iter) { | 521 !iter.Done(); ++iter) { |
| 500 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 522 WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); |
| 501 for (WorkerProcessHost::Instances::iterator instance_iter = | 523 for (WorkerProcessHost::Instances::iterator instance_iter = |
| 502 worker->mutable_instances().begin(); | 524 worker->mutable_instances().begin(); |
| 503 instance_iter != worker->mutable_instances().end(); | 525 instance_iter != worker->mutable_instances().end(); |
| 504 ++instance_iter) { | 526 ++instance_iter) { |
| 505 if (instance_iter->Matches(url, name, incognito)) | 527 if (instance_iter->Matches(url, name, incognito)) |
| 506 return &(*instance_iter); | 528 return &(*instance_iter); |
| 507 } | 529 } |
| 508 } | 530 } |
| 509 return NULL; | 531 return NULL; |
| 510 } | 532 } |
| 511 | 533 |
| 512 WorkerProcessHost::WorkerInstance* | 534 WorkerProcessHost::WorkerInstance* |
| 513 WorkerService::FindPendingInstance(const GURL& url, const string16& name, | 535 WorkerService::FindPendingInstance(const GURL& url, const string16& name, |
| 514 bool incognito) { | 536 bool incognito) { |
| 537 DCHECK(CalledOnValidThread()); |
| 515 // Walk the pending instances looking for a matching pending worker. | 538 // Walk the pending instances looking for a matching pending worker. |
| 516 for (WorkerProcessHost::Instances::iterator iter = | 539 for (WorkerProcessHost::Instances::iterator iter = |
| 517 pending_shared_workers_.begin(); | 540 pending_shared_workers_.begin(); |
| 518 iter != pending_shared_workers_.end(); | 541 iter != pending_shared_workers_.end(); |
| 519 ++iter) { | 542 ++iter) { |
| 520 if (iter->Matches(url, name, incognito)) { | 543 if (iter->Matches(url, name, incognito)) { |
| 521 return &(*iter); | 544 return &(*iter); |
| 522 } | 545 } |
| 523 } | 546 } |
| 524 return NULL; | 547 return NULL; |
| 525 } | 548 } |
| 526 | 549 |
| 527 | 550 |
| 528 void WorkerService::RemovePendingInstances(const GURL& url, | 551 void WorkerService::RemovePendingInstances(const GURL& url, |
| 529 const string16& name, | 552 const string16& name, |
| 530 bool incognito) { | 553 bool incognito) { |
| 554 DCHECK(CalledOnValidThread()); |
| 531 // Walk the pending instances looking for a matching pending worker. | 555 // Walk the pending instances looking for a matching pending worker. |
| 532 for (WorkerProcessHost::Instances::iterator iter = | 556 for (WorkerProcessHost::Instances::iterator iter = |
| 533 pending_shared_workers_.begin(); | 557 pending_shared_workers_.begin(); |
| 534 iter != pending_shared_workers_.end(); ) { | 558 iter != pending_shared_workers_.end(); ) { |
| 535 if (iter->Matches(url, name, incognito)) { | 559 if (iter->Matches(url, name, incognito)) { |
| 536 iter = pending_shared_workers_.erase(iter); | 560 iter = pending_shared_workers_.erase(iter); |
| 537 } else { | 561 } else { |
| 538 ++iter; | 562 ++iter; |
| 539 } | 563 } |
| 540 } | 564 } |
| 541 } | 565 } |
| 542 | 566 |
| 543 WorkerProcessHost::WorkerInstance* | 567 WorkerProcessHost::WorkerInstance* |
| 544 WorkerService::CreatePendingInstance(const GURL& url, | 568 WorkerService::CreatePendingInstance(const GURL& url, |
| 545 const string16& name, | 569 const string16& name, |
| 546 bool incognito) { | 570 bool incognito) { |
| 571 DCHECK(CalledOnValidThread()); |
| 547 // Look for an existing pending shared worker. | 572 // Look for an existing pending shared worker. |
| 548 WorkerProcessHost::WorkerInstance* instance = | 573 WorkerProcessHost::WorkerInstance* instance = |
| 549 FindPendingInstance(url, name, incognito); | 574 FindPendingInstance(url, name, incognito); |
| 550 if (instance) | 575 if (instance) |
| 551 return instance; | 576 return instance; |
| 552 | 577 |
| 553 // No existing pending worker - create a new one. | 578 // No existing pending worker - create a new one. |
| 554 WorkerProcessHost::WorkerInstance pending( | 579 WorkerProcessHost::WorkerInstance pending(url, true, incognito, name); |
| 555 url, true, incognito, name, MSG_ROUTING_NONE, 0, 0, 0, NULL); | |
| 556 pending_shared_workers_.push_back(pending); | 580 pending_shared_workers_.push_back(pending); |
| 557 return &pending_shared_workers_.back(); | 581 return &pending_shared_workers_.back(); |
| 558 } | 582 } |
| OLD | NEW |