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

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

Issue 580007: Changed CreateWorker to coalesce any matching queued shared workers when a (Closed)
Patch Set: Now supports multiple queued instances of one shared worker. Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/worker_host/worker_service.h" 5 #include "chrome/browser/worker_host/worker_service.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/singleton.h" 8 #include "base/singleton.h"
9 #include "base/sys_info.h" 9 #include "base/sys_info.h"
10 #include "base/thread.h" 10 #include "base/thread.h"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 // it to. 60 // it to.
61 WorkerProcessHost::WorkerInstance instance(url, 61 WorkerProcessHost::WorkerInstance instance(url,
62 is_shared, 62 is_shared,
63 off_the_record, 63 off_the_record,
64 name, 64 name,
65 next_worker_route_id()); 65 next_worker_route_id());
66 instance.AddSender(sender, sender_route_id); 66 instance.AddSender(sender, sender_route_id);
67 instance.worker_document_set()->Add( 67 instance.worker_document_set()->Add(
68 sender, document_id, renderer_id, render_view_route_id); 68 sender, document_id, renderer_id, render_view_route_id);
69 69
70 return CreateWorkerFromInstance(instance);
71 }
72
73 bool WorkerService::CreateWorkerFromInstance(
74 WorkerProcessHost::WorkerInstance instance) {
75
70 WorkerProcessHost* worker = NULL; 76 WorkerProcessHost* worker = NULL;
71 if (CommandLine::ForCurrentProcess()->HasSwitch( 77 if (CommandLine::ForCurrentProcess()->HasSwitch(
72 switches::kWebWorkerProcessPerCore)) { 78 switches::kWebWorkerProcessPerCore)) {
73 worker = GetProcessToFillUpCores(); 79 worker = GetProcessToFillUpCores();
74 } else if (CommandLine::ForCurrentProcess()->HasSwitch( 80 } else if (CommandLine::ForCurrentProcess()->HasSwitch(
75 switches::kWebWorkerShareProcesses)) { 81 switches::kWebWorkerShareProcesses)) {
76 worker = GetProcessForDomain(url); 82 worker = GetProcessForDomain(instance.url());
77 } else { // One process per worker. 83 } else { // One process per worker.
78 if (!CanCreateWorkerProcess(instance)) { 84 if (!CanCreateWorkerProcess(instance)) {
79 queued_workers_.push_back(instance); 85 queued_workers_.push_back(instance);
80 return true; 86 return true;
81 } 87 }
82 } 88 }
83 89
84 // Check to see if this shared worker is already running (two pages may have 90 // Check to see if this shared worker is already running (two pages may have
85 // tried to start up the worker simultaneously). 91 // tried to start up the worker simultaneously).
86 if (is_shared) { 92 if (instance.shared()) {
87 // See if a worker with this name already exists. 93 // See if a worker with this name already exists.
88 WorkerProcessHost::WorkerInstance* existing_instance = 94 WorkerProcessHost::WorkerInstance* existing_instance =
89 FindSharedWorkerInstance(url, name, off_the_record); 95 FindSharedWorkerInstance(
96 instance.url(), instance.name(), instance.off_the_record());
90 // If this worker is already running, no need to create a new copy. Just 97 // If this worker is already running, no need to create a new copy. Just
91 // inform the caller that the worker has been created. 98 // inform the caller that the worker has been created.
92 if (existing_instance) { 99 if (existing_instance) {
93 // TODO(atwilson): Change this to scan the sender list (crbug.com/29243). 100 // TODO(atwilson): Change this to scan the sender list (crbug.com/29243).
94 existing_instance->AddSender(sender, sender_route_id); 101 WorkerProcessHost::WorkerInstance::SenderInfo sender_info =
95 sender->Send(new ViewMsg_WorkerCreated(sender_route_id)); 102 instance.GetSender();
103 existing_instance->AddSender(sender_info.first, sender_info.second);
104 sender_info.first->Send(new ViewMsg_WorkerCreated(sender_info.second));
96 return true; 105 return true;
97 } 106 }
98 107
99 // Look to see if there's a pending instance. 108 // Look to see if there's a pending instance.
100 WorkerProcessHost::WorkerInstance* pending = FindPendingInstance( 109 WorkerProcessHost::WorkerInstance* pending = FindPendingInstance(
101 url, name, off_the_record); 110 instance.url(), instance.name(), instance.off_the_record());
102 // If there's no instance *and* no pending instance, then it means the 111 // If there's no instance *and* no pending instance, then it means the
103 // worker started up and exited already. Log a warning because this should 112 // worker started up and exited already. Log a warning because this should
104 // be a very rare occurrence and is probably a bug, but it *can* happen so 113 // be a very rare occurrence and is probably a bug, but it *can* happen so
105 // handle it gracefully. 114 // handle it gracefully.
106 if (!pending) { 115 if (!pending) {
107 DLOG(WARNING) << "Pending worker already exited"; 116 DLOG(WARNING) << "Pending worker already exited";
108 return false; 117 return false;
109 } 118 }
110 119
111 // Assign the accumulated document set and sender list for this pending 120 // Assign the accumulated document set and sender list for this pending
112 // worker to the new instance. 121 // worker to the new instance.
113 DCHECK(!pending->worker_document_set()->IsEmpty()); 122 DCHECK(!pending->worker_document_set()->IsEmpty());
114 instance.ShareDocumentSet(*pending); 123 instance.ShareDocumentSet(*pending);
115 RemovePendingInstance(url, name, off_the_record); 124 RemovePendingInstances(
125 instance.url(), instance.name(), instance.off_the_record());
126
127 // Remove any queued instances of this worker and copy over the sender to
128 // this instance.
129 for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
130 iter != queued_workers_.end();) {
131 if (iter->Matches(instance.url(), instance.name(),
132 instance.off_the_record())) {
133 DCHECK(iter->NumSenders() == 1);
134 WorkerProcessHost::WorkerInstance::SenderInfo sender_info =
135 iter->GetSender();
136 instance.AddSender(sender_info.first, sender_info.second);
137 iter = queued_workers_.erase(iter);
138 } else {
139 ++iter;
140 }
141 }
116 } 142 }
117 143
118 if (!worker) { 144 if (!worker) {
119 worker = new WorkerProcessHost(resource_dispatcher_host_); 145 worker = new WorkerProcessHost(resource_dispatcher_host_);
120 if (!worker->Init()) { 146 if (!worker->Init()) {
121 delete worker; 147 delete worker;
122 return false; 148 return false;
123 } 149 }
124 } 150 }
125 151
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 } 422 }
397 } 423 }
398 424
399 void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) { 425 void WorkerService::WorkerProcessDestroyed(WorkerProcessHost* process) {
400 if (queued_workers_.empty()) 426 if (queued_workers_.empty())
401 return; 427 return;
402 428
403 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin(); 429 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
404 i != queued_workers_.end();) { 430 i != queued_workers_.end();) {
405 if (CanCreateWorkerProcess(*i)) { 431 if (CanCreateWorkerProcess(*i)) {
406 WorkerProcessHost* worker = 432 WorkerProcessHost::WorkerInstance instance = *i;
407 new WorkerProcessHost(resource_dispatcher_host_); 433 queued_workers_.erase(i);
408 if (!worker->Init()) { 434 CreateWorkerFromInstance(instance);
409 delete worker;
410 return;
411 }
412 435
413 worker->CreateWorker(*i); 436 // CreateWorkerFromInstance can modify the queued_workers_ list when it
414 i = queued_workers_.erase(i); 437 // coalesces queued instances after starting a shared worker, so we
438 // have to rescan the list from the beginning (our iterator is now
439 // invalid). This is not a big deal as having any queued workers will be
440 // rare in practice so the list will be small.
441 i = queued_workers_.begin();
415 } else { 442 } else {
416 ++i; 443 ++i;
417 } 444 }
418 } 445 }
419 } 446 }
420 447
421 const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance( 448 const WorkerProcessHost::WorkerInstance* WorkerService::FindWorkerInstance(
422 int worker_process_id) { 449 int worker_process_id) {
423 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS); 450 for (ChildProcessHost::Iterator iter(ChildProcessInfo::WORKER_PROCESS);
424 !iter.Done(); ++iter) { 451 !iter.Done(); ++iter) {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 iter != pending_shared_workers_.end(); 486 iter != pending_shared_workers_.end();
460 ++iter) { 487 ++iter) {
461 if (iter->Matches(url, name, off_the_record)) { 488 if (iter->Matches(url, name, off_the_record)) {
462 return &(*iter); 489 return &(*iter);
463 } 490 }
464 } 491 }
465 return NULL; 492 return NULL;
466 } 493 }
467 494
468 495
469 void WorkerService::RemovePendingInstance(const GURL& url, 496 void WorkerService::RemovePendingInstances(const GURL& url,
470 const string16& name, 497 const string16& name,
471 bool off_the_record) { 498 bool off_the_record) {
472 // Walk the pending instances looking for a matching pending worker. 499 // Walk the pending instances looking for a matching pending worker.
473 for (WorkerProcessHost::Instances::iterator iter = 500 for (WorkerProcessHost::Instances::iterator iter =
474 pending_shared_workers_.begin(); 501 pending_shared_workers_.begin();
475 iter != pending_shared_workers_.end(); 502 iter != pending_shared_workers_.end(); ) {
476 ++iter) { 503 // Pending workers should have no senders - only actively running worker
504 // instances have senders.
505 DCHECK(iter->NumSenders() == 0);
477 if (iter->Matches(url, name, off_the_record)) { 506 if (iter->Matches(url, name, off_the_record)) {
478 pending_shared_workers_.erase(iter); 507 iter = pending_shared_workers_.erase(iter);
479 break; 508 } else {
509 ++iter;
480 } 510 }
481 } 511 }
482 } 512 }
483 513
484 WorkerProcessHost::WorkerInstance* 514 WorkerProcessHost::WorkerInstance*
485 WorkerService::CreatePendingInstance(const GURL& url, 515 WorkerService::CreatePendingInstance(const GURL& url,
486 const string16& name, 516 const string16& name,
487 bool off_the_record) { 517 bool off_the_record) {
488 // Look for an existing pending worker. 518 // Look for an existing pending worker.
489 WorkerProcessHost::WorkerInstance* instance = 519 WorkerProcessHost::WorkerInstance* instance =
490 FindPendingInstance(url, name, off_the_record); 520 FindPendingInstance(url, name, off_the_record);
491 if (instance) 521 if (instance)
492 return instance; 522 return instance;
493 523
494 // No existing pending worker - create a new one. 524 // No existing pending worker - create a new one.
495 WorkerProcessHost::WorkerInstance pending( 525 WorkerProcessHost::WorkerInstance pending(
496 url, true, off_the_record, name, MSG_ROUTING_NONE); 526 url, true, off_the_record, name, MSG_ROUTING_NONE);
497 pending_shared_workers_.push_back(pending); 527 pending_shared_workers_.push_back(pending);
498 return &pending_shared_workers_.back(); 528 return &pending_shared_workers_.back();
499 } 529 }
OLDNEW
« no previous file with comments | « chrome/browser/worker_host/worker_service.h ('k') | chrome/test/data/workers/many_shared_workers.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698