Respond with QuotaExceededError when IndexedDB has no disk space on open.
[chromium-blink-merge.git] / content / browser / worker_host / worker_service_impl.cc
blobd2ab272922d9233012e905a6543f2bf23a8fa4ce
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/worker_host/worker_service_impl.h"
7 #include <string>
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "base/threading/thread.h"
12 #include "content/browser/devtools/worker_devtools_manager.h"
13 #include "content/browser/renderer_host/render_widget_host_impl.h"
14 #include "content/browser/worker_host/worker_message_filter.h"
15 #include "content/browser/worker_host/worker_process_host.h"
16 #include "content/common/view_messages.h"
17 #include "content/common/worker_messages.h"
18 #include "content/public/browser/child_process_data.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/browser/notification_types.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/render_widget_host.h"
24 #include "content/public/browser/render_widget_host_iterator.h"
25 #include "content/public/browser/render_widget_host_view.h"
26 #include "content/public/browser/resource_context.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/worker_service_observer.h"
29 #include "content/public/common/content_switches.h"
30 #include "content/public/common/process_type.h"
32 namespace content {
34 const int WorkerServiceImpl::kMaxWorkersWhenSeparate = 64;
35 const int WorkerServiceImpl::kMaxWorkersPerTabWhenSeparate = 16;
37 class WorkerPrioritySetter
38 : public NotificationObserver,
39 public base::RefCountedThreadSafe<WorkerPrioritySetter,
40 BrowserThread::DeleteOnUIThread> {
41 public:
42 WorkerPrioritySetter();
44 // Posts a task to the UI thread to register to receive notifications.
45 void Initialize();
47 // Invoked by WorkerServiceImpl when a worker process is created.
48 void NotifyWorkerProcessCreated();
50 private:
51 friend class base::RefCountedThreadSafe<WorkerPrioritySetter>;
52 friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
53 friend class base::DeleteHelper<WorkerPrioritySetter>;
54 virtual ~WorkerPrioritySetter();
56 // Posts a task to perform a worker priority update.
57 void PostTaskToGatherAndUpdateWorkerPriorities();
59 // Gathers up a list of the visible tabs and then updates priorities for
60 // all the shared workers.
61 void GatherVisibleIDsAndUpdateWorkerPriorities();
63 // Registers as an observer to receive notifications about
64 // widgets being shown.
65 void RegisterObserver();
67 // Sets priorities for shared workers given a set of visible tabs (as a
68 // std::set of std::pair<render_process, render_view> ids.
69 void UpdateWorkerPrioritiesFromVisibleSet(
70 const std::set<std::pair<int, int> >* visible);
72 // Called to refresh worker priorities when focus changes between tabs.
73 void OnRenderWidgetVisibilityChanged(std::pair<int, int>);
75 // NotificationObserver implementation.
76 virtual void Observe(int type,
77 const NotificationSource& source,
78 const NotificationDetails& details) OVERRIDE;
80 NotificationRegistrar registrar_;
83 WorkerPrioritySetter::WorkerPrioritySetter() {
86 WorkerPrioritySetter::~WorkerPrioritySetter() {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90 void WorkerPrioritySetter::Initialize() {
91 BrowserThread::PostTask(
92 BrowserThread::UI, FROM_HERE,
93 base::Bind(&WorkerPrioritySetter::RegisterObserver, this));
96 void WorkerPrioritySetter::NotifyWorkerProcessCreated() {
97 PostTaskToGatherAndUpdateWorkerPriorities();
100 void WorkerPrioritySetter::PostTaskToGatherAndUpdateWorkerPriorities() {
101 BrowserThread::PostTask(
102 BrowserThread::UI, FROM_HERE,
103 base::Bind(
104 &WorkerPrioritySetter::GatherVisibleIDsAndUpdateWorkerPriorities,
105 this));
108 void WorkerPrioritySetter::GatherVisibleIDsAndUpdateWorkerPriorities() {
109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
110 std::set<std::pair<int, int> >* visible_renderer_ids =
111 new std::set<std::pair<int, int> >();
113 // Gather up all the visible renderer process/view pairs
114 scoped_ptr<RenderWidgetHostIterator> widgets(
115 RenderWidgetHost::GetRenderWidgetHosts());
116 while (RenderWidgetHost* widget = widgets->GetNextHost()) {
117 if (widget->GetProcess()->VisibleWidgetCount() == 0)
118 continue;
120 RenderWidgetHostView* render_view = widget->GetView();
121 if (render_view && render_view->IsShowing()) {
122 visible_renderer_ids->insert(
123 std::pair<int, int>(widget->GetProcess()->GetID(),
124 widget->GetRoutingID()));
128 BrowserThread::PostTask(
129 BrowserThread::IO, FROM_HERE,
130 base::Bind(&WorkerPrioritySetter::UpdateWorkerPrioritiesFromVisibleSet,
131 this, base::Owned(visible_renderer_ids)));
134 void WorkerPrioritySetter::UpdateWorkerPrioritiesFromVisibleSet(
135 const std::set<std::pair<int, int> >* visible_renderer_ids) {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
138 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
139 if (!iter->process_launched())
140 continue;
141 bool throttle = true;
143 for (WorkerProcessHost::Instances::const_iterator instance =
144 iter->instances().begin(); instance != iter->instances().end();
145 ++instance) {
147 // This code assumes one worker per process
148 WorkerProcessHost::Instances::const_iterator first_instance =
149 iter->instances().begin();
150 if (first_instance == iter->instances().end())
151 continue;
153 WorkerDocumentSet::DocumentInfoSet::const_iterator info =
154 first_instance->worker_document_set()->documents().begin();
156 for (; info != first_instance->worker_document_set()->documents().end();
157 ++info) {
158 std::pair<int, int> id(
159 info->render_process_id(), info->render_view_id());
160 if (visible_renderer_ids->find(id) != visible_renderer_ids->end()) {
161 throttle = false;
162 break;
166 if (!throttle ) {
167 break;
171 iter->SetBackgrounded(throttle);
175 void WorkerPrioritySetter::OnRenderWidgetVisibilityChanged(
176 std::pair<int, int> id) {
177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
178 std::set<std::pair<int, int> > visible_renderer_ids;
180 visible_renderer_ids.insert(id);
182 UpdateWorkerPrioritiesFromVisibleSet(&visible_renderer_ids);
185 void WorkerPrioritySetter::RegisterObserver() {
186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
187 registrar_.Add(this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
188 NotificationService::AllBrowserContextsAndSources());
189 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CREATED,
190 NotificationService::AllBrowserContextsAndSources());
193 void WorkerPrioritySetter::Observe(int type,
194 const NotificationSource& source, const NotificationDetails& details) {
195 if (type == NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED) {
196 bool visible = *Details<bool>(details).ptr();
198 if (visible) {
199 int render_widget_id =
200 Source<RenderWidgetHost>(source).ptr()->GetRoutingID();
201 int render_process_pid =
202 Source<RenderWidgetHost>(source).ptr()->GetProcess()->GetID();
204 BrowserThread::PostTask(
205 BrowserThread::IO, FROM_HERE,
206 base::Bind(&WorkerPrioritySetter::OnRenderWidgetVisibilityChanged,
207 this, std::pair<int, int>(render_process_pid, render_widget_id)));
210 else if (type == NOTIFICATION_RENDERER_PROCESS_CREATED) {
211 PostTaskToGatherAndUpdateWorkerPriorities();
215 WorkerService* WorkerService::GetInstance() {
216 return WorkerServiceImpl::GetInstance();
219 WorkerServiceImpl* WorkerServiceImpl::GetInstance() {
220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
221 return Singleton<WorkerServiceImpl>::get();
224 WorkerServiceImpl::WorkerServiceImpl()
225 : priority_setter_(new WorkerPrioritySetter()),
226 next_worker_route_id_(0) {
227 priority_setter_->Initialize();
230 WorkerServiceImpl::~WorkerServiceImpl() {
231 // The observers in observers_ can't be used here because they might be
232 // gone already.
235 void WorkerServiceImpl::PerformTeardownForTesting() {
236 priority_setter_ = NULL;
239 void WorkerServiceImpl::OnWorkerMessageFilterClosing(
240 WorkerMessageFilter* filter) {
241 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
242 iter->FilterShutdown(filter);
245 // See if that process had any queued workers.
246 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
247 i != queued_workers_.end();) {
248 i->RemoveFilters(filter);
249 if (i->NumFilters() == 0) {
250 i = queued_workers_.erase(i);
251 } else {
252 ++i;
256 for (WorkerProcessHost::Instances::iterator i =
257 pending_shared_workers_.begin();
258 i != pending_shared_workers_.end(); ) {
259 i->RemoveFilters(filter);
260 if (i->NumFilters() == 0) {
261 i = pending_shared_workers_.erase(i);
262 } else {
263 ++i;
267 // Also, see if that process had any pending shared workers.
268 for (WorkerProcessHost::Instances::iterator iter =
269 pending_shared_workers_.begin();
270 iter != pending_shared_workers_.end(); ) {
271 iter->worker_document_set()->RemoveAll(filter);
272 if (iter->worker_document_set()->IsEmpty()) {
273 iter = pending_shared_workers_.erase(iter);
274 } else {
275 ++iter;
279 // Either a worker proceess has shut down, in which case we can start one of
280 // the queued workers, or a renderer has shut down, in which case it doesn't
281 // affect anything. We call this function in both scenarios because then we
282 // don't have to keep track which filters are from worker processes.
283 TryStartingQueuedWorker();
286 void WorkerServiceImpl::CreateWorker(
287 const ViewHostMsg_CreateWorker_Params& params,
288 int route_id,
289 WorkerMessageFilter* filter,
290 ResourceContext* resource_context,
291 const WorkerStoragePartition& partition) {
292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
293 // Generate a unique route id for the browser-worker communication that's
294 // unique among all worker processes. That way when the worker process sends
295 // a wrapped IPC message through us, we know which WorkerProcessHost to give
296 // it to.
297 WorkerProcessHost::WorkerInstance instance(
298 params.url,
299 params.name,
300 next_worker_route_id(),
302 params.script_resource_appcache_id,
303 resource_context,
304 partition);
305 instance.AddFilter(filter, route_id);
306 instance.worker_document_set()->Add(
307 filter, params.document_id, filter->render_process_id(),
308 params.render_view_route_id);
310 CreateWorkerFromInstance(instance);
313 void WorkerServiceImpl::LookupSharedWorker(
314 const ViewHostMsg_CreateWorker_Params& params,
315 int route_id,
316 WorkerMessageFilter* filter,
317 ResourceContext* resource_context,
318 const WorkerStoragePartition& partition,
319 bool* exists,
320 bool* url_mismatch) {
321 *exists = true;
322 WorkerProcessHost::WorkerInstance* instance = FindSharedWorkerInstance(
323 params.url, params.name, partition, resource_context);
325 if (!instance) {
326 // If no worker instance currently exists, we need to create a pending
327 // instance - this is to make sure that any subsequent lookups passing a
328 // mismatched URL get the appropriate url_mismatch error at lookup time.
329 // Having named shared workers was a Really Bad Idea due to details like
330 // this.
331 instance = CreatePendingInstance(params.url, params.name,
332 resource_context, partition);
333 *exists = false;
336 // Make sure the passed-in instance matches the URL - if not, return an
337 // error.
338 if (params.url != instance->url()) {
339 *url_mismatch = true;
340 *exists = false;
341 } else {
342 *url_mismatch = false;
343 // Add our route ID to the existing instance so we can send messages to it.
344 instance->AddFilter(filter, route_id);
346 // Add the passed filter/document_id to the worker instance.
347 // TODO(atwilson): This won't work if the message is from a worker process.
348 // We don't support that yet though (this message is only sent from
349 // renderers) but when we do, we'll need to add code to pass in the current
350 // worker's document set for nested workers.
351 instance->worker_document_set()->Add(
352 filter, params.document_id, filter->render_process_id(),
353 params.render_view_route_id);
357 void WorkerServiceImpl::ForwardToWorker(const IPC::Message& message,
358 WorkerMessageFilter* filter) {
359 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
360 if (iter->FilterMessage(message, filter))
361 return;
364 // TODO(jabdelmalek): tell filter that callee is gone
367 void WorkerServiceImpl::DocumentDetached(unsigned long long document_id,
368 WorkerMessageFilter* filter) {
369 // Any associated shared workers can be shut down.
370 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter)
371 iter->DocumentDetached(filter, document_id);
373 // Remove any queued shared workers for this document.
374 for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
375 iter != queued_workers_.end();) {
377 iter->worker_document_set()->Remove(filter, document_id);
378 if (iter->worker_document_set()->IsEmpty()) {
379 iter = queued_workers_.erase(iter);
380 continue;
382 ++iter;
385 // Remove the document from any pending shared workers.
386 for (WorkerProcessHost::Instances::iterator iter =
387 pending_shared_workers_.begin();
388 iter != pending_shared_workers_.end(); ) {
389 iter->worker_document_set()->Remove(filter, document_id);
390 if (iter->worker_document_set()->IsEmpty()) {
391 iter = pending_shared_workers_.erase(iter);
392 } else {
393 ++iter;
398 bool WorkerServiceImpl::CreateWorkerFromInstance(
399 WorkerProcessHost::WorkerInstance instance) {
400 if (!CanCreateWorkerProcess(instance)) {
401 queued_workers_.push_back(instance);
402 return true;
405 // Check to see if this shared worker is already running (two pages may have
406 // tried to start up the worker simultaneously).
407 // See if a worker with this name already exists.
408 WorkerProcessHost::WorkerInstance* existing_instance =
409 FindSharedWorkerInstance(
410 instance.url(), instance.name(), instance.partition(),
411 instance.resource_context());
412 WorkerProcessHost::WorkerInstance::FilterInfo filter_info =
413 instance.GetFilter();
414 // If this worker is already running, no need to create a new copy. Just
415 // inform the caller that the worker has been created.
416 if (existing_instance) {
417 // Walk the worker's filter list to see if this client is listed. If not,
418 // then it means that the worker started by the client already exited so
419 // we should not attach to this new one (http://crbug.com/29243).
420 if (!existing_instance->HasFilter(filter_info.first, filter_info.second))
421 return false;
422 filter_info.first->Send(new ViewMsg_WorkerCreated(filter_info.second));
423 return true;
426 // Look to see if there's a pending instance.
427 WorkerProcessHost::WorkerInstance* pending = FindPendingInstance(
428 instance.url(), instance.name(), instance.partition(),
429 instance.resource_context());
430 // If there's no instance *and* no pending instance (or there is a pending
431 // instance but it does not contain our filter info), then it means the
432 // worker started up and exited already. Log a warning because this should
433 // be a very rare occurrence and is probably a bug, but it *can* happen so
434 // handle it gracefully.
435 if (!pending ||
436 !pending->HasFilter(filter_info.first, filter_info.second)) {
437 DLOG(WARNING) << "Pending worker already exited";
438 return false;
441 // Assign the accumulated document set and filter list for this pending
442 // worker to the new instance.
443 DCHECK(!pending->worker_document_set()->IsEmpty());
444 instance.ShareDocumentSet(*pending);
445 for (WorkerProcessHost::WorkerInstance::FilterList::const_iterator i =
446 pending->filters().begin();
447 i != pending->filters().end(); ++i) {
448 instance.AddFilter(i->first, i->second);
450 RemovePendingInstances(instance.url(), instance.name(),
451 instance.partition(), instance.resource_context());
453 // Remove any queued instances of this worker and copy over the filter to
454 // this instance.
455 for (WorkerProcessHost::Instances::iterator iter = queued_workers_.begin();
456 iter != queued_workers_.end();) {
457 if (iter->Matches(instance.url(), instance.name(),
458 instance.partition(), instance.resource_context())) {
459 DCHECK(iter->NumFilters() == 1);
460 WorkerProcessHost::WorkerInstance::FilterInfo filter_info =
461 iter->GetFilter();
462 instance.AddFilter(filter_info.first, filter_info.second);
463 iter = queued_workers_.erase(iter);
464 } else {
465 ++iter;
469 WorkerMessageFilter* first_filter = instance.filters().begin()->first;
470 WorkerProcessHost* worker = new WorkerProcessHost(
471 instance.resource_context(), instance.partition());
472 // TODO(atwilson): This won't work if the message is from a worker process.
473 // We don't support that yet though (this message is only sent from
474 // renderers) but when we do, we'll need to add code to pass in the current
475 // worker's document set for nested workers.
476 if (!worker->Init(first_filter->render_process_id())) {
477 delete worker;
478 return false;
481 worker->CreateWorker(instance);
482 FOR_EACH_OBSERVER(
483 WorkerServiceObserver, observers_,
484 WorkerCreated(instance.url(), instance.name(), worker->GetData().id,
485 instance.worker_route_id()));
486 WorkerDevToolsManager::GetInstance()->WorkerCreated(worker, instance);
487 return true;
490 bool WorkerServiceImpl::CanCreateWorkerProcess(
491 const WorkerProcessHost::WorkerInstance& instance) {
492 // Worker can be fired off if *any* parent has room.
493 const WorkerDocumentSet::DocumentInfoSet& parents =
494 instance.worker_document_set()->documents();
496 for (WorkerDocumentSet::DocumentInfoSet::const_iterator parent_iter =
497 parents.begin();
498 parent_iter != parents.end(); ++parent_iter) {
499 bool hit_total_worker_limit = false;
500 if (TabCanCreateWorkerProcess(parent_iter->render_process_id(),
501 parent_iter->render_view_id(),
502 &hit_total_worker_limit)) {
503 return true;
505 // Return false if already at the global worker limit (no need to continue
506 // checking parent tabs).
507 if (hit_total_worker_limit)
508 return false;
510 // If we've reached here, none of the parent tabs is allowed to create an
511 // instance.
512 return false;
515 bool WorkerServiceImpl::TabCanCreateWorkerProcess(
516 int render_process_id,
517 int render_view_id,
518 bool* hit_total_worker_limit) {
519 int total_workers = 0;
520 int workers_per_tab = 0;
521 *hit_total_worker_limit = false;
522 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
523 for (WorkerProcessHost::Instances::const_iterator cur_instance =
524 iter->instances().begin();
525 cur_instance != iter->instances().end(); ++cur_instance) {
526 total_workers++;
527 if (total_workers >= kMaxWorkersWhenSeparate) {
528 *hit_total_worker_limit = true;
529 return false;
531 if (cur_instance->RendererIsParent(render_process_id, render_view_id)) {
532 workers_per_tab++;
533 if (workers_per_tab >= kMaxWorkersPerTabWhenSeparate)
534 return false;
539 return true;
542 void WorkerServiceImpl::TryStartingQueuedWorker() {
543 if (queued_workers_.empty())
544 return;
546 for (WorkerProcessHost::Instances::iterator i = queued_workers_.begin();
547 i != queued_workers_.end();) {
548 if (CanCreateWorkerProcess(*i)) {
549 WorkerProcessHost::WorkerInstance instance = *i;
550 queued_workers_.erase(i);
551 CreateWorkerFromInstance(instance);
553 // CreateWorkerFromInstance can modify the queued_workers_ list when it
554 // coalesces queued instances after starting a shared worker, so we
555 // have to rescan the list from the beginning (our iterator is now
556 // invalid). This is not a big deal as having any queued workers will be
557 // rare in practice so the list will be small.
558 i = queued_workers_.begin();
559 } else {
560 ++i;
565 bool WorkerServiceImpl::GetRendererForWorker(int worker_process_id,
566 int* render_process_id,
567 int* render_view_id) const {
568 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
569 if (iter.GetData().id != worker_process_id)
570 continue;
572 // This code assumes one worker per process, see function comment in header!
573 WorkerProcessHost::Instances::const_iterator first_instance =
574 iter->instances().begin();
575 if (first_instance == iter->instances().end())
576 return false;
578 WorkerDocumentSet::DocumentInfoSet::const_iterator info =
579 first_instance->worker_document_set()->documents().begin();
580 *render_process_id = info->render_process_id();
581 *render_view_id = info->render_view_id();
582 return true;
584 return false;
587 const WorkerProcessHost::WorkerInstance* WorkerServiceImpl::FindWorkerInstance(
588 int worker_process_id) {
589 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
590 if (iter.GetData().id != worker_process_id)
591 continue;
593 WorkerProcessHost::Instances::const_iterator instance =
594 iter->instances().begin();
595 return instance == iter->instances().end() ? NULL : &*instance;
597 return NULL;
600 bool WorkerServiceImpl::TerminateWorker(int process_id, int route_id) {
601 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
602 if (iter.GetData().id == process_id) {
603 iter->TerminateWorker(route_id);
604 return true;
607 return false;
610 std::vector<WorkerService::WorkerInfo> WorkerServiceImpl::GetWorkers() {
611 std::vector<WorkerService::WorkerInfo> results;
612 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
613 const WorkerProcessHost::Instances& instances = (*iter)->instances();
614 for (WorkerProcessHost::Instances::const_iterator i = instances.begin();
615 i != instances.end(); ++i) {
616 WorkerService::WorkerInfo info;
617 info.url = i->url();
618 info.name = i->name();
619 info.route_id = i->worker_route_id();
620 info.process_id = iter.GetData().id;
621 info.handle = iter.GetData().handle;
622 results.push_back(info);
625 return results;
628 void WorkerServiceImpl::AddObserver(WorkerServiceObserver* observer) {
629 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
630 observers_.AddObserver(observer);
633 void WorkerServiceImpl::RemoveObserver(WorkerServiceObserver* observer) {
634 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
635 observers_.RemoveObserver(observer);
638 void WorkerServiceImpl::NotifyWorkerDestroyed(
639 WorkerProcessHost* process,
640 int worker_route_id) {
641 WorkerDevToolsManager::GetInstance()->WorkerDestroyed(
642 process, worker_route_id);
643 FOR_EACH_OBSERVER(WorkerServiceObserver, observers_,
644 WorkerDestroyed(process->GetData().id, worker_route_id));
647 void WorkerServiceImpl::NotifyWorkerProcessCreated() {
648 priority_setter_->NotifyWorkerProcessCreated();
651 WorkerProcessHost::WorkerInstance* WorkerServiceImpl::FindSharedWorkerInstance(
652 const GURL& url,
653 const string16& name,
654 const WorkerStoragePartition& partition,
655 ResourceContext* resource_context) {
656 for (WorkerProcessHostIterator iter; !iter.Done(); ++iter) {
657 for (WorkerProcessHost::Instances::iterator instance_iter =
658 iter->mutable_instances().begin();
659 instance_iter != iter->mutable_instances().end();
660 ++instance_iter) {
661 if (instance_iter->Matches(url, name, partition, resource_context))
662 return &(*instance_iter);
665 return NULL;
668 WorkerProcessHost::WorkerInstance* WorkerServiceImpl::FindPendingInstance(
669 const GURL& url,
670 const string16& name,
671 const WorkerStoragePartition& partition,
672 ResourceContext* resource_context) {
673 // Walk the pending instances looking for a matching pending worker.
674 for (WorkerProcessHost::Instances::iterator iter =
675 pending_shared_workers_.begin();
676 iter != pending_shared_workers_.end();
677 ++iter) {
678 if (iter->Matches(url, name, partition, resource_context))
679 return &(*iter);
681 return NULL;
685 void WorkerServiceImpl::RemovePendingInstances(
686 const GURL& url,
687 const string16& name,
688 const WorkerStoragePartition& partition,
689 ResourceContext* resource_context) {
690 // Walk the pending instances looking for a matching pending worker.
691 for (WorkerProcessHost::Instances::iterator iter =
692 pending_shared_workers_.begin();
693 iter != pending_shared_workers_.end(); ) {
694 if (iter->Matches(url, name, partition, resource_context)) {
695 iter = pending_shared_workers_.erase(iter);
696 } else {
697 ++iter;
702 WorkerProcessHost::WorkerInstance* WorkerServiceImpl::CreatePendingInstance(
703 const GURL& url,
704 const string16& name,
705 ResourceContext* resource_context,
706 const WorkerStoragePartition& partition) {
707 // Look for an existing pending shared worker.
708 WorkerProcessHost::WorkerInstance* instance =
709 FindPendingInstance(url, name, partition, resource_context);
710 if (instance)
711 return instance;
713 // No existing pending worker - create a new one.
714 WorkerProcessHost::WorkerInstance pending(
715 url, true, name, resource_context, partition);
716 pending_shared_workers_.push_back(pending);
717 return &pending_shared_workers_.back();
720 } // namespace content