summaryrefslogtreecommitdiffstats
path: root/content/child
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-19 16:34:36 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-19 16:34:36 +0000
commitce944c615b0d8f2402f884eab81d303e0ac2072e (patch)
tree0dd3ec560ff87fb15be9fc613794fd97f23cac68 /content/child
parent9aec59935a7c4e6a1bdb04acfc3b64fafa822e8c (diff)
downloadchromium_src-ce944c615b0d8f2402f884eab81d303e0ac2072e.zip
chromium_src-ce944c615b0d8f2402f884eab81d303e0ac2072e.tar.gz
chromium_src-ce944c615b0d8f2402f884eab81d303e0ac2072e.tar.bz2
Add ChildMessageFilter, a base class for renderer/worker cross-thread MessageFilter
- Save some dup'ed code in similar message filters - Centralize WorkerRunner thread-handling code into one class (which could be helpful when we migrate worker thread implementation) BUG=none Review URL: https://codereview.chromium.org/63843002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@236004 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/child')
-rw-r--r--content/child/child_message_filter.cc64
-rw-r--r--content/child/child_message_filter.h68
-rw-r--r--content/child/child_thread.cc6
-rw-r--r--content/child/indexed_db/indexed_db_message_filter.cc42
-rw-r--r--content/child/indexed_db/indexed_db_message_filter.h17
-rw-r--r--content/child/quota_message_filter.cc60
-rw-r--r--content/child/quota_message_filter.h14
-rw-r--r--content/child/service_worker/service_worker_message_filter.cc35
-rw-r--r--content/child/service_worker/service_worker_message_filter.h19
-rw-r--r--content/child/worker_thread_task_runner.cc40
-rw-r--r--content/child/worker_thread_task_runner.h39
11 files changed, 298 insertions, 106 deletions
diff --git a/content/child/child_message_filter.cc b/content/child/child_message_filter.cc
new file mode 100644
index 0000000..c325632
--- /dev/null
+++ b/content/child/child_message_filter.cc
@@ -0,0 +1,64 @@
+// 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/child/child_message_filter.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/task_runner.h"
+#include "content/child/child_thread.h"
+#include "content/child/thread_safe_sender.h"
+
+namespace content {
+
+class ChildMessageFilter::Internal : public IPC::ChannelProxy::MessageFilter {
+ public:
+ explicit Internal(ChildMessageFilter* filter) : filter_(filter) {}
+
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
+ scoped_refptr<base::TaskRunner> runner =
+ filter_->OverrideTaskRunnerForMessage(msg);
+ if (runner && !runner->RunsTasksOnCurrentThread()) {
+ if (!runner->PostTask(
+ FROM_HERE,
+ base::Bind(
+ base::IgnoreResult(&ChildMessageFilter::OnMessageReceived),
+ filter_, msg)))
+ filter_->OnStaleMessageReceived(msg);
+ return true;
+ }
+
+ return filter_->OnMessageReceived(msg);
+ }
+
+ private:
+ virtual ~Internal() {}
+ scoped_refptr<ChildMessageFilter> filter_;
+
+ DISALLOW_COPY_AND_ASSIGN(Internal);
+};
+
+bool ChildMessageFilter::Send(IPC::Message* message) {
+ return thread_safe_sender_->Send(message);
+}
+
+base::TaskRunner* ChildMessageFilter::OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) {
+ return NULL;
+}
+
+ChildMessageFilter::ChildMessageFilter()
+ : internal_(NULL),
+ thread_safe_sender_(ChildThread::current()->thread_safe_sender()) {}
+
+ChildMessageFilter::~ChildMessageFilter() {}
+
+IPC::ChannelProxy::MessageFilter* ChildMessageFilter::GetFilter() {
+ if (!internal_)
+ internal_ = new Internal(this);
+ return internal_;
+}
+
+} // namespace content
diff --git a/content/child/child_message_filter.h b/content/child/child_message_filter.h
new file mode 100644
index 0000000..21cccac
--- /dev/null
+++ b/content/child/child_message_filter.h
@@ -0,0 +1,68 @@
+// 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_CHILD_CROSS_MESSAGE_FILTER_H_
+#define CONTENT_CHILD_CROSS_MESSAGE_FILTER_H_
+
+#include "ipc/ipc_channel_proxy.h"
+
+namespace base {
+class TaskRunner;
+}
+
+namespace content {
+
+class ThreadSafeSender;
+
+// A base class for implementing IPC MessageFilter's that run on a different
+// thread or TaskRunner than the main thread.
+class ChildMessageFilter
+ : public base::RefCountedThreadSafe<ChildMessageFilter>,
+ public IPC::Sender {
+ public:
+ // IPC::Sender implementation. Can be called on any threads.
+ virtual bool Send(IPC::Message* message) OVERRIDE;
+
+ // If implementers want to run OnMessageReceived on a different task
+ // runner it should override this and return the TaskRunner for the message.
+ // Returning NULL runs OnMessageReceived() on the current IPC thread.
+ virtual base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) = 0;
+
+ // If OverrideTaskRunnerForMessage is overriden and returns non-null
+ // this will be called on the returned TaskRunner.
+ virtual bool OnMessageReceived(const IPC::Message& msg) = 0;
+
+ // This method is called when WorkerTaskRunner::PostTask() returned false
+ // for the target thread. Note that there's still a little chance that
+ // PostTask() returns true but OnMessageReceived() is never called on the
+ // target thread. By default this does nothing.
+ virtual void OnStaleMessageReceived(const IPC::Message& msg) {}
+
+ protected:
+ ChildMessageFilter();
+ virtual ~ChildMessageFilter();
+
+ private:
+ class Internal;
+ friend class ChildThread;
+ friend class RenderThreadImpl;
+ friend class WorkerThread;
+
+ friend class base::RefCountedThreadSafe<ChildMessageFilter>;
+
+ IPC::ChannelProxy::MessageFilter* GetFilter();
+
+ // This implements IPC::ChannelProxy::MessageFilter to hide the actual
+ // filter methods from child classes.
+ Internal* internal_;
+
+ scoped_refptr<ThreadSafeSender> thread_safe_sender_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_CROSS_MESSAGE_FILTER_H_
diff --git a/content/child/child_thread.cc b/content/child/child_thread.cc
index f4387ec..8147d93 100644
--- a/content/child/child_thread.cc
+++ b/content/child/child_thread.cc
@@ -201,8 +201,8 @@ void ChildThread::Init() {
channel_->AddFilter(new tracing::ChildTraceMessageFilter(
ChildProcess::current()->io_message_loop_proxy()));
channel_->AddFilter(resource_message_filter_.get());
- channel_->AddFilter(quota_message_filter_.get());
- channel_->AddFilter(service_worker_message_filter_.get());
+ channel_->AddFilter(quota_message_filter_->GetFilter());
+ channel_->AddFilter(service_worker_message_filter_->GetFilter());
// In single process mode we may already have a power monitor
if (!base::PowerMonitor::Get()) {
@@ -264,8 +264,6 @@ ChildThread::~ChildThread() {
IPC::Logging::GetInstance()->SetIPCSender(NULL);
#endif
- channel_->RemoveFilter(service_worker_message_filter_.get());
- channel_->RemoveFilter(quota_message_filter_.get());
channel_->RemoveFilter(histogram_message_filter_.get());
channel_->RemoveFilter(sync_message_filter_.get());
diff --git a/content/child/indexed_db/indexed_db_message_filter.cc b/content/child/indexed_db/indexed_db_message_filter.cc
index 7022925..6d2305f 100644
--- a/content/child/indexed_db/indexed_db_message_filter.cc
+++ b/content/child/indexed_db/indexed_db_message_filter.cc
@@ -4,16 +4,11 @@
#include "content/child/indexed_db/indexed_db_message_filter.h"
-#include "base/bind.h"
-#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
-#include "base/pickle.h"
#include "content/child/indexed_db/indexed_db_dispatcher.h"
#include "content/child/thread_safe_sender.h"
+#include "content/child/worker_thread_task_runner.h"
#include "content/common/indexed_db/indexed_db_messages.h"
-#include "webkit/child/worker_task_runner.h"
-
-using webkit_glue::WorkerTaskRunner;
namespace content {
@@ -23,31 +18,26 @@ IndexedDBMessageFilter::IndexedDBMessageFilter(
thread_safe_sender_(thread_safe_sender) {
}
-bool IndexedDBMessageFilter::OnMessageReceived(const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != IndexedDBMsgStart)
- return false;
- int ipc_thread_id = -1;
- bool result = PickleIterator(msg).ReadInt(&ipc_thread_id);
- DCHECK(result);
- base::Closure closure = base::Bind(
- &IndexedDBMessageFilter::DispatchMessage, this, msg);
- if (!ipc_thread_id) {
- main_thread_loop_proxy_->PostTask(FROM_HERE, closure);
- return true;
- }
- if (WorkerTaskRunner::Instance()->PostTask(ipc_thread_id, closure))
- return true;
+IndexedDBMessageFilter::~IndexedDBMessageFilter() {}
- // Message for a terminated worker - perform necessary cleanup
- OnStaleMessageReceived(msg);
- return true;
+base::TaskRunner* IndexedDBMessageFilter::OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) {
+ if (IPC_MESSAGE_CLASS(msg) != IndexedDBMsgStart)
+ return NULL;
+ int ipc_thread_id = 0;
+ const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
+ DCHECK(success);
+ if (!ipc_thread_id)
+ return main_thread_loop_proxy_.get();
+ return new WorkerThreadTaskRunner(ipc_thread_id);
}
-IndexedDBMessageFilter::~IndexedDBMessageFilter() {}
-
-void IndexedDBMessageFilter::DispatchMessage(const IPC::Message& msg) {
+bool IndexedDBMessageFilter::OnMessageReceived(const IPC::Message& msg) {
+ if (IPC_MESSAGE_CLASS(msg) != IndexedDBMsgStart)
+ return false;
IndexedDBDispatcher::ThreadSpecificInstance(thread_safe_sender_.get())
->OnMessageReceived(msg);
+ return true;
}
void IndexedDBMessageFilter::OnStaleMessageReceived(const IPC::Message& msg) {
diff --git a/content/child/indexed_db/indexed_db_message_filter.h b/content/child/indexed_db/indexed_db_message_filter.h
index da11adf..ebe492b 100644
--- a/content/child/indexed_db/indexed_db_message_filter.h
+++ b/content/child/indexed_db/indexed_db_message_filter.h
@@ -5,7 +5,7 @@
#ifndef CONTENT_CHILD_INDEXED_DB_INDEXED_DB_MESSAGE_FILTER_H_
#define CONTENT_CHILD_INDEXED_DB_INDEXED_DB_MESSAGE_FILTER_H_
-#include "ipc/ipc_channel_proxy.h"
+#include "content/child/child_message_filter.h"
struct IndexedDBDatabaseMetadata;
struct IndexedDBMsg_CallbacksUpgradeNeeded_Params;
@@ -15,22 +15,23 @@ class MessageLoopProxy;
} // namespace base
namespace content {
-class IndexedDBDispatcher;
+
class ThreadSafeSender;
-class IndexedDBMessageFilter : public IPC::ChannelProxy::MessageFilter {
+class IndexedDBMessageFilter : public ChildMessageFilter {
public:
explicit IndexedDBMessageFilter(ThreadSafeSender* thread_safe_sender);
- // IPC::Listener implementation.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
-
protected:
virtual ~IndexedDBMessageFilter();
private:
- void DispatchMessage(const IPC::Message& msg);
- void OnStaleMessageReceived(const IPC::Message& msg);
+ // ChildMessageFilter implementation:
+ virtual base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) OVERRIDE;
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ virtual void OnStaleMessageReceived(const IPC::Message& msg) OVERRIDE;
+
void OnStaleSuccessIDBDatabase(int32 ipc_thread_id,
int32 ipc_callbacks_id,
int32 ipc_database_callbacks_id,
diff --git a/content/child/quota_message_filter.cc b/content/child/quota_message_filter.cc
index 590a966..139be25 100644
--- a/content/child/quota_message_filter.cc
+++ b/content/child/quota_message_filter.cc
@@ -4,16 +4,11 @@
#include "content/child/quota_message_filter.h"
-#include "base/bind.h"
-#include "base/location.h"
#include "base/message_loop/message_loop_proxy.h"
-#include "base/pickle.h"
#include "content/child/quota_dispatcher.h"
#include "content/child/thread_safe_sender.h"
+#include "content/child/worker_thread_task_runner.h"
#include "content/common/quota_messages.h"
-#include "webkit/child/worker_task_runner.h"
-
-using webkit_glue::WorkerTaskRunner;
namespace content {
@@ -24,30 +19,7 @@ QuotaMessageFilter::QuotaMessageFilter(
next_request_id_(0) {
}
-bool QuotaMessageFilter::OnMessageReceived(const IPC::Message& msg) {
- if (IPC_MESSAGE_CLASS(msg) != QuotaMsgStart)
- return false;
- int request_id = -1;
- bool result = PickleIterator(msg).ReadInt(&request_id);
- DCHECK(result);
- base::Closure closure = base::Bind(
- &QuotaMessageFilter::DispatchMessage, this, msg);
- int thread_id = 0;
- {
- base::AutoLock lock(request_id_map_lock_);
- RequestIdToThreadId::iterator found = request_id_map_.find(request_id);
- if (found != request_id_map_.end()) {
- thread_id = found->second;
- request_id_map_.erase(found);
- }
- }
- if (!thread_id) {
- main_thread_loop_proxy_->PostTask(FROM_HERE, closure);
- return true;
- }
- WorkerTaskRunner::Instance()->PostTask(thread_id, closure);
- return true;
-}
+QuotaMessageFilter::~QuotaMessageFilter() {}
int QuotaMessageFilter::GenerateRequestID(int thread_id) {
base::AutoLock lock(request_id_map_lock_);
@@ -66,11 +38,35 @@ void QuotaMessageFilter::ClearThreadRequests(int thread_id) {
}
}
-QuotaMessageFilter::~QuotaMessageFilter() {}
+base::TaskRunner* QuotaMessageFilter::OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) {
+ if (IPC_MESSAGE_CLASS(msg) != QuotaMsgStart)
+ return NULL;
+
+ int request_id = -1, thread_id = 0;
+ const bool success = PickleIterator(msg).ReadInt(&request_id);
+ DCHECK(success);
-void QuotaMessageFilter::DispatchMessage(const IPC::Message& msg) {
+ {
+ base::AutoLock lock(request_id_map_lock_);
+ RequestIdToThreadId::iterator found = request_id_map_.find(request_id);
+ if (found != request_id_map_.end()) {
+ thread_id = found->second;
+ request_id_map_.erase(found);
+ }
+ }
+
+ if (!thread_id)
+ return main_thread_loop_proxy_.get();
+ return new WorkerThreadTaskRunner(thread_id);
+}
+
+bool QuotaMessageFilter::OnMessageReceived(const IPC::Message& msg) {
+ if (IPC_MESSAGE_CLASS(msg) != QuotaMsgStart)
+ return false;
QuotaDispatcher::ThreadSpecificInstance(thread_safe_sender_.get(), this)
->OnMessageReceived(msg);
+ return true;
}
} // namespace content
diff --git a/content/child/quota_message_filter.h b/content/child/quota_message_filter.h
index eba6313..eabff1b 100644
--- a/content/child/quota_message_filter.h
+++ b/content/child/quota_message_filter.h
@@ -8,7 +8,7 @@
#include <map>
#include "base/synchronization/lock.h"
-#include "ipc/ipc_channel_proxy.h"
+#include "content/child/child_message_filter.h"
namespace base {
class MessageLoopProxy;
@@ -18,13 +18,10 @@ namespace content {
class ThreadSafeSender;
-class QuotaMessageFilter : public IPC::ChannelProxy::MessageFilter {
+class QuotaMessageFilter : public ChildMessageFilter {
public:
explicit QuotaMessageFilter(ThreadSafeSender* thread_safe_sender);
- // IPC::Listener implementation.
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
-
// Generates a new request_id, registers { request_id, thread_id } map to
// the message filter and returns the request_id.
// This method can be called on any thread.
@@ -37,9 +34,12 @@ class QuotaMessageFilter : public IPC::ChannelProxy::MessageFilter {
virtual ~QuotaMessageFilter();
private:
- typedef std::map<int, int> RequestIdToThreadId;
+ // ChildMessageFilter implementation:
+ virtual base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) OVERRIDE;
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
- void DispatchMessage(const IPC::Message& msg);
+ typedef std::map<int, int> RequestIdToThreadId;
scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
diff --git a/content/child/service_worker/service_worker_message_filter.cc b/content/child/service_worker/service_worker_message_filter.cc
index aaacabe..e6b5ff1 100644
--- a/content/child/service_worker/service_worker_message_filter.cc
+++ b/content/child/service_worker/service_worker_message_filter.cc
@@ -4,15 +4,11 @@
#include "content/child/service_worker/service_worker_message_filter.h"
-#include "ipc/ipc_message_macros.h"
-#include "base/bind.h"
#include "base/message_loop/message_loop_proxy.h"
-#include "base/pickle.h"
#include "content/child/service_worker/service_worker_dispatcher.h"
#include "content/child/thread_safe_sender.h"
-#include "webkit/child/worker_task_runner.h"
-
-using webkit_glue::WorkerTaskRunner;
+#include "content/child/worker_thread_task_runner.h"
+#include "ipc/ipc_message_macros.h"
namespace content {
@@ -22,25 +18,24 @@ ServiceWorkerMessageFilter::ServiceWorkerMessageFilter(ThreadSafeSender* sender)
ServiceWorkerMessageFilter::~ServiceWorkerMessageFilter() {}
-bool ServiceWorkerMessageFilter::OnMessageReceived(const IPC::Message& msg) {
+base::TaskRunner* ServiceWorkerMessageFilter::OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) {
if (IPC_MESSAGE_CLASS(msg) != ServiceWorkerMsgStart)
- return false;
- int thread_id = 0;
- bool result = PickleIterator(msg).ReadInt(&thread_id);
- DCHECK(result);
- base::Closure closure =
- base::Bind(&ServiceWorkerMessageFilter::DispatchMessage, this, msg);
- if (!thread_id) {
- main_thread_loop_proxy_->PostTask(FROM_HERE, closure);
- return true;
- }
- WorkerTaskRunner::Instance()->PostTask(thread_id, closure);
- return true;
+ return NULL;
+ int ipc_thread_id = 0;
+ const bool success = PickleIterator(msg).ReadInt(&ipc_thread_id);
+ DCHECK(success);
+ if (!ipc_thread_id)
+ return main_thread_loop_proxy_.get();
+ return new WorkerThreadTaskRunner(ipc_thread_id);
}
-void ServiceWorkerMessageFilter::DispatchMessage(const IPC::Message& msg) {
+bool ServiceWorkerMessageFilter::OnMessageReceived(const IPC::Message& msg) {
+ if (IPC_MESSAGE_CLASS(msg) != ServiceWorkerMsgStart)
+ return false;
ServiceWorkerDispatcher::ThreadSpecificInstance(thread_safe_sender_.get())
->OnMessageReceived(msg);
+ return true;
}
} // namespace content
diff --git a/content/child/service_worker/service_worker_message_filter.h b/content/child/service_worker/service_worker_message_filter.h
index 5400e74..f14cbcf 100644
--- a/content/child/service_worker/service_worker_message_filter.h
+++ b/content/child/service_worker/service_worker_message_filter.h
@@ -5,29 +5,30 @@
#ifndef CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
#define CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
-#include <map>
-
+#include "content/child/child_message_filter.h"
#include "content/common/content_export.h"
-#include "ipc/ipc_channel_proxy.h"
+
+namespace base {
+class MessageLoopProxy;
+}
namespace content {
class ThreadSafeSender;
-class MessageLoopProxy;
class CONTENT_EXPORT ServiceWorkerMessageFilter
- : public IPC::ChannelProxy::MessageFilter {
+ : public NON_EXPORTED_BASE(ChildMessageFilter) {
public:
explicit ServiceWorkerMessageFilter(ThreadSafeSender* thread_safe_sender);
- // IPC::Listener implementation
- virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
-
protected:
virtual ~ServiceWorkerMessageFilter();
private:
- void DispatchMessage(const IPC::Message& msg);
+ // ChildMessageFilter implementation:
+ virtual base::TaskRunner* OverrideTaskRunnerForMessage(
+ const IPC::Message& msg) OVERRIDE;
+ virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
scoped_refptr<base::MessageLoopProxy> main_thread_loop_proxy_;
scoped_refptr<ThreadSafeSender> thread_safe_sender_;
diff --git a/content/child/worker_thread_task_runner.cc b/content/child/worker_thread_task_runner.cc
new file mode 100644
index 0000000..fb2a5a8
--- /dev/null
+++ b/content/child/worker_thread_task_runner.cc
@@ -0,0 +1,40 @@
+// 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/child/worker_thread_task_runner.h"
+
+#include "base/logging.h"
+#include "webkit/child/worker_task_runner.h"
+
+using webkit_glue::WorkerTaskRunner;
+
+namespace content {
+
+WorkerThreadTaskRunner::WorkerThreadTaskRunner(int worker_thread_id)
+ : worker_thread_id_(worker_thread_id) {
+}
+
+scoped_refptr<WorkerThreadTaskRunner> WorkerThreadTaskRunner::current() {
+ int worker_thread_id = WorkerTaskRunner::Instance()->CurrentWorkerId();
+ if (!worker_thread_id)
+ return scoped_refptr<WorkerThreadTaskRunner>();
+ return make_scoped_refptr(new WorkerThreadTaskRunner(worker_thread_id));
+}
+
+bool WorkerThreadTaskRunner::PostDelayedTask(
+ const tracked_objects::Location& /* from_here */,
+ const base::Closure& task,
+ base::TimeDelta delay) {
+ // Currently non-zero delay is not supported.
+ DCHECK(!delay.ToInternalValue());
+ return WorkerTaskRunner::Instance()->PostTask(worker_thread_id_, task);
+}
+
+bool WorkerThreadTaskRunner::RunsTasksOnCurrentThread() const {
+ return worker_thread_id_ == WorkerTaskRunner::Instance()->CurrentWorkerId();
+}
+
+WorkerThreadTaskRunner::~WorkerThreadTaskRunner() {}
+
+} // namespace content
diff --git a/content/child/worker_thread_task_runner.h b/content/child/worker_thread_task_runner.h
new file mode 100644
index 0000000..a4fbc91
--- /dev/null
+++ b/content/child/worker_thread_task_runner.h
@@ -0,0 +1,39 @@
+// 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_CHILD_WORKER_THREAD_TASK_RUNNER_H_
+#define CONTENT_CHILD_WORKER_THREAD_TASK_RUNNER_H_
+
+#include "base/task_runner.h"
+
+namespace content {
+
+// A task runner that runs tasks on a single webkit worker thread which
+// is managed by webkit_glue::WorkerTaskRunner.
+// Note that this implementation ignores the delay duration for PostDelayedTask
+// and have it behave the same as PostTask.
+class WorkerThreadTaskRunner : public base::TaskRunner {
+ public:
+ explicit WorkerThreadTaskRunner(int worker_thread_id);
+
+ // Gets the WorkerThreadTaskRunner for the current worker thread.
+ // This returns non-null value only when it is called on a worker thread.
+ static scoped_refptr<WorkerThreadTaskRunner> current();
+
+ // TaskRunner overrides.
+ virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) OVERRIDE;
+ virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
+
+ protected:
+ virtual ~WorkerThreadTaskRunner();
+
+ private:
+ const int worker_thread_id_;
+};
+
+} // namespace content
+
+#endif // CONTENT_CHILD_WORKER_THREAD_TASK_RUNNER_H_