summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/service_worker/service_worker_process_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/service_worker/service_worker_process_manager.cc')
-rw-r--r--chromium/content/browser/service_worker/service_worker_process_manager.cc193
1 files changed, 193 insertions, 0 deletions
diff --git a/chromium/content/browser/service_worker/service_worker_process_manager.cc b/chromium/content/browser/service_worker/service_worker_process_manager.cc
new file mode 100644
index 00000000000..7395e7b7b77
--- /dev/null
+++ b/chromium/content/browser/service_worker/service_worker_process_manager.cc
@@ -0,0 +1,193 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/service_worker/service_worker_process_manager.h"
+
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/site_instance.h"
+#include "url/gurl.h"
+
+namespace content {
+
+static bool IncrementWorkerRefCountByPid(int process_id) {
+ RenderProcessHost* rph = RenderProcessHost::FromID(process_id);
+ if (!rph || rph->FastShutdownStarted())
+ return false;
+
+ static_cast<RenderProcessHostImpl*>(rph)->IncrementWorkerRefCount();
+ return true;
+}
+
+ServiceWorkerProcessManager::ProcessInfo::ProcessInfo(
+ const scoped_refptr<SiteInstance>& site_instance)
+ : site_instance(site_instance),
+ process_id(site_instance->GetProcess()->GetID()) {
+}
+
+ServiceWorkerProcessManager::ProcessInfo::ProcessInfo(int process_id)
+ : process_id(process_id) {
+}
+
+ServiceWorkerProcessManager::ProcessInfo::~ProcessInfo() {
+}
+
+ServiceWorkerProcessManager::ServiceWorkerProcessManager(
+ BrowserContext* browser_context)
+ : browser_context_(browser_context),
+ process_id_for_test_(-1),
+ weak_this_factory_(this),
+ weak_this_(weak_this_factory_.GetWeakPtr()) {
+}
+
+ServiceWorkerProcessManager::~ServiceWorkerProcessManager() {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ DCHECK(browser_context_ == NULL)
+ << "Call Shutdown() before destroying |this|, so that racing method "
+ << "invocations don't use a destroyed BrowserContext.";
+}
+
+void ServiceWorkerProcessManager::Shutdown() {
+ browser_context_ = NULL;
+ for (std::map<int, ProcessInfo>::const_iterator it = instance_info_.begin();
+ it != instance_info_.end();
+ ++it) {
+ RenderProcessHost* rph = RenderProcessHost::FromID(it->second.process_id);
+ DCHECK(rph);
+ static_cast<RenderProcessHostImpl*>(rph)->DecrementWorkerRefCount();
+ }
+ instance_info_.clear();
+}
+
+void ServiceWorkerProcessManager::AllocateWorkerProcess(
+ int embedded_worker_id,
+ const std::vector<int>& process_ids,
+ const GURL& script_url,
+ const base::Callback<void(ServiceWorkerStatusCode, int process_id)>&
+ callback) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ServiceWorkerProcessManager::AllocateWorkerProcess,
+ weak_this_,
+ embedded_worker_id,
+ process_ids,
+ script_url,
+ callback));
+ return;
+ }
+
+ if (process_id_for_test_ != -1) {
+ // Let tests specify the returned process ID. Note: We may need to be able
+ // to specify the error code too.
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_OK, process_id_for_test_));
+ return;
+ }
+
+ DCHECK(!ContainsKey(instance_info_, embedded_worker_id))
+ << embedded_worker_id << " already has a process allocated";
+
+ for (std::vector<int>::const_iterator it = process_ids.begin();
+ it != process_ids.end();
+ ++it) {
+ if (IncrementWorkerRefCountByPid(*it)) {
+ instance_info_.insert(
+ std::make_pair(embedded_worker_id, ProcessInfo(*it)));
+ BrowserThread::PostTask(BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_OK, *it));
+ return;
+ }
+ }
+
+ if (!browser_context_) {
+ // Shutdown has started.
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED, -1));
+ return;
+ }
+ // No existing processes available; start a new one.
+ scoped_refptr<SiteInstance> site_instance =
+ SiteInstance::CreateForURL(browser_context_, script_url);
+ RenderProcessHost* rph = site_instance->GetProcess();
+ // This Init() call posts a task to the IO thread that adds the RPH's
+ // ServiceWorkerDispatcherHost to the
+ // EmbeddedWorkerRegistry::process_sender_map_.
+ if (!rph->Init()) {
+ LOG(ERROR) << "Couldn't start a new process!";
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_ERROR_START_WORKER_FAILED, -1));
+ return;
+ }
+
+ instance_info_.insert(
+ std::make_pair(embedded_worker_id, ProcessInfo(site_instance)));
+
+ static_cast<RenderProcessHostImpl*>(rph)->IncrementWorkerRefCount();
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(callback, SERVICE_WORKER_OK, rph->GetID()));
+}
+
+void ServiceWorkerProcessManager::ReleaseWorkerProcess(int embedded_worker_id) {
+ if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ServiceWorkerProcessManager::ReleaseWorkerProcess,
+ weak_this_,
+ embedded_worker_id));
+ return;
+ }
+ if (process_id_for_test_ != -1) {
+ // Unittests don't increment or decrement the worker refcount of a
+ // RenderProcessHost.
+ return;
+ }
+ if (browser_context_ == NULL) {
+ // Shutdown already released all instances.
+ DCHECK(instance_info_.empty());
+ return;
+ }
+ std::map<int, ProcessInfo>::iterator info =
+ instance_info_.find(embedded_worker_id);
+ DCHECK(info != instance_info_.end());
+ RenderProcessHost* rph = NULL;
+ if (info->second.site_instance) {
+ rph = info->second.site_instance->GetProcess();
+ DCHECK_EQ(info->second.process_id, rph->GetID())
+ << "A SiteInstance's process shouldn't get destroyed while we're "
+ "holding a reference to it. Was the reference actually held?";
+ } else {
+ rph = RenderProcessHost::FromID(info->second.process_id);
+ DCHECK(rph)
+ << "Process " << info->second.process_id
+ << " was destroyed unexpectedly. Did we actually hold a reference?";
+ }
+ static_cast<RenderProcessHostImpl*>(rph)->DecrementWorkerRefCount();
+ instance_info_.erase(info);
+}
+
+} // namespace content
+
+namespace base {
+// Destroying ServiceWorkerProcessManagers only on the UI thread allows the
+// member WeakPtr to safely guard the object's lifetime when used on that
+// thread.
+void DefaultDeleter<content::ServiceWorkerProcessManager>::operator()(
+ content::ServiceWorkerProcessManager* ptr) const {
+ content::BrowserThread::DeleteSoon(
+ content::BrowserThread::UI, FROM_HERE, ptr);
+}
+} // namespace base