summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-11 06:05:34 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-11 06:05:34 +0000
commit91239db318e4e637e0f1f325552ceedfcaf995cc (patch)
tree4dcaf7ccfd8f40a18e3cece62f6feb598d8a6dbc /content
parent6f865c86e6d88d0a955f4c261b8cdf5914643ecc (diff)
downloadchromium_src-91239db318e4e637e0f1f325552ceedfcaf995cc.zip
chromium_src-91239db318e4e637e0f1f325552ceedfcaf995cc.tar.gz
chromium_src-91239db318e4e637e0f1f325552ceedfcaf995cc.tar.bz2
EmbeddedWorker, browser side code
Adding two new classes, EmbeddedWorkerRegistry and EmbeddedWorkerInstance. Technically they can be implemented within ServiceWorkerContextCore and ServiceWorkerVersion, but here I wrote them in separate classes for logical separation. * EmbeddedWorkerRegistry -- Hangs off the ServiceWorkerContextCore -- Acts as a stub between MessageFilter and each EmbeddedWorkerInstance -- Sends/receives messages to/from each EmbeddedWorker in child process -- Mostly talks only with MessageFilter and EmbeddedWorkerInstance * EmbeddedWorkerInstance -- ServiceWorkerVersion will own it (1:1 relation) -- Provides an interface to interact (Start/Stop/Execute) with an EmbeddedWorker BUG=313530 TBR=jochen Review URL: https://codereview.chromium.org/85023003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240030 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/service_worker/embedded_worker_instance.cc99
-rw-r--r--content/browser/service_worker/embedded_worker_instance.h102
-rw-r--r--content/browser/service_worker/embedded_worker_instance_unittest.cc137
-rw-r--r--content/browser/service_worker/embedded_worker_registry.cc70
-rw-r--r--content/browser/service_worker/embedded_worker_registry.h77
-rw-r--r--content/browser/service_worker/service_worker_context_core.cc4
-rw-r--r--content/browser/service_worker/service_worker_context_core.h10
-rw-r--r--content/browser/service_worker/service_worker_dispatcher_host.cc8
-rw-r--r--content/browser/service_worker/service_worker_registration_unittest.cc11
-rw-r--r--content/browser/service_worker/service_worker_version.cc38
-rw-r--r--content/browser/service_worker/service_worker_version.h29
-rw-r--r--content/content_browser.gypi4
-rw-r--r--content/content_tests.gypi5
13 files changed, 580 insertions, 14 deletions
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
new file mode 100644
index 0000000..0799884
--- /dev/null
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -0,0 +1,99 @@
+// Copyright 2013 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/embedded_worker_instance.h"
+
+#include "content/browser/service_worker/embedded_worker_registry.h"
+#include "url/gurl.h"
+
+namespace content {
+
+EmbeddedWorkerInstance::~EmbeddedWorkerInstance() {
+ registry_->RemoveWorker(embedded_worker_id_);
+}
+
+bool EmbeddedWorkerInstance::Start(
+ int64 service_worker_version_id,
+ const GURL& script_url) {
+ DCHECK(status_ == STOPPED);
+ if (!ChooseProcess())
+ return false;
+ status_ = STARTING;
+ bool success = registry_->StartWorker(
+ process_id_,
+ embedded_worker_id_,
+ service_worker_version_id,
+ script_url);
+ if (!success) {
+ status_ = STOPPED;
+ process_id_ = -1;
+ }
+ return success;
+}
+
+bool EmbeddedWorkerInstance::Stop() {
+ DCHECK(status_ == STARTING || status_ == RUNNING);
+ const bool success = registry_->StopWorker(process_id_, embedded_worker_id_);
+ if (success)
+ status_ = STOPPING;
+ return success;
+}
+
+void EmbeddedWorkerInstance::AddProcessReference(int process_id) {
+ ProcessRefMap::iterator found = process_refs_.find(process_id);
+ if (found == process_refs_.end())
+ found = process_refs_.insert(std::make_pair(process_id, 0)).first;
+ ++found->second;
+}
+
+void EmbeddedWorkerInstance::ReleaseProcessReference(int process_id) {
+ ProcessRefMap::iterator found = process_refs_.find(process_id);
+ if (found == process_refs_.end()) {
+ NOTREACHED() << "Releasing unknown process ref " << process_id;
+ return;
+ }
+ if (--found->second == 0)
+ process_refs_.erase(found);
+}
+
+EmbeddedWorkerInstance::EmbeddedWorkerInstance(
+ EmbeddedWorkerRegistry* registry,
+ int embedded_worker_id)
+ : registry_(registry),
+ embedded_worker_id_(embedded_worker_id),
+ status_(STOPPED),
+ process_id_(-1),
+ thread_id_(-1) {
+}
+
+void EmbeddedWorkerInstance::OnStarted(int thread_id) {
+ DCHECK(status_ == STARTING);
+ status_ = RUNNING;
+ thread_id_ = thread_id;
+}
+
+void EmbeddedWorkerInstance::OnStopped() {
+ status_ = STOPPED;
+ process_id_ = -1;
+ thread_id_ = -1;
+}
+
+bool EmbeddedWorkerInstance::ChooseProcess() {
+ DCHECK_EQ(-1, process_id_);
+ // Naive implementation; chooses a process which has the biggest number of
+ // associated providers (so that hopefully likely live longer).
+ ProcessRefMap::iterator max_ref_iter = process_refs_.end();
+ for (ProcessRefMap::iterator iter = process_refs_.begin();
+ iter != process_refs_.end(); ++iter) {
+ if (max_ref_iter == process_refs_.end() ||
+ max_ref_iter->second < iter->second)
+ max_ref_iter = iter;
+ }
+ if (max_ref_iter == process_refs_.end())
+ return false;
+ process_id_ = max_ref_iter->first;
+ return true;
+}
+
+} // namespace content
diff --git a/content/browser/service_worker/embedded_worker_instance.h b/content/browser/service_worker/embedded_worker_instance.h
new file mode 100644
index 0000000..fb0fe19
--- /dev/null
+++ b/content/browser/service_worker/embedded_worker_instance.h
@@ -0,0 +1,102 @@
+// Copyright 2013 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.
+
+#ifndef CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_INSTANCE_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_INSTANCE_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+
+class GURL;
+
+namespace content {
+
+class EmbeddedWorkerRegistry;
+
+// This gives an interface to control one EmbeddedWorker instance, which
+// may be 'in-waiting' or running in one of the child processes added by
+// AddProcessReference().
+class CONTENT_EXPORT EmbeddedWorkerInstance {
+ public:
+ enum Status {
+ STOPPED,
+ STARTING,
+ RUNNING,
+ STOPPING,
+ };
+
+ ~EmbeddedWorkerInstance();
+
+ // Starts the worker. It is invalid to call this when the worker is
+ // not in STOPPED status.
+ // This returns false if starting a worker fails immediately, e.g. when
+ // IPC couldn't be sent to the worker or no process was available.
+ bool Start(int64 service_worker_version_id,
+ const GURL& script_url);
+
+ // Stops the worker. It is invalid to call this when the worker is
+ // not in STARTING or RUNNING status.
+ // This returns false if stopping a worker fails immediately, e.g. when
+ // IPC couldn't be sent to the worker.
+ bool Stop();
+
+ // Add or remove |process_id| to the internal process set where this
+ // worker can be started.
+ void AddProcessReference(int process_id);
+ void ReleaseProcessReference(int process_id);
+
+ int embedded_worker_id() const { return embedded_worker_id_; }
+ Status status() const { return status_; }
+ int process_id() const { return process_id_; }
+ int thread_id() const { return thread_id_; }
+
+ private:
+ friend class EmbeddedWorkerRegistry;
+ FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerInstanceTest, StartAndStop);
+
+ typedef std::map<int, int> ProcessRefMap;
+
+ // Constructor is called via EmbeddedWorkerRegistry::CreateWorker().
+ // This instance holds a ref of |registry|.
+ EmbeddedWorkerInstance(EmbeddedWorkerRegistry* registry,
+ int embedded_worker_id);
+
+ // Called back from Registry when the worker instance has ack'ed that
+ // its WorkerGlobalScope is actually started on |thread_id| in the
+ // child process.
+ // This will change the internal status from STARTING to RUNNING.
+ void OnStarted(int thread_id);
+
+ // Called back from Registry when the worker instance has ack'ed that
+ // its WorkerGlobalScope is actually stopped in the child process.
+ // This will change the internal status from STARTING or RUNNING to
+ // STOPPED.
+ void OnStopped();
+
+ // Chooses a process to start this worker and populate process_id_.
+ // Returns false when no process is available.
+ bool ChooseProcess();
+
+ scoped_refptr<EmbeddedWorkerRegistry> registry_;
+ const int embedded_worker_id_;
+ Status status_;
+
+ // Current running information. -1 indicates the worker is not running.
+ int process_id_;
+ int thread_id_;
+
+ ProcessRefMap process_refs_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstance);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_INSTANCE_H_
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
new file mode 100644
index 0000000..45b2f29
--- /dev/null
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -0,0 +1,137 @@
+// Copyright 2013 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 "base/basictypes.h"
+#include "base/stl_util.h"
+#include "content/browser/service_worker/embedded_worker_instance.h"
+#include "content/browser/service_worker/embedded_worker_registry.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/common/service_worker_messages.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_sender.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+typedef std::vector<IPC::Message*> MessageList;
+
+class FakeSender : public IPC::Sender {
+ public:
+ FakeSender() {}
+ virtual ~FakeSender() {
+ STLDeleteContainerPointers(sent_messages_.begin(), sent_messages_.end());
+ }
+
+ // IPC::Sender implementation.
+ virtual bool Send(IPC::Message* message) OVERRIDE {
+ sent_messages_.push_back(message);
+ return true;
+ }
+
+ const MessageList& sent_messages() { return sent_messages_; }
+
+ private:
+ MessageList sent_messages_;
+ DISALLOW_COPY_AND_ASSIGN(FakeSender);
+};
+
+} // namespace
+
+class EmbeddedWorkerInstanceTest : public testing::Test {
+ protected:
+ EmbeddedWorkerInstanceTest()
+ : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
+
+ virtual void SetUp() OVERRIDE {
+ context_.reset(new ServiceWorkerContextCore(base::FilePath(), NULL));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ context_.reset();
+ }
+
+ EmbeddedWorkerRegistry* embedded_worker_registry() {
+ DCHECK(context_);
+ return context_->embedded_worker_registry();
+ }
+
+ TestBrowserThreadBundle thread_bundle_;
+ scoped_ptr<ServiceWorkerContextCore> context_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerInstanceTest);
+};
+
+TEST_F(EmbeddedWorkerInstanceTest, StartAndStop) {
+ scoped_ptr<EmbeddedWorkerInstance> worker =
+ embedded_worker_registry()->CreateWorker();
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+
+ FakeSender fake_sender;
+ const int process_id = 11;
+ const int thread_id = 33;
+ const int64 service_worker_version_id = 55L;
+ const GURL url("http://example.com/worker.js");
+
+ // This fails as we have no available process yet.
+ EXPECT_FALSE(worker->Start(service_worker_version_id, url));
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+
+ // Simulate adding one process to the worker.
+ worker->AddProcessReference(process_id);
+ embedded_worker_registry()->AddChildProcessSender(process_id, &fake_sender);
+
+ // Start should succeed.
+ EXPECT_TRUE(worker->Start(service_worker_version_id, url));
+ EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
+
+ // Simulate an upcall from embedded worker to notify that it's started.
+ worker->OnStarted(thread_id);
+ EXPECT_EQ(EmbeddedWorkerInstance::RUNNING, worker->status());
+ EXPECT_EQ(process_id, worker->process_id());
+ EXPECT_EQ(thread_id, worker->thread_id());
+
+ // Stop the worker.
+ EXPECT_TRUE(worker->Stop());
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPING, worker->status());
+
+ // Simulate an upcall from embedded worker to notify that it's stopped.
+ worker->OnStopped();
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+
+ // Verify that we've sent two messages to start and terminate the worker.
+ const MessageList& messages = fake_sender.sent_messages();
+ ASSERT_EQ(2U, messages.size());
+ ASSERT_EQ(ServiceWorkerMsg_StartWorker::ID, messages[0]->type());
+ ASSERT_EQ(ServiceWorkerMsg_TerminateWorker::ID, messages[1]->type());
+}
+
+TEST_F(EmbeddedWorkerInstanceTest, ChooseProcess) {
+ scoped_ptr<EmbeddedWorkerInstance> worker =
+ embedded_worker_registry()->CreateWorker();
+ EXPECT_EQ(EmbeddedWorkerInstance::STOPPED, worker->status());
+
+ FakeSender fake_sender;
+
+ // Simulate adding processes to the worker.
+ // Process 1 has 1 ref, 2 has 2 refs and 3 has 3 refs.
+ worker->AddProcessReference(1);
+ worker->AddProcessReference(2);
+ worker->AddProcessReference(2);
+ worker->AddProcessReference(3);
+ worker->AddProcessReference(3);
+ worker->AddProcessReference(3);
+ embedded_worker_registry()->AddChildProcessSender(1, &fake_sender);
+ embedded_worker_registry()->AddChildProcessSender(2, &fake_sender);
+ embedded_worker_registry()->AddChildProcessSender(3, &fake_sender);
+
+ // Process 3 has the biggest # of references and it should be chosen.
+ EXPECT_TRUE(worker->Start(1L, GURL("http://example.com/worker.js")));
+ EXPECT_EQ(EmbeddedWorkerInstance::STARTING, worker->status());
+ EXPECT_EQ(3, worker->process_id());
+}
+
+} // namespace content
diff --git a/content/browser/service_worker/embedded_worker_registry.cc b/content/browser/service_worker/embedded_worker_registry.cc
new file mode 100644
index 0000000..f8f0fbe
--- /dev/null
+++ b/content/browser/service_worker/embedded_worker_registry.cc
@@ -0,0 +1,70 @@
+// Copyright 2013 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/embedded_worker_registry.h"
+
+#include "base/stl_util.h"
+#include "content/browser/service_worker/embedded_worker_instance.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
+#include "content/common/service_worker_messages.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_sender.h"
+
+namespace content {
+
+EmbeddedWorkerRegistry::EmbeddedWorkerRegistry(
+ base::WeakPtr<ServiceWorkerContextCore> context)
+ : context_(context),
+ next_embedded_worker_id_(0) {}
+
+scoped_ptr<EmbeddedWorkerInstance> EmbeddedWorkerRegistry::CreateWorker() {
+ scoped_ptr<EmbeddedWorkerInstance> worker(
+ new EmbeddedWorkerInstance(this, next_embedded_worker_id_));
+ worker_map_[next_embedded_worker_id_++] = worker.get();
+ return worker.Pass();
+}
+
+void EmbeddedWorkerRegistry::RemoveWorker(int embedded_worker_id) {
+ DCHECK(ContainsKey(worker_map_, embedded_worker_id));
+ worker_map_.erase(embedded_worker_id);
+}
+
+bool EmbeddedWorkerRegistry::StartWorker(
+ int process_id,
+ int embedded_worker_id,
+ int64 service_worker_version_id,
+ const GURL& script_url) {
+ return Send(process_id,
+ new ServiceWorkerMsg_StartWorker(embedded_worker_id,
+ service_worker_version_id,
+ script_url));
+}
+
+bool EmbeddedWorkerRegistry::StopWorker(int process_id,
+ int embedded_worker_id) {
+ return Send(process_id,
+ new ServiceWorkerMsg_TerminateWorker(embedded_worker_id));
+}
+
+void EmbeddedWorkerRegistry::AddChildProcessSender(
+ int process_id, IPC::Sender* sender) {
+ process_sender_map_[process_id] = sender;
+}
+
+void EmbeddedWorkerRegistry::RemoveChildProcessSender(int process_id) {
+ process_sender_map_.erase(process_id);
+}
+
+EmbeddedWorkerRegistry::~EmbeddedWorkerRegistry() {}
+
+bool EmbeddedWorkerRegistry::Send(int process_id, IPC::Message* message) {
+ if (!context_)
+ return false;
+ ProcessToSenderMap::iterator found = process_sender_map_.find(process_id);
+ if (found == process_sender_map_.end())
+ return false;
+ return found->second->Send(message);
+}
+
+} // namespace content
diff --git a/content/browser/service_worker/embedded_worker_registry.h b/content/browser/service_worker/embedded_worker_registry.h
new file mode 100644
index 0000000..8860e37
--- /dev/null
+++ b/content/browser/service_worker/embedded_worker_registry.h
@@ -0,0 +1,77 @@
+// Copyright 2013 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.
+
+#ifndef CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_REGISTRY_H_
+#define CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_REGISTRY_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "content/common/content_export.h"
+
+class GURL;
+
+namespace IPC {
+class Message;
+class Sender;
+}
+
+namespace content {
+
+class EmbeddedWorkerInstance;
+class ServiceWorkerContextCore;
+
+// Acts as a thin stub between MessageFilter and each EmbeddedWorkerInstance,
+// which sends/receives messages to/from each EmbeddedWorker in child process.
+//
+// Hangs off ServiceWorkerContextCore (its reference is also held by each
+// EmbeddedWorkerInstance). Operated only on IO thread.
+class CONTENT_EXPORT EmbeddedWorkerRegistry
+ : public NON_EXPORTED_BASE(base::RefCounted<EmbeddedWorkerRegistry>) {
+ public:
+ explicit EmbeddedWorkerRegistry(
+ base::WeakPtr<ServiceWorkerContextCore> context);
+
+ // Creates and removes a new worker instance entry for bookkeeping.
+ // This doesn't actually start or stop the worker.
+ scoped_ptr<EmbeddedWorkerInstance> CreateWorker();
+ void RemoveWorker(int embedded_worker_id);
+
+ // Called from EmbeddedWorkerInstance, relayed to the child process.
+ bool StartWorker(int process_id,
+ int embedded_worker_id,
+ int64 service_worker_version_id,
+ const GURL& script_url);
+ bool StopWorker(int process_id,
+ int embedded_worker_id);
+
+ // Keeps a map from process_id to sender information.
+ void AddChildProcessSender(int process_id, IPC::Sender* sender);
+ void RemoveChildProcessSender(int process_id);
+
+ private:
+ friend class base::RefCounted<EmbeddedWorkerRegistry>;
+
+ ~EmbeddedWorkerRegistry();
+ bool Send(int process_id, IPC::Message* message);
+
+ typedef std::map<int, EmbeddedWorkerInstance*> WorkerInstanceMap;
+ typedef std::map<int, IPC::Sender*> ProcessToSenderMap;
+
+ base::WeakPtr<ServiceWorkerContextCore> context_;
+
+ WorkerInstanceMap worker_map_;
+ ProcessToSenderMap process_sender_map_;
+
+ int next_embedded_worker_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerRegistry);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_SERVICE_WORKER_EMBEDDED_WORKER_REGISTRY_H_
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc
index 19b6c7f..8d1e7a8 100644
--- a/content/browser/service_worker/service_worker_context_core.cc
+++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/strings/string_util.h"
+#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
#include "content/browser/service_worker/service_worker_register_job.h"
#include "content/browser/service_worker/service_worker_registration.h"
@@ -20,7 +21,8 @@ namespace content {
ServiceWorkerContextCore::ServiceWorkerContextCore(
const base::FilePath& path,
quota::QuotaManagerProxy* quota_manager_proxy)
- : storage_(new ServiceWorkerStorage(path, quota_manager_proxy)) {}
+ : storage_(new ServiceWorkerStorage(path, quota_manager_proxy)),
+ embedded_worker_registry_(new EmbeddedWorkerRegistry(AsWeakPtr())) {}
ServiceWorkerContextCore::~ServiceWorkerContextCore() {}
diff --git a/content/browser/service_worker/service_worker_context_core.h b/content/browser/service_worker/service_worker_context_core.h
index 854e234..0351c2e 100644
--- a/content/browser/service_worker/service_worker_context_core.h
+++ b/content/browser/service_worker/service_worker_context_core.h
@@ -29,9 +29,10 @@ class QuotaManagerProxy;
namespace content {
-class ServiceWorkerStorage;
-class ServiceWorkerRegistration;
+class EmbeddedWorkerRegistry;
class ServiceWorkerProviderHost;
+class ServiceWorkerRegistration;
+class ServiceWorkerStorage;
// This class manages data associated with service workers.
// The class is single threaded and should only be used on the IO thread.
@@ -74,6 +75,10 @@ class CONTENT_EXPORT ServiceWorkerContextCore
void UnregisterServiceWorker(const GURL& pattern,
const UnregistrationCallback& callback);
+ EmbeddedWorkerRegistry* embedded_worker_registry() {
+ return embedded_worker_registry_.get();
+ }
+
private:
typedef IDMap<ServiceWorkerProviderHost, IDMapOwnPointer> ProviderMap;
typedef IDMap<ProviderMap, IDMapOwnPointer> ProcessToProviderMap;
@@ -91,6 +96,7 @@ class CONTENT_EXPORT ServiceWorkerContextCore
ProcessToProviderMap providers_;
scoped_ptr<ServiceWorkerStorage> storage_;
+ scoped_refptr<EmbeddedWorkerRegistry> embedded_worker_registry_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextCore);
};
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index b6614fa..9f6b139 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -5,6 +5,7 @@
#include "content/browser/service_worker/service_worker_dispatcher_host.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/browser/service_worker/embedded_worker_registry.h"
#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/service_worker/service_worker_provider_host.h"
@@ -37,8 +38,11 @@ ServiceWorkerDispatcherHost::ServiceWorkerDispatcherHost(
}
ServiceWorkerDispatcherHost::~ServiceWorkerDispatcherHost() {
- if (context_)
+ if (context_) {
context_->RemoveAllProviderHostsForProcess(render_process_id_);
+ context_->embedded_worker_registry()->RemoveChildProcessSender(
+ render_process_id_);
+ }
}
void ServiceWorkerDispatcherHost::Init(
@@ -51,6 +55,8 @@ void ServiceWorkerDispatcherHost::Init(
return;
}
context_ = context_wrapper->context()->AsWeakPtr();
+ context_->embedded_worker_registry()->AddChildProcessSender(
+ render_process_id_, this);
}
void ServiceWorkerDispatcherHost::OnDestruct() const {
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc
index 1ad7895..3fb6611 100644
--- a/content/browser/service_worker/service_worker_registration_unittest.cc
+++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -26,7 +26,8 @@ class ServiceWorkerRegistrationTest : public testing::Test {
};
TEST_F(ServiceWorkerRegistrationTest, Shutdown) {
- int64 registration_id = -1L;
+ const int64 registration_id = -1L;
+ const int64 version_id = -1L;
scoped_refptr<ServiceWorkerRegistration> registration =
new ServiceWorkerRegistration(
GURL("http://www.example.com/*"),
@@ -34,7 +35,7 @@ TEST_F(ServiceWorkerRegistrationTest, Shutdown) {
registration_id);
scoped_refptr<ServiceWorkerVersion> active_version =
- new ServiceWorkerVersion(registration);
+ new ServiceWorkerVersion(registration, NULL, version_id);
registration->set_active_version(active_version);
registration->Shutdown();
@@ -54,12 +55,14 @@ TEST_F(ServiceWorkerRegistrationTest, ActivatePending) {
GURL("http://www.example.com/service_worker.js"),
registration_id);
+ const int64 version_1_id = 1L;
+ const int64 version_2_id = 2L;
scoped_refptr<ServiceWorkerVersion> version_1 =
- new ServiceWorkerVersion(registration);
+ new ServiceWorkerVersion(registration, NULL, version_1_id);
registration->set_active_version(version_1);
scoped_refptr<ServiceWorkerVersion> version_2 =
- new ServiceWorkerVersion(registration);
+ new ServiceWorkerVersion(registration, NULL, version_2_id);
registration->set_pending_version(version_2);
registration->ActivatePendingVersion();
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index fa3ad3d..a91ac6e 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -4,19 +4,53 @@
#include "content/browser/service_worker/service_worker_version.h"
+#include "base/stl_util.h"
+#include "content/browser/service_worker/embedded_worker_instance.h"
+#include "content/browser/service_worker/embedded_worker_registry.h"
+#include "content/browser/service_worker/service_worker_context_core.h"
#include "content/browser/service_worker/service_worker_registration.h"
namespace content {
ServiceWorkerVersion::ServiceWorkerVersion(
- ServiceWorkerRegistration* registration)
- : is_shutdown_(false), registration_(registration) {}
+ ServiceWorkerRegistration* registration,
+ EmbeddedWorkerRegistry* worker_registry,
+ int64 version_id)
+ : version_id_(version_id),
+ is_shutdown_(false),
+ registration_(registration) {
+ if (worker_registry)
+ embedded_worker_ = worker_registry->CreateWorker();
+}
ServiceWorkerVersion::~ServiceWorkerVersion() { DCHECK(is_shutdown_); }
void ServiceWorkerVersion::Shutdown() {
is_shutdown_ = true;
registration_ = NULL;
+ embedded_worker_.reset();
+}
+
+void ServiceWorkerVersion::StartWorker() {
+ DCHECK(!is_shutdown_);
+ DCHECK(registration_);
+ embedded_worker_->Start(version_id_, registration_->script_url());
+}
+
+void ServiceWorkerVersion::StopWorker() {
+ DCHECK(!is_shutdown_);
+ embedded_worker_->Stop();
+}
+
+void ServiceWorkerVersion::OnAssociateProvider(
+ ServiceWorkerProviderHost* provider_host) {
+ DCHECK(!is_shutdown_);
+ embedded_worker_->AddProcessReference(provider_host->process_id());
+}
+
+void ServiceWorkerVersion::OnUnassociateProvider(
+ ServiceWorkerProviderHost* provider_host) {
+ embedded_worker_->ReleaseProcessReference(provider_host->process_id());
}
} // namespace content
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index 93f4459..46b75bd 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -8,12 +8,16 @@
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
class GURL;
namespace content {
+class EmbeddedWorkerInstance;
+class EmbeddedWorkerRegistry;
+class ServiceWorkerProviderHost;
class ServiceWorkerRegistration;
// This class corresponds to a specific version of a ServiceWorker
@@ -51,19 +55,40 @@ class ServiceWorkerRegistration;
class CONTENT_EXPORT ServiceWorkerVersion
: NON_EXPORTED_BASE(public base::RefCounted<ServiceWorkerVersion>) {
public:
- explicit ServiceWorkerVersion(ServiceWorkerRegistration* registration);
+ ServiceWorkerVersion(
+ ServiceWorkerRegistration* registration,
+ EmbeddedWorkerRegistry* worker_registry,
+ int64 version_id);
+
+ int64 version_id() const { return version_id_; }
void Shutdown();
bool is_shutdown() const { return is_shutdown_; }
+ // Starts and stops an embedded worker for this version.
+ void StartWorker();
+ void StopWorker();
+
+ // Called when this version is associated to a provider host.
+ // Non-null |provider_host| must be given.
+ void OnAssociateProvider(ServiceWorkerProviderHost* provider_host);
+ void OnUnassociateProvider(ServiceWorkerProviderHost* provider_host);
+
private:
- ~ServiceWorkerVersion();
friend class base::RefCounted<ServiceWorkerVersion>;
+ ~ServiceWorkerVersion();
+
+ const int64 version_id_;
+
bool is_shutdown_;
scoped_refptr<ServiceWorkerRegistration> registration_;
+ scoped_ptr<EmbeddedWorkerInstance> embedded_worker_;
+
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersion);
};
+
} // namespace content
+
#endif // CONTENT_BROWSER_SERVICE_WORKER_SERVICE_WORKER_VERSION_H_
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 03fb24b..294782a 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -1084,6 +1084,10 @@
'browser/resource_context_impl.h',
'browser/safe_util_win.cc',
'browser/safe_util_win.h',
+ 'browser/service_worker/embedded_worker_instance.cc',
+ 'browser/service_worker/embedded_worker_instance.h',
+ 'browser/service_worker/embedded_worker_registry.cc',
+ 'browser/service_worker/embedded_worker_registry.h',
'browser/service_worker/service_worker_context.h',
'browser/service_worker/service_worker_context_core.cc',
'browser/service_worker/service_worker_context_core.h',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index c71dc3d..bf6cdeb 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -461,10 +461,11 @@
'browser/renderer_host/input/web_input_event_builders_gtk_unittest.cc',
'browser/renderer_host/websocket_dispatcher_host_unittest.cc',
'browser/resolve_proxy_msg_helper_unittest.cc',
- 'browser/service_worker/service_worker_dispatcher_host_unittest.cc',
+ 'browser/service_worker/embedded_worker_instance_unittest.cc',
'browser/service_worker/service_worker_context_unittest.cc',
- 'browser/service_worker/service_worker_storage_unittest.cc',
+ 'browser/service_worker/service_worker_dispatcher_host_unittest.cc',
'browser/service_worker/service_worker_registration_unittest.cc',
+ 'browser/service_worker/service_worker_storage_unittest.cc',
'browser/site_instance_impl_unittest.cc',
'browser/speech/chunked_byte_buffer_unittest.cc',
'browser/speech/endpointer/endpointer_unittest.cc',