base: Make it possible to replace the MessageLoop's task runner
This patch makes it possible to customize the task posting behavior
of a MessageLoop. More specifically, a client can change the value
returned by MessageLoop::task_runner() as well as
ThreadTaskRunnerHandle::Get() on the target thread. The original task
runner can still be used to post tasks to be run on the message loop.
The Blink/renderer scheduler will use this functionality to manage task
posting on the renderer main thread. This is needed to ensure consistent
ordering of tasks posted through the MessageLoop w.r.t. tasks posted to
the scheduler.
Design doc: https://docs.google.com/a/chromium.org/document/d/1qxdh2I61_aB_Uzh1QgNqvdWFBCL_E65G2smoSySw7KU/edit#
Alex Clarke <alexclarke@chromium.org> also contributed to this patch (https://codereview.chromium.org/1206893003/).
BUG=465354
Review URL: https://codereview.chromium.org/998063002
Cr-Commit-Position: refs/heads/master@{#337799}
CrOS-Libchrome-Original-Commit: 698e77997894bf823c45ad1d6e0764fa93e2f3c1
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 0eb24cf..4fecbc5 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -170,6 +170,7 @@
// Tell the incoming queue that we are dying.
incoming_task_queue_->WillDestroyCurrentMessageLoop();
incoming_task_queue_ = NULL;
+ unbound_task_runner_ = NULL;
task_runner_ = NULL;
// OK, now make it so that no one can find us.
@@ -367,6 +368,7 @@
//------------------------------------------------------------------------------
+// static
scoped_ptr<MessageLoop> MessageLoop::CreateUnbound(
Type type, MessagePumpFactoryCallback pump_factory) {
return make_scoped_ptr(new MessageLoop(type, pump_factory));
@@ -386,7 +388,9 @@
message_histogram_(NULL),
run_loop_(NULL),
incoming_task_queue_(new internal::IncomingTaskQueue(this)),
- task_runner_(new internal::MessageLoopTaskRunner(incoming_task_queue_)) {
+ unbound_task_runner_(
+ new internal::MessageLoopTaskRunner(incoming_task_queue_)),
+ task_runner_(unbound_task_runner_) {
// If type is TYPE_CUSTOM non-null pump_factory must be given.
DCHECK_EQ(type_ == TYPE_CUSTOM, !pump_factory_.is_null());
}
@@ -402,7 +406,19 @@
lazy_tls_ptr.Pointer()->Set(this);
incoming_task_queue_->StartScheduling();
- task_runner_->BindToCurrentThread();
+ unbound_task_runner_->BindToCurrentThread();
+ SetTaskRunner(unbound_task_runner_.Pass());
+}
+
+void MessageLoop::SetTaskRunner(
+ scoped_refptr<SingleThreadTaskRunner> task_runner) {
+ DCHECK_EQ(this, current());
+ DCHECK(task_runner->BelongsToCurrentThread());
+ DCHECK(!unbound_task_runner_);
+ task_runner_ = task_runner.Pass();
+ // Clear the previous thread task runner first because only one can exist at
+ // a time.
+ thread_task_runner_handle_.reset();
thread_task_runner_handle_.reset(new ThreadTaskRunnerHandle(task_runner_));
}
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 9429e6b..3445a77 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -296,9 +296,16 @@
const std::string& thread_name() const { return thread_name_; }
// Gets the TaskRunner associated with this message loop.
- // TODO(skyostil): Change this to return a const reference to a refptr
- // once the internal type matches what is being returned (crbug.com/465354).
- scoped_refptr<SingleThreadTaskRunner> task_runner() { return task_runner_; }
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner() {
+ return task_runner_;
+ }
+
+ // Sets a new TaskRunner for this message loop. The message loop must already
+ // have been bound to a thread prior to this call, and the task runner must
+ // belong to that thread. Note that changing the task runner will also affect
+ // the ThreadTaskRunnerHandle for the target thread. Must be called on the
+ // thread to which the message loop is bound.
+ void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
// Enables or disables the recursive task processing. This happens in the case
// of recursive message loops. Some unwanted message loop may occurs when
@@ -521,8 +528,11 @@
scoped_refptr<internal::IncomingTaskQueue> incoming_task_queue_;
+ // A task runner which we haven't bound to a thread yet.
+ scoped_refptr<internal::MessageLoopTaskRunner> unbound_task_runner_;
+
// The task runner associated with this message loop.
- scoped_refptr<internal::MessageLoopTaskRunner> task_runner_;
+ scoped_refptr<SingleThreadTaskRunner> task_runner_;
scoped_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
template <class T, class R> friend class base::subtle::DeleteHelperInternal;
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
index 48c82c4..9c17017 100644
--- a/base/message_loop/message_loop_unittest.cc
+++ b/base/message_loop/message_loop_unittest.cc
@@ -15,6 +15,7 @@
#include "base/posix/eintr_wrapper.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
+#include "base/test/test_simple_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
@@ -1011,4 +1012,26 @@
}
#endif // defined(OS_WIN)
+TEST(MessageLoopTest, SetTaskRunner) {
+ MessageLoop loop;
+ scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner());
+
+ loop.SetTaskRunner(new_runner);
+ EXPECT_EQ(new_runner, loop.task_runner());
+ EXPECT_EQ(new_runner, ThreadTaskRunnerHandle::Get());
+}
+
+TEST(MessageLoopTest, OriginalRunnerWorks) {
+ MessageLoop loop;
+ scoped_refptr<SingleThreadTaskRunner> new_runner(new TestSimpleTaskRunner());
+ scoped_refptr<SingleThreadTaskRunner> original_runner(loop.task_runner());
+ loop.SetTaskRunner(new_runner);
+
+ scoped_refptr<Foo> foo(new Foo());
+ original_runner->PostTask(FROM_HERE,
+ Bind(&Foo::Test1ConstRef, foo.get(), "a"));
+ loop.RunUntilIdle();
+ EXPECT_EQ(1, foo->test_count());
+}
+
} // namespace base