| 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()); | 
| 314     // TODO(atwilson): This won't work if the message is from a worker process. | 326     // 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 | 327     // 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 | 328     // renderers) but when we do, we'll need to add code to pass in the current | 
| 317     // worker's document set for nested workers. | 329     // worker's document set for nested workers. | 
| 318     if (!worker->Init(first_filter->render_process_id())) { | 330     if (!worker->Init(first_filter->render_process_id())) { | 
| 319       delete worker; | 331       delete worker; | 
| 320       return false; | 332       return false; | 
| 321     } | 333     } | 
| 322   } | 334   } | 
| 323 | 335 | 
| 324   // TODO(michaeln): As written, test can fail per my earlier comment in | 336   // TODO(michaeln): As written, test can fail per my earlier comment in | 
| 325   // this method, but that's a bug. | 337   // this method, but that's a bug. | 
| 326   // DCHECK(worker->request_context() == instance.request_context()); | 338   // DCHECK(worker->request_context() == instance.request_context()); | 
| 327 | 339 | 
| 328   worker->CreateWorker(instance); | 340   worker->CreateWorker(instance); | 
| 329   return true; | 341   return true; | 
| 330 } | 342 } | 
| 331 | 343 | 
| 332 WorkerProcessHost* WorkerService::GetProcessForDomain(const GURL& url) { | 344 WorkerProcessHost* WorkerService::GetProcessForDomain(const GURL& url) { | 
|  | 345   DCHECK(CalledOnValidThread()); | 
| 333   int num_processes = 0; | 346   int num_processes = 0; | 
| 334   std::string domain = | 347   std::string domain = | 
| 335       net::RegistryControlledDomainService::GetDomainAndRegistry(url); | 348       net::RegistryControlledDomainService::GetDomainAndRegistry(url); | 
| 336   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 349   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 
| 337        !iter.Done(); ++iter) { | 350        !iter.Done(); ++iter) { | 
| 338     num_processes++; | 351     num_processes++; | 
| 339     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 352     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 
| 340     for (WorkerProcessHost::Instances::const_iterator instance = | 353     for (WorkerProcessHost::Instances::const_iterator instance = | 
| 341              worker->instances().begin(); | 354              worker->instances().begin(); | 
| 342          instance != worker->instances().end(); ++instance) { | 355          instance != worker->instances().end(); ++instance) { | 
| 343       if (net::RegistryControlledDomainService::GetDomainAndRegistry( | 356       if (net::RegistryControlledDomainService::GetDomainAndRegistry( | 
| 344               instance->url()) == domain) { | 357               instance->url()) == domain) { | 
| 345         return worker; | 358         return worker; | 
| 346       } | 359       } | 
| 347     } | 360     } | 
| 348   } | 361   } | 
| 349 | 362 | 
| 350   if (num_processes >= kMaxWorkerProcessesWhenSharing) | 363   if (num_processes >= kMaxWorkerProcessesWhenSharing) | 
| 351     return GetLeastLoadedWorker(); | 364     return GetLeastLoadedWorker(); | 
| 352 | 365 | 
| 353   return NULL; | 366   return NULL; | 
| 354 } | 367 } | 
| 355 | 368 | 
| 356 WorkerProcessHost* WorkerService::GetProcessToFillUpCores() { | 369 WorkerProcessHost* WorkerService::GetProcessToFillUpCores() { | 
|  | 370   DCHECK(CalledOnValidThread()); | 
| 357   int num_processes = 0; | 371   int num_processes = 0; | 
| 358   BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 372   BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 
| 359   for (; !iter.Done(); ++iter) | 373   for (; !iter.Done(); ++iter) | 
| 360     num_processes++; | 374     num_processes++; | 
| 361 | 375 | 
| 362   if (num_processes >= base::SysInfo::NumberOfProcessors()) | 376   if (num_processes >= base::SysInfo::NumberOfProcessors()) | 
| 363     return GetLeastLoadedWorker(); | 377     return GetLeastLoadedWorker(); | 
| 364 | 378 | 
| 365   return NULL; | 379   return NULL; | 
| 366 } | 380 } | 
| 367 | 381 | 
| 368 WorkerProcessHost* WorkerService::GetLeastLoadedWorker() { | 382 WorkerProcessHost* WorkerService::GetLeastLoadedWorker() { | 
|  | 383   DCHECK(CalledOnValidThread()); | 
| 369   WorkerProcessHost* smallest = NULL; | 384   WorkerProcessHost* smallest = NULL; | 
| 370   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 385   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 
| 371        !iter.Done(); ++iter) { | 386        !iter.Done(); ++iter) { | 
| 372     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 387     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 
| 373     if (!smallest || worker->instances().size() < smallest->instances().size()) | 388     if (!smallest || worker->instances().size() < smallest->instances().size()) | 
| 374       smallest = worker; | 389       smallest = worker; | 
| 375   } | 390   } | 
| 376 | 391 | 
| 377   return smallest; | 392   return smallest; | 
| 378 } | 393 } | 
| 379 | 394 | 
| 380 bool WorkerService::CanCreateWorkerProcess( | 395 bool WorkerService::CanCreateWorkerProcess( | 
| 381     const WorkerProcessHost::WorkerInstance& instance) { | 396     const WorkerProcessHost::WorkerInstance& instance) { | 
|  | 397   DCHECK(CalledOnValidThread()); | 
| 382   // Worker can be fired off if *any* parent has room. | 398   // Worker can be fired off if *any* parent has room. | 
| 383   const WorkerDocumentSet::DocumentInfoSet& parents = | 399   const WorkerDocumentSet::DocumentInfoSet& parents = | 
| 384         instance.worker_document_set()->documents(); | 400         instance.worker_document_set()->documents(); | 
| 385 | 401 | 
| 386   for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter = | 402   for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter = | 
| 387            parents.begin(); | 403            parents.begin(); | 
| 388        parent_iter != parents.end(); ++parent_iter) { | 404        parent_iter != parents.end(); ++parent_iter) { | 
| 389     bool hit_total_worker_limit = false; | 405     bool hit_total_worker_limit = false; | 
| 390     if (TabCanCreateWorkerProcess(parent_iter->render_process_id(), | 406     if (TabCanCreateWorkerProcess(parent_iter->render_process_id(), | 
| 391                                   parent_iter->render_view_id(), | 407                                   parent_iter->render_view_id(), | 
| 392                                   &hit_total_worker_limit)) { | 408                                   &hit_total_worker_limit)) { | 
| 393       return true; | 409       return true; | 
| 394     } | 410     } | 
| 395     // Return false if already at the global worker limit (no need to continue | 411     // Return false if already at the global worker limit (no need to continue | 
| 396     // checking parent tabs). | 412     // checking parent tabs). | 
| 397     if (hit_total_worker_limit) | 413     if (hit_total_worker_limit) | 
| 398       return false; | 414       return false; | 
| 399   } | 415   } | 
| 400   // If we've reached here, none of the parent tabs is allowed to create an | 416   // If we've reached here, none of the parent tabs is allowed to create an | 
| 401   // instance. | 417   // instance. | 
| 402   return false; | 418   return false; | 
| 403 } | 419 } | 
| 404 | 420 | 
| 405 bool WorkerService::TabCanCreateWorkerProcess(int render_process_id, | 421 bool WorkerService::TabCanCreateWorkerProcess(int render_process_id, | 
| 406                                               int render_view_id, | 422                                               int render_view_id, | 
| 407                                               bool* hit_total_worker_limit) { | 423                                               bool* hit_total_worker_limit) { | 
|  | 424   DCHECK(CalledOnValidThread()); | 
| 408   int total_workers = 0; | 425   int total_workers = 0; | 
| 409   int workers_per_tab = 0; | 426   int workers_per_tab = 0; | 
| 410   *hit_total_worker_limit = false; | 427   *hit_total_worker_limit = false; | 
| 411   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 428   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 
| 412        !iter.Done(); ++iter) { | 429        !iter.Done(); ++iter) { | 
| 413     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 430     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 
| 414     for (WorkerProcessHost::Instances::const_iterator cur_instance = | 431     for (WorkerProcessHost::Instances::const_iterator cur_instance = | 
| 415              worker->instances().begin(); | 432              worker->instances().begin(); | 
| 416          cur_instance != worker->instances().end(); ++cur_instance) { | 433          cur_instance != worker->instances().end(); ++cur_instance) { | 
| 417       total_workers++; | 434       total_workers++; | 
| 418       if (total_workers >= kMaxWorkersWhenSeparate) { | 435       if (total_workers >= kMaxWorkersWhenSeparate) { | 
| 419         *hit_total_worker_limit = true; | 436         *hit_total_worker_limit = true; | 
| 420         return false; | 437         return false; | 
| 421       } | 438       } | 
| 422       if (cur_instance->RendererIsParent(render_process_id, render_view_id)) { | 439       if (cur_instance->RendererIsParent(render_process_id, render_view_id)) { | 
| 423         workers_per_tab++; | 440         workers_per_tab++; | 
| 424         if (workers_per_tab >= kMaxWorkersPerTabWhenSeparate) | 441         if (workers_per_tab >= kMaxWorkersPerTabWhenSeparate) | 
| 425           return false; | 442           return false; | 
| 426       } | 443       } | 
| 427     } | 444     } | 
| 428   } | 445   } | 
| 429 | 446 | 
| 430   return true; | 447   return true; | 
| 431 } | 448 } | 
| 432 | 449 | 
| 433 void WorkerService::TryStartingQueuedWorker() { | 450 void WorkerService::TryStartingQueuedWorker() { | 
|  | 451   DCHECK(CalledOnValidThread()); | 
| 434   if (queued_workers_.empty()) | 452   if (queued_workers_.empty()) | 
| 435     return; | 453     return; | 
| 436 | 454 | 
| 437   for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); | 455   for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); | 
| 438        i != queued_workers_.end();) { | 456        i != queued_workers_.end();) { | 
| 439     if (CanCreateWorkerProcess(*i)) { | 457     if (CanCreateWorkerProcess(*i)) { | 
| 440       WorkerProcessHost::WorkerInstance instance = *i; | 458       WorkerProcessHost::WorkerInstance instance = *i; | 
| 441       queued_workers_.erase(i); | 459       queued_workers_.erase(i); | 
| 442       CreateWorkerFromInstance(instance); | 460       CreateWorkerFromInstance(instance); | 
| 443 | 461 | 
| 444       // CreateWorkerFromInstance can modify the queued_workers_ list when it | 462       // CreateWorkerFromInstance can modify the queued_workers_ list when it | 
| 445       // coalesces queued instances after starting a shared worker, so we | 463       // coalesces queued instances after starting a shared worker, so we | 
| 446       // have to rescan the list from the beginning (our iterator is now | 464       // 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 | 465       // invalid). This is not a big deal as having any queued workers will be | 
| 448       // rare in practice so the list will be small. | 466       // rare in practice so the list will be small. | 
| 449       i = queued_workers_.begin(); | 467       i = queued_workers_.begin(); | 
| 450     } else { | 468     } else { | 
| 451       ++i; | 469       ++i; | 
| 452     } | 470     } | 
| 453   } | 471   } | 
| 454 } | 472 } | 
| 455 | 473 | 
| 456 bool WorkerService::GetRendererForWorker(int worker_process_id, | 474 bool WorkerService::GetRendererForWorker(int worker_process_id, | 
| 457                                          int* render_process_id, | 475                                          int* render_process_id, | 
| 458                                          int* render_view_id) const { | 476                                          int* render_view_id) const { | 
|  | 477   DCHECK(CalledOnValidThread()); | 
| 459   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 478   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 
| 460        !iter.Done(); ++iter) { | 479        !iter.Done(); ++iter) { | 
| 461     if (iter->id() != worker_process_id) | 480     if (iter->id() != worker_process_id) | 
| 462         continue; | 481         continue; | 
| 463 | 482 | 
| 464     // This code assumes one worker per process, see function comment in header! | 483     // This code assumes one worker per process, see function comment in header! | 
| 465     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 484     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 
| 466     WorkerProcessHost::Instances::const_iterator first_instance = | 485     WorkerProcessHost::Instances::const_iterator first_instance = | 
| 467         worker->instances().begin(); | 486         worker->instances().begin(); | 
| 468     if (first_instance == worker->instances().end()) | 487     if (first_instance == worker->instances().end()) | 
| 469       return false; | 488       return false; | 
| 470 | 489 | 
| 471     WorkerDocumentSet::DocumentInfoSet::const_iterator info = | 490     WorkerDocumentSet::DocumentInfoSet::const_iterator info = | 
| 472         first_instance->worker_document_set()->documents().begin(); | 491         first_instance->worker_document_set()->documents().begin(); | 
| 473     *render_process_id = info->render_process_id(); | 492     *render_process_id = info->render_process_id(); | 
| 474     *render_view_id = info->render_view_id(); | 493     *render_view_id = info->render_view_id(); | 
| 475     return true; | 494     return true; | 
| 476   } | 495   } | 
| 477   return false; | 496   return false; | 
| 478 } | 497 } | 
| 479 | 498 | 
| 480 const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance( | 499 const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance( | 
| 481       int worker_process_id) { | 500       int worker_process_id) { | 
|  | 501   DCHECK(CalledOnValidThread()); | 
| 482   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 502   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 
| 483        !iter.Done(); ++iter) { | 503        !iter.Done(); ++iter) { | 
| 484     if (iter->id() != worker_process_id) | 504     if (iter->id() != worker_process_id) | 
| 485         continue; | 505         continue; | 
| 486 | 506 | 
| 487     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 507     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 
| 488     WorkerProcessHost::Instances::const_iterator instance = | 508     WorkerProcessHost::Instances::const_iterator instance = | 
| 489         worker->instances().begin(); | 509         worker->instances().begin(); | 
| 490     return instance == worker->instances().end() ? NULL : &*instance; | 510     return instance == worker->instances().end() ? NULL : &*instance; | 
| 491   } | 511   } | 
| 492   return NULL; | 512   return NULL; | 
| 493 } | 513 } | 
| 494 | 514 | 
| 495 WorkerProcessHost::WorkerInstance* | 515 WorkerProcessHost::WorkerInstance* | 
| 496 WorkerService::FindSharedWorkerInstance(const GURL& url, const string16& name, | 516 WorkerService::FindSharedWorkerInstance(const GURL& url, const string16& name, | 
| 497                                         bool incognito) { | 517                                         bool incognito) { | 
|  | 518   DCHECK(CalledOnValidThread()); | 
| 498   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 519   for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); | 
| 499        !iter.Done(); ++iter) { | 520        !iter.Done(); ++iter) { | 
| 500     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 521     WorkerProcessHost* worker = static_cast<WorkerProcessHost*>(*iter); | 
| 501     for (WorkerProcessHost::Instances::iterator instance_iter = | 522     for (WorkerProcessHost::Instances::iterator instance_iter = | 
| 502              worker->mutable_instances().begin(); | 523              worker->mutable_instances().begin(); | 
| 503          instance_iter != worker->mutable_instances().end(); | 524          instance_iter != worker->mutable_instances().end(); | 
| 504          ++instance_iter) { | 525          ++instance_iter) { | 
| 505       if (instance_iter->Matches(url, name, incognito)) | 526       if (instance_iter->Matches(url, name, incognito)) | 
| 506         return &(*instance_iter); | 527         return &(*instance_iter); | 
| 507     } | 528     } | 
| 508   } | 529   } | 
| 509   return NULL; | 530   return NULL; | 
| 510 } | 531 } | 
| 511 | 532 | 
| 512 WorkerProcessHost::WorkerInstance* | 533 WorkerProcessHost::WorkerInstance* | 
| 513 WorkerService::FindPendingInstance(const GURL& url, const string16& name, | 534 WorkerService::FindPendingInstance(const GURL& url, const string16& name, | 
| 514                                    bool incognito) { | 535                                    bool incognito) { | 
|  | 536   DCHECK(CalledOnValidThread()); | 
| 515   // Walk the pending instances looking for a matching pending worker. | 537   // Walk the pending instances looking for a matching pending worker. | 
| 516   for (WorkerProcessHost::Instances::iterator iter = | 538   for (WorkerProcessHost::Instances::iterator iter = | 
| 517            pending_shared_workers_.begin(); | 539            pending_shared_workers_.begin(); | 
| 518        iter != pending_shared_workers_.end(); | 540        iter != pending_shared_workers_.end(); | 
| 519        ++iter) { | 541        ++iter) { | 
| 520     if (iter->Matches(url, name, incognito)) { | 542     if (iter->Matches(url, name, incognito)) { | 
| 521       return &(*iter); | 543       return &(*iter); | 
| 522     } | 544     } | 
| 523   } | 545   } | 
| 524   return NULL; | 546   return NULL; | 
| 525 } | 547 } | 
| 526 | 548 | 
| 527 | 549 | 
| 528 void WorkerService::RemovePendingInstances(const GURL& url, | 550 void WorkerService::RemovePendingInstances(const GURL& url, | 
| 529                                            const string16& name, | 551                                            const string16& name, | 
| 530                                            bool incognito) { | 552                                            bool incognito) { | 
|  | 553   DCHECK(CalledOnValidThread()); | 
| 531   // Walk the pending instances looking for a matching pending worker. | 554   // Walk the pending instances looking for a matching pending worker. | 
| 532   for (WorkerProcessHost::Instances::iterator iter = | 555   for (WorkerProcessHost::Instances::iterator iter = | 
| 533            pending_shared_workers_.begin(); | 556            pending_shared_workers_.begin(); | 
| 534        iter != pending_shared_workers_.end(); ) { | 557        iter != pending_shared_workers_.end(); ) { | 
| 535     if (iter->Matches(url, name, incognito)) { | 558     if (iter->Matches(url, name, incognito)) { | 
| 536       iter = pending_shared_workers_.erase(iter); | 559       iter = pending_shared_workers_.erase(iter); | 
| 537     } else { | 560     } else { | 
| 538       ++iter; | 561       ++iter; | 
| 539     } | 562     } | 
| 540   } | 563   } | 
| 541 } | 564 } | 
| 542 | 565 | 
| 543 WorkerProcessHost::WorkerInstance* | 566 WorkerProcessHost::WorkerInstance* | 
| 544 WorkerService::CreatePendingInstance(const GURL& url, | 567 WorkerService::CreatePendingInstance(const GURL& url, | 
| 545                                      const string16& name, | 568                                      const string16& name, | 
| 546                                      bool incognito) { | 569                                      bool incognito) { | 
|  | 570   DCHECK(CalledOnValidThread()); | 
| 547   // Look for an existing pending shared worker. | 571   // Look for an existing pending shared worker. | 
| 548   WorkerProcessHost::WorkerInstance* instance = | 572   WorkerProcessHost::WorkerInstance* instance = | 
| 549       FindPendingInstance(url, name, incognito); | 573       FindPendingInstance(url, name, incognito); | 
| 550   if (instance) | 574   if (instance) | 
| 551     return instance; | 575     return instance; | 
| 552 | 576 | 
| 553   // No existing pending worker - create a new one. | 577   // No existing pending worker - create a new one. | 
| 554   WorkerProcessHost::WorkerInstance pending( | 578   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); | 579   pending_shared_workers_.push_back(pending); | 
| 557   return &pending_shared_workers_.back(); | 580   return &pending_shared_workers_.back(); | 
| 558 } | 581 } | 
| OLD | NEW | 
|---|