diff options
author | Andras Becsi <andras.becsi@digia.com> | 2014-03-18 13:16:26 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-03-20 15:55:39 +0100 |
commit | 3f0f86b0caed75241fa71c95a5d73bc0164348c5 (patch) | |
tree | 92b9fb00f2e9e90b0be2262093876d4f43b6cd13 /chromium/base/message_loop | |
parent | e90d7c4b152c56919d963987e2503f9909a666d2 (diff) |
Update to new stable branch 1750
This also includes an updated ninja and chromium dependencies
needed on Windows.
Change-Id: Icd597d80ed3fa4425933c9f1334c3c2e31291c42
Reviewed-by: Zoltan Arvai <zarvai@inf.u-szeged.hu>
Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'chromium/base/message_loop')
-rw-r--r-- | chromium/base/message_loop/message_loop.cc | 134 | ||||
-rw-r--r-- | chromium/base/message_loop/message_loop.h | 22 | ||||
-rw-r--r-- | chromium/base/message_loop/message_loop_test.cc | 1069 | ||||
-rw-r--r-- | chromium/base/message_loop/message_loop_test.h | 137 | ||||
-rw-r--r-- | chromium/base/message_loop/message_loop_unittest.cc | 1151 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_android.cc | 5 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_io_ios_unittest.cc | 4 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_libevent.cc | 4 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_libevent_unittest.cc | 4 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_win.cc | 24 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_win.h | 5 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_x11.cc | 12 | ||||
-rw-r--r-- | chromium/base/message_loop/message_pump_x11.h | 3 |
13 files changed, 1417 insertions, 1157 deletions
diff --git a/chromium/base/message_loop/message_loop.cc b/chromium/base/message_loop/message_loop.cc index 87a0b631735..3f9d01c8620 100644 --- a/chromium/base/message_loop/message_loop.cc +++ b/chromium/base/message_loop/message_loop.cc @@ -144,58 +144,23 @@ MessageLoop::MessageLoop(Type type) #endif // OS_WIN message_histogram_(NULL), run_loop_(NULL) { - DCHECK(!current()) << "should only have one message loop per thread"; - lazy_tls_ptr.Pointer()->Set(this); + Init(); - incoming_task_queue_ = new internal::IncomingTaskQueue(this); - message_loop_proxy_ = - new internal::MessageLoopProxyImpl(incoming_task_queue_); - thread_task_runner_handle_.reset( - new ThreadTaskRunnerHandle(message_loop_proxy_)); + pump_.reset(CreateMessagePumpForType(type)); +} -// TODO(rvargas): Get rid of the OS guards. +MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump) + : pump_(pump.Pass()), + type_(TYPE_CUSTOM), + exception_restoration_(false), + nestable_tasks_allowed_(true), #if defined(OS_WIN) -#define MESSAGE_PUMP_UI new MessagePumpForUI() -#define MESSAGE_PUMP_IO new MessagePumpForIO() -#elif defined(OS_IOS) -#define MESSAGE_PUMP_UI MessagePumpMac::Create() -#define MESSAGE_PUMP_IO new MessagePumpIOSForIO() -#elif defined(OS_MACOSX) -#define MESSAGE_PUMP_UI MessagePumpMac::Create() -#define MESSAGE_PUMP_IO new MessagePumpLibevent() -#elif defined(OS_NACL) -// Currently NaCl doesn't have a UI MessageLoop. -// TODO(abarth): Figure out if we need this. -#define MESSAGE_PUMP_UI NULL -// ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and -// doesn't require extra support for watching file descriptors. -#define MESSAGE_PUMP_IO new MessagePumpDefault() -#elif defined(OS_POSIX) // POSIX but not MACOSX. -#define MESSAGE_PUMP_UI new MessagePumpForUI() -#define MESSAGE_PUMP_IO new MessagePumpLibevent() -#else -#error Not implemented -#endif - - if (type_ == TYPE_UI) { - if (message_pump_for_ui_factory_) - pump_.reset(message_pump_for_ui_factory_()); - else - pump_.reset(MESSAGE_PUMP_UI); - } else if (type_ == TYPE_IO) { - pump_.reset(MESSAGE_PUMP_IO); -#if defined(TOOLKIT_GTK) - } else if (type_ == TYPE_GPU) { - pump_.reset(new MessagePumpX11()); -#endif -#if defined(OS_ANDROID) - } else if (type_ == TYPE_JAVA) { - pump_.reset(MESSAGE_PUMP_UI); -#endif - } else { - DCHECK_EQ(TYPE_DEFAULT, type_); - pump_.reset(new MessagePumpDefault()); - } + os_modal_loop_(false), +#endif // OS_WIN + message_histogram_(NULL), + run_loop_(NULL) { + DCHECK(pump_.get()); + Init(); } MessageLoop::~MessageLoop() { @@ -257,6 +222,51 @@ bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) { return true; } +// static +MessagePump* MessageLoop::CreateMessagePumpForType(Type type) { +// TODO(rvargas): Get rid of the OS guards. +#if defined(OS_WIN) +#define MESSAGE_PUMP_UI new MessagePumpForUI() +#define MESSAGE_PUMP_IO new MessagePumpForIO() +#elif defined(OS_IOS) +#define MESSAGE_PUMP_UI MessagePumpMac::Create() +#define MESSAGE_PUMP_IO new MessagePumpIOSForIO() +#elif defined(OS_MACOSX) +#define MESSAGE_PUMP_UI MessagePumpMac::Create() +#define MESSAGE_PUMP_IO new MessagePumpLibevent() +#elif defined(OS_NACL) +// Currently NaCl doesn't have a UI MessageLoop. +// TODO(abarth): Figure out if we need this. +#define MESSAGE_PUMP_UI NULL +// ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and +// doesn't require extra support for watching file descriptors. +#define MESSAGE_PUMP_IO new MessagePumpDefault() +#elif defined(OS_POSIX) // POSIX but not MACOSX. +#define MESSAGE_PUMP_UI new MessagePumpForUI() +#define MESSAGE_PUMP_IO new MessagePumpLibevent() +#else +#error Not implemented +#endif + + if (type == MessageLoop::TYPE_UI) { + if (message_pump_for_ui_factory_) + return message_pump_for_ui_factory_(); + return MESSAGE_PUMP_UI; + } + if (type == MessageLoop::TYPE_IO) + return MESSAGE_PUMP_IO; +#if defined(TOOLKIT_GTK) + if (type == MessageLoop::TYPE_GPU) + return new MessagePumpX11(); +#endif +#if defined(OS_ANDROID) + if (type == MessageLoop::TYPE_JAVA) + return MESSAGE_PUMP_UI; +#endif + DCHECK_EQ(MessageLoop::TYPE_DEFAULT, type); + return new MessagePumpDefault(); +} + void MessageLoop::AddDestructionObserver( DestructionObserver* destruction_observer) { DCHECK_EQ(this, current()); @@ -348,13 +358,12 @@ Closure MessageLoop::QuitWhenIdleClosure() { } void MessageLoop::SetNestableTasksAllowed(bool allowed) { - if (nestable_tasks_allowed_ != allowed) { - nestable_tasks_allowed_ = allowed; - if (!nestable_tasks_allowed_) - return; - // Start the native pump if we are not already pumping. + if (allowed) { + // Kick the native pump just in case we enter a OS-driven nested message + // loop. pump_->ScheduleWork(); } + nestable_tasks_allowed_ = allowed; } bool MessageLoop::NestableTasksAllowed() const { @@ -397,6 +406,17 @@ void MessageLoop::LockWaitUnLockForTesting(WaitableEvent* caller_wait, //------------------------------------------------------------------------------ +void MessageLoop::Init() { + DCHECK(!current()) << "should only have one message loop per thread"; + lazy_tls_ptr.Pointer()->Set(this); + + incoming_task_queue_ = new internal::IncomingTaskQueue(this); + message_loop_proxy_ = + new internal::MessageLoopProxyImpl(incoming_task_queue_); + thread_task_runner_handle_.reset( + new ThreadTaskRunnerHandle(message_loop_proxy_)); +} + // Runs the loop in two different SEH modes: // enable_SEH_restoration_ = false : any unhandled exception goes to the last // one that calls SetUnhandledExceptionFilter(). @@ -695,12 +715,6 @@ void MessageLoop::ReleaseSoonInternal( //------------------------------------------------------------------------------ // MessageLoopForUI -#if defined(OS_WIN) -void MessageLoopForUI::DidProcessMessage(const MSG& message) { - pump_win()->DidProcessMessage(message); -} -#endif // defined(OS_WIN) - #if defined(OS_ANDROID) void MessageLoopForUI::Start() { // No Histogram support for UI message loop as it is managed by Java side diff --git a/chromium/base/message_loop/message_loop.h b/chromium/base/message_loop/message_loop.h index 3520b72516f..e307d365a00 100644 --- a/chromium/base/message_loop/message_loop.h +++ b/chromium/base/message_loop/message_loop.h @@ -128,9 +128,13 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { // TYPE_JAVA behaves in essence like TYPE_UI, except during construction // where it does not use the main thread specific pump factory. // + // TYPE_CUSTOM + // MessagePump was supplied to constructor. + // enum Type { TYPE_DEFAULT, TYPE_UI, + TYPE_CUSTOM, #if defined(TOOLKIT_GTK) TYPE_GPU, #endif @@ -143,6 +147,9 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { // Normally, it is not necessary to instantiate a MessageLoop. Instead, it // is typical to make use of the current thread's MessageLoop instance. explicit MessageLoop(Type type = TYPE_DEFAULT); + // Creates a TYPE_CUSTOM MessageLoop with the supplied MessagePump, which must + // be non-NULL. + explicit MessageLoop(scoped_ptr<base::MessagePump> pump); virtual ~MessageLoop(); // Returns the MessageLoop object for the current thread, or null if none. @@ -156,6 +163,12 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { // was successfully registered. static bool InitMessagePumpForUIFactory(MessagePumpFactory* factory); + // Creates the default MessagePump based on |type|. Caller owns return + // value. + // TODO(sky): convert this and InitMessagePumpForUIFactory() to return a + // scoped_ptr. + static MessagePump* CreateMessagePumpForType(Type type); + // A DestructionObserver is notified when the current MessageLoop is being // destroyed. These observers are notified prior to MessageLoop::current() // being changed to return NULL. This gives interested parties the chance to @@ -442,6 +455,9 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { friend class internal::IncomingTaskQueue; friend class RunLoop; + // Configures various members for the two constructors. + void Init(); + // A function to encapsulate all the exception handling capability in the // stacks around the running of a main message loop. It will run the message // loop in a SEH try block or not depending on the set_SEH_restoration() @@ -504,7 +520,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { virtual void GetQueueingInformation(size_t* queue_size, TimeDelta* queueing_delay) OVERRIDE; - Type type_; + const Type type_; // A list of tasks that need to be processed by this instance. Note that // this queue is only accessed (push/pop) by our current thread. @@ -586,10 +602,6 @@ class BASE_EXPORT MessageLoopForUI : public MessageLoop { return static_cast<MessageLoopForUI*>(loop); } -#if defined(OS_WIN) - void DidProcessMessage(const MSG& message); -#endif // defined(OS_WIN) - #if defined(OS_IOS) // On iOS, the main message loop cannot be Run(). Instead call Attach(), // which connects this MessageLoop to the UI thread's CFRunLoop and allows diff --git a/chromium/base/message_loop/message_loop_test.cc b/chromium/base/message_loop/message_loop_test.cc new file mode 100644 index 00000000000..9ac5b72d374 --- /dev/null +++ b/chromium/base/message_loop/message_loop_test.cc @@ -0,0 +1,1069 @@ +// 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/message_loop/message_loop_test.h" + +#include "base/bind.h" +#include "base/memory/ref_counted.h" +#include "base/run_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" + +namespace base { +namespace test { + +namespace { + +class Foo : public RefCounted<Foo> { + public: + Foo() : test_count_(0) { + } + + void Test0() { + ++test_count_; + } + + void Test1ConstRef(const std::string& a) { + ++test_count_; + result_.append(a); + } + + void Test1Ptr(std::string* a) { + ++test_count_; + result_.append(*a); + } + + void Test1Int(int a) { + test_count_ += a; + } + + void Test2Ptr(std::string* a, std::string* b) { + ++test_count_; + result_.append(*a); + result_.append(*b); + } + + void Test2Mixed(const std::string& a, std::string* b) { + ++test_count_; + result_.append(a); + result_.append(*b); + } + + int test_count() const { return test_count_; } + const std::string& result() const { return result_; } + + private: + friend class RefCounted<Foo>; + + ~Foo() {} + + int test_count_; + std::string result_; + + DISALLOW_COPY_AND_ASSIGN(Foo); +}; + +// This function runs slowly to simulate a large amount of work being done. +void SlowFunc(TimeDelta pause, int* quit_counter) { + PlatformThread::Sleep(pause); + if (--(*quit_counter) == 0) + MessageLoop::current()->QuitWhenIdle(); +} + +// This function records the time when Run was called in a Time object, which is +// useful for building a variety of MessageLoop tests. +// TODO(sky): remove? +void RecordRunTimeFunc(Time* run_time, int* quit_counter) { + *run_time = Time::Now(); + + // Cause our Run function to take some time to execute. As a result we can + // count on subsequent RecordRunTimeFunc()s running at a future time, + // without worry about the resolution of our system clock being an issue. + SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter); +} + +} // namespace + +void RunTest_PostTask(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + // Add tests to message loop + scoped_refptr<Foo> foo(new Foo()); + std::string a("a"), b("b"), c("c"), d("d"); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test0, foo.get())); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test1ConstRef, foo.get(), a)); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test1Ptr, foo.get(), &b)); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test1Int, foo.get(), 100)); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test2Ptr, foo.get(), &a, &c)); + + // TryPost with no contention. It must succeed. + EXPECT_TRUE(MessageLoop::current()->TryPostTask(FROM_HERE, Bind( + &Foo::Test2Mixed, foo.get(), a, &d))); + + // TryPost with simulated contention. It must fail. We wait for a helper + // thread to lock the queue, we TryPost on this thread and finally we + // signal the helper to unlock and exit. + WaitableEvent wait(true, false); + WaitableEvent signal(true, false); + Thread thread("RunTest_PostTask_helper"); + thread.Start(); + thread.message_loop()->PostTask( + FROM_HERE, + Bind(&MessageLoop::LockWaitUnLockForTesting, + base::Unretained(MessageLoop::current()), + &wait, + &signal)); + + wait.Wait(); + EXPECT_FALSE(MessageLoop::current()->TryPostTask(FROM_HERE, Bind( + &Foo::Test2Mixed, foo.get(), a, &d))); + signal.Signal(); + + // After all tests, post a message that will shut down the message loop + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &MessageLoop::Quit, Unretained(MessageLoop::current()))); + + // Now kick things off + MessageLoop::current()->Run(); + + EXPECT_EQ(foo->test_count(), 105); + EXPECT_EQ(foo->result(), "abacad"); +} + +void RunTest_PostTask_SEH(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + // Add tests to message loop + scoped_refptr<Foo> foo(new Foo()); + std::string a("a"), b("b"), c("c"), d("d"); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test0, foo.get())); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test1ConstRef, foo.get(), a)); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test1Ptr, foo.get(), &b)); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test1Int, foo.get(), 100)); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test2Ptr, foo.get(), &a, &c)); + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &Foo::Test2Mixed, foo.get(), a, &d)); + + // After all tests, post a message that will shut down the message loop + MessageLoop::current()->PostTask(FROM_HERE, Bind( + &MessageLoop::Quit, Unretained(MessageLoop::current()))); + + // Now kick things off with the SEH block active. + MessageLoop::current()->set_exception_restoration(true); + MessageLoop::current()->Run(); + MessageLoop::current()->set_exception_restoration(false); + + EXPECT_EQ(foo->test_count(), 105); + EXPECT_EQ(foo->result(), "abacad"); +} + +void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + // Test that PostDelayedTask results in a delayed task. + + const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); + + int num_tasks = 1; + Time run_time; + + loop.PostDelayedTask( + FROM_HERE, Bind(&RecordRunTimeFunc, &run_time, &num_tasks), + kDelay); + + Time time_before_run = Time::Now(); + loop.Run(); + Time time_after_run = Time::Now(); + + EXPECT_EQ(0, num_tasks); + EXPECT_LT(kDelay, time_after_run - time_before_run); +} + +void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + // Test that two tasks with different delays run in the right order. + int num_tasks = 2; + Time run_time1, run_time2; + + loop.PostDelayedTask( + FROM_HERE, + Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), + TimeDelta::FromMilliseconds(200)); + // If we get a large pause in execution (due to a context switch) here, this + // test could fail. + loop.PostDelayedTask( + FROM_HERE, + Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), + TimeDelta::FromMilliseconds(10)); + + loop.Run(); + EXPECT_EQ(0, num_tasks); + + EXPECT_TRUE(run_time2 < run_time1); +} + +void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + // Test that two tasks with the same delay run in the order in which they + // were posted. + // + // NOTE: This is actually an approximate test since the API only takes a + // "delay" parameter, so we are not exactly simulating two tasks that get + // posted at the exact same time. It would be nice if the API allowed us to + // specify the desired run time. + + const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); + + int num_tasks = 2; + Time run_time1, run_time2; + + loop.PostDelayedTask( + FROM_HERE, + Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay); + loop.PostDelayedTask( + FROM_HERE, + Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay); + + loop.Run(); + EXPECT_EQ(0, num_tasks); + + EXPECT_TRUE(run_time1 < run_time2); +} + +void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + // Test that a delayed task still runs after a normal tasks even if the + // normal tasks take a long time to run. + + const TimeDelta kPause = TimeDelta::FromMilliseconds(50); + + int num_tasks = 2; + Time run_time; + + loop.PostTask(FROM_HERE, Bind(&SlowFunc, kPause, &num_tasks)); + loop.PostDelayedTask( + FROM_HERE, + Bind(&RecordRunTimeFunc, &run_time, &num_tasks), + TimeDelta::FromMilliseconds(10)); + + Time time_before_run = Time::Now(); + loop.Run(); + Time time_after_run = Time::Now(); + + EXPECT_EQ(0, num_tasks); + + EXPECT_LT(kPause, time_after_run - time_before_run); +} + +void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + // Test that a delayed task still runs after a pile of normal tasks. The key + // difference between this test and the previous one is that here we return + // the MessageLoop a lot so we give the MessageLoop plenty of opportunities + // to maybe run the delayed task. It should know not to do so until the + // delayed task's delay has passed. + + int num_tasks = 11; + Time run_time1, run_time2; + + // Clutter the ML with tasks. + for (int i = 1; i < num_tasks; ++i) + loop.PostTask(FROM_HERE, + Bind(&RecordRunTimeFunc, &run_time1, &num_tasks)); + + loop.PostDelayedTask( + FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), + TimeDelta::FromMilliseconds(1)); + + loop.Run(); + EXPECT_EQ(0, num_tasks); + + EXPECT_TRUE(run_time2 > run_time1); +} + +void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + // Test that the interval of the timer, used to run the next delayed task, is + // set to a value corresponding to when the next delayed task should run. + + // By setting num_tasks to 1, we ensure that the first task to run causes the + // run loop to exit. + int num_tasks = 1; + Time run_time1, run_time2; + + loop.PostDelayedTask( + FROM_HERE, + Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), + TimeDelta::FromSeconds(1000)); + loop.PostDelayedTask( + FROM_HERE, + Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), + TimeDelta::FromMilliseconds(10)); + + Time start_time = Time::Now(); + + loop.Run(); + EXPECT_EQ(0, num_tasks); + + // Ensure that we ran in far less time than the slower timer. + TimeDelta total_time = Time::Now() - start_time; + EXPECT_GT(5000, total_time.InMilliseconds()); + + // In case both timers somehow run at nearly the same time, sleep a little + // and then run all pending to force them both to have run. This is just + // encouraging flakiness if there is any. + PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); + RunLoop().RunUntilIdle(); + + EXPECT_TRUE(run_time1.is_null()); + EXPECT_FALSE(run_time2.is_null()); +} + +// This is used to inject a test point for recording the destructor calls for +// Closure objects send to MessageLoop::PostTask(). It is awkward usage since we +// are trying to hook the actual destruction, which is not a common operation. +class RecordDeletionProbe : public RefCounted<RecordDeletionProbe> { + public: + RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted) + : post_on_delete_(post_on_delete), was_deleted_(was_deleted) { + } + void Run() {} + + private: + friend class RefCounted<RecordDeletionProbe>; + + ~RecordDeletionProbe() { + *was_deleted_ = true; + if (post_on_delete_.get()) + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&RecordDeletionProbe::Run, post_on_delete_.get())); + } + + scoped_refptr<RecordDeletionProbe> post_on_delete_; + bool* was_deleted_; +}; + +void RunTest_EnsureDeletion(MessagePumpFactory factory) { + bool a_was_deleted = false; + bool b_was_deleted = false; + { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + loop.PostTask( + FROM_HERE, Bind(&RecordDeletionProbe::Run, + new RecordDeletionProbe(NULL, &a_was_deleted))); + // TODO(ajwong): Do we really need 1000ms here? + loop.PostDelayedTask( + FROM_HERE, Bind(&RecordDeletionProbe::Run, + new RecordDeletionProbe(NULL, &b_was_deleted)), + TimeDelta::FromMilliseconds(1000)); + } + EXPECT_TRUE(a_was_deleted); + EXPECT_TRUE(b_was_deleted); +} + +void RunTest_EnsureDeletion_Chain(MessagePumpFactory factory) { + bool a_was_deleted = false; + bool b_was_deleted = false; + bool c_was_deleted = false; + { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + // The scoped_refptr for each of the below is held either by the chained + // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback. + RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted); + RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted); + RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted); + loop.PostTask(FROM_HERE, Bind(&RecordDeletionProbe::Run, c)); + } + EXPECT_TRUE(a_was_deleted); + EXPECT_TRUE(b_was_deleted); + EXPECT_TRUE(c_was_deleted); +} + +void NestingFunc(int* depth) { + if (*depth > 0) { + *depth -= 1; + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&NestingFunc, depth)); + + MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoop::current()->Run(); + } + MessageLoop::current()->QuitWhenIdle(); +} + +void RunTest_Nesting(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + int depth = 100; + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&NestingFunc, &depth)); + MessageLoop::current()->Run(); + EXPECT_EQ(depth, 0); +} + +enum TaskType { + MESSAGEBOX, + ENDDIALOG, + RECURSIVE, + TIMEDMESSAGELOOP, + QUITMESSAGELOOP, + ORDERED, + PUMPS, + SLEEP, + RUNS, +}; + +struct TaskItem { + TaskItem(TaskType t, int c, bool s) + : type(t), + cookie(c), + start(s) { + } + + TaskType type; + int cookie; + bool start; + + bool operator == (const TaskItem& other) const { + return type == other.type && cookie == other.cookie && start == other.start; + } +}; + +std::ostream& operator <<(std::ostream& os, TaskType type) { + switch (type) { + case MESSAGEBOX: os << "MESSAGEBOX"; break; + case ENDDIALOG: os << "ENDDIALOG"; break; + case RECURSIVE: os << "RECURSIVE"; break; + case TIMEDMESSAGELOOP: os << "TIMEDMESSAGELOOP"; break; + case QUITMESSAGELOOP: os << "QUITMESSAGELOOP"; break; + case ORDERED: os << "ORDERED"; break; + case PUMPS: os << "PUMPS"; break; + case SLEEP: os << "SLEEP"; break; + default: + NOTREACHED(); + os << "Unknown TaskType"; + break; + } + return os; +} + +std::ostream& operator <<(std::ostream& os, const TaskItem& item) { + if (item.start) + return os << item.type << " " << item.cookie << " starts"; + else + return os << item.type << " " << item.cookie << " ends"; +} + +class TaskList { + public: + void RecordStart(TaskType type, int cookie) { + TaskItem item(type, cookie, true); + DVLOG(1) << item; + task_list_.push_back(item); + } + + void RecordEnd(TaskType type, int cookie) { + TaskItem item(type, cookie, false); + DVLOG(1) << item; + task_list_.push_back(item); + } + + size_t Size() { + return task_list_.size(); + } + + TaskItem Get(int n) { + return task_list_[n]; + } + + private: + std::vector<TaskItem> task_list_; +}; + +void RecursiveFunc(TaskList* order, int cookie, int depth, + bool is_reentrant) { + order->RecordStart(RECURSIVE, cookie); + if (depth > 0) { + if (is_reentrant) + MessageLoop::current()->SetNestableTasksAllowed(true); + MessageLoop::current()->PostTask( + FROM_HERE, + Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant)); + } + order->RecordEnd(RECURSIVE, cookie); +} + +void QuitFunc(TaskList* order, int cookie) { + order->RecordStart(QUITMESSAGELOOP, cookie); + MessageLoop::current()->QuitWhenIdle(); + order->RecordEnd(QUITMESSAGELOOP, cookie); +} +void RunTest_RecursiveDenial1(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); + TaskList order; + MessageLoop::current()->PostTask( + FROM_HERE, + Bind(&RecursiveFunc, &order, 1, 2, false)); + MessageLoop::current()->PostTask( + FROM_HERE, + Bind(&RecursiveFunc, &order, 2, 2, false)); + MessageLoop::current()->PostTask( + FROM_HERE, + Bind(&QuitFunc, &order, 3)); + + MessageLoop::current()->Run(); + + // FIFO order. + ASSERT_EQ(14U, order.Size()); + EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); + EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); + EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); + EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); + EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); + EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); + EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); + EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); + EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); + EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); + EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); + EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); + EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); + EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); +} + +void RecursiveSlowFunc(TaskList* order, int cookie, int depth, + bool is_reentrant) { + RecursiveFunc(order, cookie, depth, is_reentrant); + PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); +} + +void OrderedFunc(TaskList* order, int cookie) { + order->RecordStart(ORDERED, cookie); + order->RecordEnd(ORDERED, cookie); +} + +void RunTest_RecursiveDenial3(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); + TaskList order; + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&RecursiveSlowFunc, &order, 1, 2, false)); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&RecursiveSlowFunc, &order, 2, 2, false)); + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + Bind(&OrderedFunc, &order, 3), + TimeDelta::FromMilliseconds(5)); + MessageLoop::current()->PostDelayedTask( + FROM_HERE, + Bind(&QuitFunc, &order, 4), + TimeDelta::FromMilliseconds(5)); + + MessageLoop::current()->Run(); + + // FIFO order. + ASSERT_EQ(16U, order.Size()); + EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); + EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); + EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); + EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); + EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true)); + EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false)); + EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 3, true)); + EXPECT_EQ(order.Get(7), TaskItem(ORDERED, 3, false)); + EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); + EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); + EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true)); + EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false)); + EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true)); + EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false)); + EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true)); + EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false)); +} + +void RunTest_RecursiveSupport1(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, true)); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, true)); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&QuitFunc, &order, 3)); + + MessageLoop::current()->Run(); + + // FIFO order. + ASSERT_EQ(14U, order.Size()); + EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); + EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); + EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); + EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); + EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); + EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); + EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); + EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); + EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); + EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); + EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); + EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); + EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); + EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); +} + +// Tests that non nestable tasks run in FIFO if there are no nested loops. +void RunTest_NonNestableWithNoNesting(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + + MessageLoop::current()->PostNonNestableTask( + FROM_HERE, + Bind(&OrderedFunc, &order, 1)); + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&OrderedFunc, &order, 2)); + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&QuitFunc, &order, 3)); + MessageLoop::current()->Run(); + + // FIFO order. + ASSERT_EQ(6U, order.Size()); + EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true)); + EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false)); + EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true)); + EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false)); + EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); + EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); +} + +void FuncThatPumps(TaskList* order, int cookie) { + order->RecordStart(PUMPS, cookie); + { + MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); + RunLoop().RunUntilIdle(); + } + order->RecordEnd(PUMPS, cookie); +} + +void SleepFunc(TaskList* order, int cookie, TimeDelta delay) { + order->RecordStart(SLEEP, cookie); + PlatformThread::Sleep(delay); + order->RecordEnd(SLEEP, cookie); +} + +// Tests that non nestable tasks don't run when there's code in the call stack. +void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory, + bool use_delayed) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + + MessageLoop::current()->PostTask( + FROM_HERE, + Bind(&FuncThatPumps, &order, 1)); + if (use_delayed) { + MessageLoop::current()->PostNonNestableDelayedTask( + FROM_HERE, + Bind(&OrderedFunc, &order, 2), + TimeDelta::FromMilliseconds(1)); + } else { + MessageLoop::current()->PostNonNestableTask( + FROM_HERE, + Bind(&OrderedFunc, &order, 2)); + } + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&OrderedFunc, &order, 3)); + MessageLoop::current()->PostTask( + FROM_HERE, + Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50))); + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&OrderedFunc, &order, 5)); + if (use_delayed) { + MessageLoop::current()->PostNonNestableDelayedTask( + FROM_HERE, + Bind(&QuitFunc, &order, 6), + TimeDelta::FromMilliseconds(2)); + } else { + MessageLoop::current()->PostNonNestableTask( + FROM_HERE, + Bind(&QuitFunc, &order, 6)); + } + + MessageLoop::current()->Run(); + + // FIFO order. + ASSERT_EQ(12U, order.Size()); + EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true)); + EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true)); + EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false)); + EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true)); + EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false)); + EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true)); + EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false)); + EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false)); + EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true)); + EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false)); + EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true)); + EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false)); +} + +void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) { + order->RecordStart(RUNS, cookie); + { + MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); + run_loop->Run(); + } + order->RecordEnd(RUNS, cookie); +} + +void FuncThatQuitsNow() { + MessageLoop::current()->QuitNow(); +} +// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. +void RunTest_QuitNow(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + + RunLoop run_loop; + + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop))); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 2)); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&FuncThatQuitsNow)); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 3)); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&FuncThatQuitsNow)); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 4)); // never runs + + MessageLoop::current()->Run(); + + ASSERT_EQ(6U, order.Size()); + int task_index = 0; + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); + EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); +} + +// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. +void RunTest_RunLoopQuitTop(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + + RunLoop outer_run_loop; + RunLoop nested_run_loop; + + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); + MessageLoop::current()->PostTask( + FROM_HERE, outer_run_loop.QuitClosure()); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 2)); + MessageLoop::current()->PostTask( + FROM_HERE, nested_run_loop.QuitClosure()); + + outer_run_loop.Run(); + + ASSERT_EQ(4U, order.Size()); + int task_index = 0; + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); + EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); +} + +// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. +void RunTest_RunLoopQuitNested(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + + RunLoop outer_run_loop; + RunLoop nested_run_loop; + + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); + MessageLoop::current()->PostTask( + FROM_HERE, nested_run_loop.QuitClosure()); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 2)); + MessageLoop::current()->PostTask( + FROM_HERE, outer_run_loop.QuitClosure()); + + outer_run_loop.Run(); + + ASSERT_EQ(4U, order.Size()); + int task_index = 0; + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); + EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); +} + +// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. +void RunTest_RunLoopQuitBogus(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + + RunLoop outer_run_loop; + RunLoop nested_run_loop; + RunLoop bogus_run_loop; + + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); + MessageLoop::current()->PostTask( + FROM_HERE, bogus_run_loop.QuitClosure()); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 2)); + MessageLoop::current()->PostTask( + FROM_HERE, outer_run_loop.QuitClosure()); + MessageLoop::current()->PostTask( + FROM_HERE, nested_run_loop.QuitClosure()); + + outer_run_loop.Run(); + + ASSERT_EQ(4U, order.Size()); + int task_index = 0; + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); + EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); +} + +// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. +void RunTest_RunLoopQuitDeep(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + + RunLoop outer_run_loop; + RunLoop nested_loop1; + RunLoop nested_loop2; + RunLoop nested_loop3; + RunLoop nested_loop4; + + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&FuncThatRuns, &order, 1, Unretained(&nested_loop1))); + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&FuncThatRuns, &order, 2, Unretained(&nested_loop2))); + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&FuncThatRuns, &order, 3, Unretained(&nested_loop3))); + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&FuncThatRuns, &order, 4, Unretained(&nested_loop4))); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 5)); + MessageLoop::current()->PostTask( + FROM_HERE, outer_run_loop.QuitClosure()); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 6)); + MessageLoop::current()->PostTask( + FROM_HERE, nested_loop1.QuitClosure()); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 7)); + MessageLoop::current()->PostTask( + FROM_HERE, nested_loop2.QuitClosure()); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 8)); + MessageLoop::current()->PostTask( + FROM_HERE, nested_loop3.QuitClosure()); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 9)); + MessageLoop::current()->PostTask( + FROM_HERE, nested_loop4.QuitClosure()); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 10)); + + outer_run_loop.Run(); + + ASSERT_EQ(18U, order.Size()); + int task_index = 0; + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); + EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); +} + +// Tests RunLoopQuit works before RunWithID. +void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + + RunLoop run_loop; + + run_loop.Quit(); + + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 1)); // never runs + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs + + run_loop.Run(); + + ASSERT_EQ(0U, order.Size()); +} + +// Tests RunLoopQuit works during RunWithID. +void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + + RunLoop run_loop; + + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 1)); + MessageLoop::current()->PostTask( + FROM_HERE, run_loop.QuitClosure()); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 2)); // never runs + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs + + run_loop.Run(); + + ASSERT_EQ(2U, order.Size()); + int task_index = 0; + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, false)); + EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); +} + +// Tests RunLoopQuit works after RunWithID. +void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory) { + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + + TaskList order; + + RunLoop run_loop; + + MessageLoop::current()->PostTask(FROM_HERE, + Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop))); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 2)); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&FuncThatQuitsNow)); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 3)); + MessageLoop::current()->PostTask( + FROM_HERE, run_loop.QuitClosure()); // has no affect + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&OrderedFunc, &order, 4)); + MessageLoop::current()->PostTask( + FROM_HERE, Bind(&FuncThatQuitsNow)); + + RunLoop outer_run_loop; + outer_run_loop.Run(); + + ASSERT_EQ(8U, order.Size()); + int task_index = 0; + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, true)); + EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, false)); + EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); +} + +void PostNTasksThenQuit(int posts_remaining) { + if (posts_remaining > 1) { + MessageLoop::current()->PostTask( + FROM_HERE, + Bind(&PostNTasksThenQuit, posts_remaining - 1)); + } else { + MessageLoop::current()->QuitWhenIdle(); + } +} + +// There was a bug in the MessagePumpGLib where posting tasks recursively +// caused the message loop to hang, due to the buffer of the internal pipe +// becoming full. Test all MessageLoop types to ensure this issue does not +// exist in other MessagePumps. +// +// On Linux, the pipe buffer size is 64KiB by default. The bug caused one +// byte accumulated in the pipe per two posts, so we should repeat 128K +// times to reproduce the bug. +void RunTest_RecursivePosts(MessagePumpFactory factory) { + const int kNumTimes = 1 << 17; + scoped_ptr<MessagePump> pump(factory()); + MessageLoop loop(pump.Pass()); + loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumTimes)); + loop.Run(); +} + +} // namespace test +} // namespace base diff --git a/chromium/base/message_loop/message_loop_test.h b/chromium/base/message_loop/message_loop_test.h new file mode 100644 index 00000000000..5d1a4f5ac27 --- /dev/null +++ b/chromium/base/message_loop/message_loop_test.h @@ -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. + +#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_TEST_H_ +#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_TEST_H_ + +#include "base/message_loop/message_loop.h" +#include "testing/gtest/include/gtest/gtest.h" + +// This file consists of tests meant to exercise the combination of MessageLoop +// and MessagePump. To use these define the macro RUN_MESSAGE_LOOP_TESTS using +// an ID appropriate for your MessagePump, eg +// RUN_MESSAGE_LOOP_TESTS(UI, factory). Factory is a function called to create +// the MessagePump. +namespace base { +namespace test { + +typedef MessageLoop::MessagePumpFactory MessagePumpFactory; + +void RunTest_PostTask(MessagePumpFactory factory); +void RunTest_PostTask_SEH(MessagePumpFactory factory); +void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory); +void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory); +void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory); +void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory); +void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory); +void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory); +void RunTest_EnsureDeletion(MessagePumpFactory factory); +void RunTest_EnsureDeletion_Chain(MessagePumpFactory factory); +void RunTest_Nesting(MessagePumpFactory factory); +void RunTest_RecursiveDenial1(MessagePumpFactory factory); +void RunTest_RecursiveDenial3(MessagePumpFactory factory); +void RunTest_RecursiveSupport1(MessagePumpFactory factory); +void RunTest_NonNestableWithNoNesting(MessagePumpFactory factory); +void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory, + bool use_delayed); +void RunTest_QuitNow(MessagePumpFactory factory); +void RunTest_RunLoopQuitTop(MessagePumpFactory factory); +void RunTest_RunLoopQuitNested(MessagePumpFactory factory); +void RunTest_RunLoopQuitBogus(MessagePumpFactory factory); +void RunTest_RunLoopQuitDeep(MessagePumpFactory factory); +void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory); +void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory); +void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory); +void RunTest_RecursivePosts(MessagePumpFactory factory); + +} // namespace test +} // namespace base + +#define RUN_MESSAGE_LOOP_TESTS(id, factory) \ + TEST(MessageLoopTestType##id, PostTask) { \ + base::test::RunTest_PostTask(factory); \ + } \ + TEST(MessageLoopTestType##id, PostTask_SEH) { \ + base::test::RunTest_PostTask_SEH(factory); \ + } \ + TEST(MessageLoopTestType##id, PostDelayedTask_Basic) { \ + base::test::RunTest_PostDelayedTask_Basic(factory); \ + } \ + TEST(MessageLoopTestType##id, PostDelayedTask_InDelayOrder) { \ + base::test::RunTest_PostDelayedTask_InDelayOrder(factory); \ + } \ + TEST(MessageLoopTestType##id, PostDelayedTask_InPostOrder) { \ + base::test::RunTest_PostDelayedTask_InPostOrder(factory); \ + } \ + TEST(MessageLoopTestType##id, PostDelayedTask_InPostOrder_2) { \ + base::test::RunTest_PostDelayedTask_InPostOrder_2(factory); \ + } \ + TEST(MessageLoopTestType##id, PostDelayedTask_InPostOrder_3) { \ + base::test::RunTest_PostDelayedTask_InPostOrder_3(factory); \ + } \ + TEST(MessageLoopTestType##id, PostDelayedTask_SharedTimer) { \ + base::test::RunTest_PostDelayedTask_SharedTimer(factory); \ + } \ + /* TODO(darin): MessageLoop does not support deleting all tasks in the */ \ + /* destructor. */ \ + /* Fails, http://crbug.com/50272. */ \ + TEST(MessageLoopTestType##id, DISABLED_EnsureDeletion) { \ + base::test::RunTest_EnsureDeletion(factory); \ + } \ + /* TODO(darin): MessageLoop does not support deleting all tasks in the */ \ + /* destructor. */ \ + /* Fails, http://crbug.com/50272. */ \ + TEST(MessageLoopTestType##id, DISABLED_EnsureDeletion_Chain) { \ + base::test::RunTest_EnsureDeletion_Chain(factory); \ + } \ + TEST(MessageLoopTestType##id, Nesting) { \ + base::test::RunTest_Nesting(factory); \ + } \ + TEST(MessageLoopTestType##id, RecursiveDenial1) { \ + base::test::RunTest_RecursiveDenial1(factory); \ + } \ + TEST(MessageLoopTestType##id, RecursiveDenial3) { \ + base::test::RunTest_RecursiveDenial3(factory); \ + } \ + TEST(MessageLoopTestType##id, RecursiveSupport1) { \ + base::test::RunTest_RecursiveSupport1(factory); \ + } \ + TEST(MessageLoopTestType##id, NonNestableWithNoNesting) { \ + base::test::RunTest_NonNestableWithNoNesting(factory); \ + } \ + TEST(MessageLoopTestType##id, NonNestableInNestedLoop) { \ + base::test::RunTest_NonNestableInNestedLoop(factory, false); \ + } \ + TEST(MessageLoopTestType##id, NonNestableDelayedInNestedLoop) { \ + base::test::RunTest_NonNestableInNestedLoop(factory, true); \ + } \ + TEST(MessageLoopTestType##id, QuitNow) { \ + base::test::RunTest_QuitNow(factory); \ + } \ + TEST(MessageLoopTestType##id, RunLoopQuitTop) { \ + base::test::RunTest_RunLoopQuitTop(factory); \ + } \ + TEST(MessageLoopTestType##id, RunLoopQuitNested) { \ + base::test::RunTest_RunLoopQuitNested(factory); \ + } \ + TEST(MessageLoopTestType##id, RunLoopQuitBogus) { \ + base::test::RunTest_RunLoopQuitBogus(factory); \ + } \ + TEST(MessageLoopTestType##id, RunLoopQuitDeep) { \ + base::test::RunTest_RunLoopQuitDeep(factory); \ + } \ + TEST(MessageLoopTestType##id, RunLoopQuitOrderBefore) { \ + base::test::RunTest_RunLoopQuitOrderBefore(factory); \ + } \ + TEST(MessageLoopTestType##id, RunLoopQuitOrderDuring) { \ + base::test::RunTest_RunLoopQuitOrderDuring(factory); \ + } \ + TEST(MessageLoopTestType##id, RunLoopQuitOrderAfter) { \ + base::test::RunTest_RunLoopQuitOrderAfter(factory); \ + } \ + TEST(MessageLoopTestType##id, RecursivePosts) { \ + base::test::RunTest_RecursivePosts(factory); \ + } \ + +#endif // BASE_MESSAGE_LOOP_MESSAGE_LOOP_TEST_H_ diff --git a/chromium/base/message_loop/message_loop_unittest.cc b/chromium/base/message_loop/message_loop_unittest.cc index ab05b3cb5ab..e6d25ecef82 100644 --- a/chromium/base/message_loop/message_loop_unittest.cc +++ b/chromium/base/message_loop/message_loop_unittest.cc @@ -11,6 +11,7 @@ #include "base/memory/ref_counted.h" #include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy_impl.h" +#include "base/message_loop/message_loop_test.h" #include "base/pending_task.h" #include "base/posix/eintr_wrapper.h" #include "base/run_loop.h" @@ -22,6 +23,8 @@ #if defined(OS_WIN) #include "base/message_loop/message_pump_win.h" +#include "base/process/memory.h" +#include "base/strings/string16.h" #include "base/win/scoped_handle.h" #endif @@ -32,6 +35,18 @@ namespace base { namespace { +MessagePump* TypeDefaultMessagePumpFactory() { + return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_DEFAULT); +} + +MessagePump* TypeIOMessagePumpFactory() { + return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_IO); +} + +MessagePump* TypeUIMessagePumpFactory() { + return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_UI); +} + class Foo : public RefCounted<Foo> { public: Foo() : test_count_(0) { @@ -79,88 +94,7 @@ class Foo : public RefCounted<Foo> { std::string result_; }; -void RunTest_PostTask(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Add tests to message loop - scoped_refptr<Foo> foo(new Foo()); - std::string a("a"), b("b"), c("c"), d("d"); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test0, foo.get())); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1ConstRef, foo.get(), a)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1Ptr, foo.get(), &b)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1Int, foo.get(), 100)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test2Ptr, foo.get(), &a, &c)); - - // TryPost with no contention. It must succeed. - EXPECT_TRUE(MessageLoop::current()->TryPostTask(FROM_HERE, Bind( - &Foo::Test2Mixed, foo.get(), a, &d))); - - // TryPost with simulated contention. It must fail. We wait for a helper - // thread to lock the queue, we TryPost on this thread and finally we - // signal the helper to unlock and exit. - WaitableEvent wait(true, false); - WaitableEvent signal(true, false); - Thread thread("RunTest_PostTask_helper"); - thread.Start(); - thread.message_loop()->PostTask( - FROM_HERE, - Bind(&MessageLoop::LockWaitUnLockForTesting, - base::Unretained(MessageLoop::current()), - &wait, - &signal)); - - wait.Wait(); - EXPECT_FALSE(MessageLoop::current()->TryPostTask(FROM_HERE, Bind( - &Foo::Test2Mixed, foo.get(), a, &d))); - signal.Signal(); - - // After all tests, post a message that will shut down the message loop - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &MessageLoop::Quit, Unretained(MessageLoop::current()))); - - // Now kick things off - MessageLoop::current()->Run(); - - EXPECT_EQ(foo->test_count(), 105); - EXPECT_EQ(foo->result(), "abacad"); -} - -void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Add tests to message loop - scoped_refptr<Foo> foo(new Foo()); - std::string a("a"), b("b"), c("c"), d("d"); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test0, foo.get())); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1ConstRef, foo.get(), a)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1Ptr, foo.get(), &b)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test1Int, foo.get(), 100)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test2Ptr, foo.get(), &a, &c)); - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &Foo::Test2Mixed, foo.get(), a, &d)); - - // After all tests, post a message that will shut down the message loop - MessageLoop::current()->PostTask(FROM_HERE, Bind( - &MessageLoop::Quit, Unretained(MessageLoop::current()))); - - // Now kick things off with the SEH block active. - MessageLoop::current()->set_exception_restoration(true); - MessageLoop::current()->Run(); - MessageLoop::current()->set_exception_restoration(false); - - EXPECT_EQ(foo->test_count(), 105); - EXPECT_EQ(foo->result(), "abacad"); -} +#if defined(OS_WIN) // This function runs slowly to simulate a large amount of work being done. static void SlowFunc(TimeDelta pause, int* quit_counter) { @@ -180,180 +114,6 @@ static void RecordRunTimeFunc(Time* run_time, int* quit_counter) { SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter); } -void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that PostDelayedTask results in a delayed task. - - const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); - - int num_tasks = 1; - Time run_time; - - loop.PostDelayedTask( - FROM_HERE, Bind(&RecordRunTimeFunc, &run_time, &num_tasks), - kDelay); - - Time time_before_run = Time::Now(); - loop.Run(); - Time time_after_run = Time::Now(); - - EXPECT_EQ(0, num_tasks); - EXPECT_LT(kDelay, time_after_run - time_before_run); -} - -void RunTest_PostDelayedTask_InDelayOrder( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that two tasks with different delays run in the right order. - int num_tasks = 2; - Time run_time1, run_time2; - - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), - TimeDelta::FromMilliseconds(200)); - // If we get a large pause in execution (due to a context switch) here, this - // test could fail. - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), - TimeDelta::FromMilliseconds(10)); - - loop.Run(); - EXPECT_EQ(0, num_tasks); - - EXPECT_TRUE(run_time2 < run_time1); -} - -void RunTest_PostDelayedTask_InPostOrder( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that two tasks with the same delay run in the order in which they - // were posted. - // - // NOTE: This is actually an approximate test since the API only takes a - // "delay" parameter, so we are not exactly simulating two tasks that get - // posted at the exact same time. It would be nice if the API allowed us to - // specify the desired run time. - - const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); - - int num_tasks = 2; - Time run_time1, run_time2; - - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay); - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay); - - loop.Run(); - EXPECT_EQ(0, num_tasks); - - EXPECT_TRUE(run_time1 < run_time2); -} - -void RunTest_PostDelayedTask_InPostOrder_2( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that a delayed task still runs after a normal tasks even if the - // normal tasks take a long time to run. - - const TimeDelta kPause = TimeDelta::FromMilliseconds(50); - - int num_tasks = 2; - Time run_time; - - loop.PostTask(FROM_HERE, Bind(&SlowFunc, kPause, &num_tasks)); - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time, &num_tasks), - TimeDelta::FromMilliseconds(10)); - - Time time_before_run = Time::Now(); - loop.Run(); - Time time_after_run = Time::Now(); - - EXPECT_EQ(0, num_tasks); - - EXPECT_LT(kPause, time_after_run - time_before_run); -} - -void RunTest_PostDelayedTask_InPostOrder_3( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that a delayed task still runs after a pile of normal tasks. The key - // difference between this test and the previous one is that here we return - // the MessageLoop a lot so we give the MessageLoop plenty of opportunities - // to maybe run the delayed task. It should know not to do so until the - // delayed task's delay has passed. - - int num_tasks = 11; - Time run_time1, run_time2; - - // Clutter the ML with tasks. - for (int i = 1; i < num_tasks; ++i) - loop.PostTask(FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time1, &num_tasks)); - - loop.PostDelayedTask( - FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), - TimeDelta::FromMilliseconds(1)); - - loop.Run(); - EXPECT_EQ(0, num_tasks); - - EXPECT_TRUE(run_time2 > run_time1); -} - -void RunTest_PostDelayedTask_SharedTimer( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - // Test that the interval of the timer, used to run the next delayed task, is - // set to a value corresponding to when the next delayed task should run. - - // By setting num_tasks to 1, we ensure that the first task to run causes the - // run loop to exit. - int num_tasks = 1; - Time run_time1, run_time2; - - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), - TimeDelta::FromSeconds(1000)); - loop.PostDelayedTask( - FROM_HERE, - Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), - TimeDelta::FromMilliseconds(10)); - - Time start_time = Time::Now(); - - loop.Run(); - EXPECT_EQ(0, num_tasks); - - // Ensure that we ran in far less time than the slower timer. - TimeDelta total_time = Time::Now() - start_time; - EXPECT_GT(5000, total_time.InMilliseconds()); - - // In case both timers somehow run at nearly the same time, sleep a little - // and then run all pending to force them both to have run. This is just - // encouraging flakiness if there is any. - PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); - RunLoop().RunUntilIdle(); - - EXPECT_TRUE(run_time1.is_null()); - EXPECT_FALSE(run_time2.is_null()); -} - -#if defined(OS_WIN) - void SubPumpFunc() { MessageLoop::current()->SetNestableTasksAllowed(true); MSG msg; @@ -407,82 +167,6 @@ void RunTest_PostDelayedTask_SharedTimer_SubPump() { EXPECT_TRUE(run_time.is_null()); } -#endif // defined(OS_WIN) - -// This is used to inject a test point for recording the destructor calls for -// Closure objects send to MessageLoop::PostTask(). It is awkward usage since we -// are trying to hook the actual destruction, which is not a common operation. -class RecordDeletionProbe : public RefCounted<RecordDeletionProbe> { - public: - RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted) - : post_on_delete_(post_on_delete), was_deleted_(was_deleted) { - } - void Run() {} - - private: - friend class RefCounted<RecordDeletionProbe>; - - ~RecordDeletionProbe() { - *was_deleted_ = true; - if (post_on_delete_.get()) - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&RecordDeletionProbe::Run, post_on_delete_.get())); - } - - scoped_refptr<RecordDeletionProbe> post_on_delete_; - bool* was_deleted_; -}; - -void RunTest_EnsureDeletion(MessageLoop::Type message_loop_type) { - bool a_was_deleted = false; - bool b_was_deleted = false; - { - MessageLoop loop(message_loop_type); - loop.PostTask( - FROM_HERE, Bind(&RecordDeletionProbe::Run, - new RecordDeletionProbe(NULL, &a_was_deleted))); - // TODO(ajwong): Do we really need 1000ms here? - loop.PostDelayedTask( - FROM_HERE, Bind(&RecordDeletionProbe::Run, - new RecordDeletionProbe(NULL, &b_was_deleted)), - TimeDelta::FromMilliseconds(1000)); - } - EXPECT_TRUE(a_was_deleted); - EXPECT_TRUE(b_was_deleted); -} - -void RunTest_EnsureDeletion_Chain(MessageLoop::Type message_loop_type) { - bool a_was_deleted = false; - bool b_was_deleted = false; - bool c_was_deleted = false; - { - MessageLoop loop(message_loop_type); - // The scoped_refptr for each of the below is held either by the chained - // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback. - RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted); - RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted); - RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted); - loop.PostTask(FROM_HERE, Bind(&RecordDeletionProbe::Run, c)); - } - EXPECT_TRUE(a_was_deleted); - EXPECT_TRUE(b_was_deleted); - EXPECT_TRUE(c_was_deleted); -} - -void NestingFunc(int* depth) { - if (*depth > 0) { - *depth -= 1; - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&NestingFunc, depth)); - - MessageLoop::current()->SetNestableTasksAllowed(true); - MessageLoop::current()->Run(); - } - MessageLoop::current()->QuitWhenIdle(); -} - -#if defined(OS_WIN) - LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) { ADD_FAILURE() << "bad exception handler"; ::ExitProcess(ex_info->ExceptionRecord->ExceptionCode); @@ -597,19 +281,7 @@ void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) { ::SetUnhandledExceptionFilter(old_SEH_filter); } -#endif // defined(OS_WIN) - -void RunTest_Nesting(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - int depth = 100; - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&NestingFunc, &depth)); - MessageLoop::current()->Run(); - EXPECT_EQ(depth, 0); -} - -const wchar_t* const kMessageBoxTitle = L"MessageLoop Unit Test"; +const wchar_t kMessageBoxTitle[] = L"MessageLoop Unit Test"; enum TaskType { MESSAGEBOX, @@ -691,14 +363,6 @@ class TaskList { std::vector<TaskItem> task_list_; }; -// Saves the order the tasks ran. -void OrderedFunc(TaskList* order, int cookie) { - order->RecordStart(ORDERED, cookie); - order->RecordEnd(ORDERED, cookie); -} - -#if defined(OS_WIN) - // MessageLoop implicitly start a "modal message loop". Modal dialog boxes, // common controls (like OpenFile) and StartDoc printing function can cause // implicit message loops. @@ -722,8 +386,6 @@ void EndDialogFunc(TaskList* order, int cookie) { } } -#endif // defined(OS_WIN) - void RecursiveFunc(TaskList* order, int cookie, int depth, bool is_reentrant) { order->RecordStart(RECURSIVE, cookie); @@ -737,25 +399,12 @@ void RecursiveFunc(TaskList* order, int cookie, int depth, order->RecordEnd(RECURSIVE, cookie); } -void RecursiveSlowFunc(TaskList* order, int cookie, int depth, - bool is_reentrant) { - RecursiveFunc(order, cookie, depth, is_reentrant); - PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); -} - void QuitFunc(TaskList* order, int cookie) { order->RecordStart(QUITMESSAGELOOP, cookie); MessageLoop::current()->QuitWhenIdle(); order->RecordEnd(QUITMESSAGELOOP, cookie); } -void SleepFunc(TaskList* order, int cookie, TimeDelta delay) { - order->RecordStart(SLEEP, cookie); - PlatformThread::Sleep(delay); - order->RecordEnd(SLEEP, cookie); -} - -#if defined(OS_WIN) void RecursiveFuncWin(MessageLoop* target, HANDLE event, bool expect_window, @@ -801,115 +450,6 @@ void RecursiveFuncWin(MessageLoop* target, } } -#endif // defined(OS_WIN) - -void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); - TaskList order; - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&RecursiveFunc, &order, 1, 2, false)); - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&RecursiveFunc, &order, 2, 2, false)); - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&QuitFunc, &order, 3)); - - MessageLoop::current()->Run(); - - // FIFO order. - ASSERT_EQ(14U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); - EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); -} - -void RunTest_RecursiveDenial3(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); - TaskList order; - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&RecursiveSlowFunc, &order, 1, 2, false)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&RecursiveSlowFunc, &order, 2, 2, false)); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - Bind(&OrderedFunc, &order, 3), - TimeDelta::FromMilliseconds(5)); - MessageLoop::current()->PostDelayedTask( - FROM_HERE, - Bind(&QuitFunc, &order, 4), - TimeDelta::FromMilliseconds(5)); - - MessageLoop::current()->Run(); - - // FIFO order. - ASSERT_EQ(16U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(7), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true)); - EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false)); -} - -void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, true)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, true)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&QuitFunc, &order, 3)); - - MessageLoop::current()->Run(); - - // FIFO order. - ASSERT_EQ(14U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); - EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); - EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); - EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); - EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); -} - -#if defined(OS_WIN) // TODO(darin): These tests need to be ported since they test critical // message loop functionality. @@ -1007,387 +547,6 @@ void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) { #endif // defined(OS_WIN) -void FuncThatPumps(TaskList* order, int cookie) { - order->RecordStart(PUMPS, cookie); - { - MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); - RunLoop().RunUntilIdle(); - } - order->RecordEnd(PUMPS, cookie); -} - -void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) { - order->RecordStart(RUNS, cookie); - { - MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); - run_loop->Run(); - } - order->RecordEnd(RUNS, cookie); -} - -void FuncThatQuitsNow() { - MessageLoop::current()->QuitNow(); -} - -// Tests that non nestable tasks run in FIFO if there are no nested loops. -void RunTest_NonNestableWithNoNesting( - MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - MessageLoop::current()->PostNonNestableTask( - FROM_HERE, - Bind(&OrderedFunc, &order, 1)); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&QuitFunc, &order, 3)); - MessageLoop::current()->Run(); - - // FIFO order. - ASSERT_EQ(6U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false)); - EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); - EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); -} - -// Tests that non nestable tasks don't run when there's code in the call stack. -void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type, - bool use_delayed) { - MessageLoop loop(message_loop_type); - - TaskList order; - - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&FuncThatPumps, &order, 1)); - if (use_delayed) { - MessageLoop::current()->PostNonNestableDelayedTask( - FROM_HERE, - Bind(&OrderedFunc, &order, 2), - TimeDelta::FromMilliseconds(1)); - } else { - MessageLoop::current()->PostNonNestableTask( - FROM_HERE, - Bind(&OrderedFunc, &order, 2)); - } - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&OrderedFunc, &order, 3)); - MessageLoop::current()->PostTask( - FROM_HERE, - Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50))); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&OrderedFunc, &order, 5)); - if (use_delayed) { - MessageLoop::current()->PostNonNestableDelayedTask( - FROM_HERE, - Bind(&QuitFunc, &order, 6), - TimeDelta::FromMilliseconds(2)); - } else { - MessageLoop::current()->PostNonNestableTask( - FROM_HERE, - Bind(&QuitFunc, &order, 6)); - } - - MessageLoop::current()->Run(); - - // FIFO order. - ASSERT_EQ(12U, order.Size()); - EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true)); - EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true)); - EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false)); - EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true)); - EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false)); - EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false)); - EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true)); - EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false)); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -void RunTest_QuitNow(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop run_loop; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop))); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 3)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 4)); // never runs - - MessageLoop::current()->Run(); - - ASSERT_EQ(6U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit works before RunWithID. -void RunTest_RunLoopQuitOrderBefore(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop run_loop; - - run_loop.Quit(); - - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 1)); // never runs - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs - - run_loop.Run(); - - ASSERT_EQ(0U, order.Size()); -} - -// Tests RunLoopQuit works during RunWithID. -void RunTest_RunLoopQuitOrderDuring(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop run_loop; - - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 1)); - MessageLoop::current()->PostTask( - FROM_HERE, run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); // never runs - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs - - run_loop.Run(); - - ASSERT_EQ(2U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit works after RunWithID. -void RunTest_RunLoopQuitOrderAfter(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop run_loop; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop))); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 3)); - MessageLoop::current()->PostTask( - FROM_HERE, run_loop.QuitClosure()); // has no affect - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 4)); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&FuncThatQuitsNow)); - - RunLoop outer_run_loop; - outer_run_loop.Run(); - - ASSERT_EQ(8U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -void RunTest_RunLoopQuitTop(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_run_loop; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); - MessageLoop::current()->PostTask( - FROM_HERE, outer_run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask( - FROM_HERE, nested_run_loop.QuitClosure()); - - outer_run_loop.Run(); - - ASSERT_EQ(4U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -void RunTest_RunLoopQuitNested(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_run_loop; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); - MessageLoop::current()->PostTask( - FROM_HERE, nested_run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask( - FROM_HERE, outer_run_loop.QuitClosure()); - - outer_run_loop.Run(); - - ASSERT_EQ(4U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -void RunTest_RunLoopQuitBogus(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_run_loop; - RunLoop bogus_run_loop; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); - MessageLoop::current()->PostTask( - FROM_HERE, bogus_run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 2)); - MessageLoop::current()->PostTask( - FROM_HERE, outer_run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, nested_run_loop.QuitClosure()); - - outer_run_loop.Run(); - - ASSERT_EQ(4U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - -// Tests RunLoopQuit only quits the corresponding MessageLoop::Run. -void RunTest_RunLoopQuitDeep(MessageLoop::Type message_loop_type) { - MessageLoop loop(message_loop_type); - - TaskList order; - - RunLoop outer_run_loop; - RunLoop nested_loop1; - RunLoop nested_loop2; - RunLoop nested_loop3; - RunLoop nested_loop4; - - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 1, Unretained(&nested_loop1))); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 2, Unretained(&nested_loop2))); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 3, Unretained(&nested_loop3))); - MessageLoop::current()->PostTask(FROM_HERE, - Bind(&FuncThatRuns, &order, 4, Unretained(&nested_loop4))); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 5)); - MessageLoop::current()->PostTask( - FROM_HERE, outer_run_loop.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 6)); - MessageLoop::current()->PostTask( - FROM_HERE, nested_loop1.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 7)); - MessageLoop::current()->PostTask( - FROM_HERE, nested_loop2.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 8)); - MessageLoop::current()->PostTask( - FROM_HERE, nested_loop3.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 9)); - MessageLoop::current()->PostTask( - FROM_HERE, nested_loop4.QuitClosure()); - MessageLoop::current()->PostTask( - FROM_HERE, Bind(&OrderedFunc, &order, 10)); - - outer_run_loop.Run(); - - ASSERT_EQ(18U, order.Size()); - int task_index = 0; - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, true)); - EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, false)); - EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); - EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); -} - void PostNTasksThenQuit(int posts_remaining) { if (posts_remaining > 1) { MessageLoop::current()->PostTask( @@ -1398,13 +557,6 @@ void PostNTasksThenQuit(int posts_remaining) { } } -void RunTest_RecursivePosts(MessageLoop::Type message_loop_type, - int num_times) { - MessageLoop loop(message_loop_type); - loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, num_times)); - loop.Run(); -} - #if defined(OS_WIN) class DispatcherImpl : public MessageLoopForUI::Dispatcher { @@ -1620,79 +772,15 @@ void RunTest_WaitForIO() { // that message loops work properly in all configurations. Of course, in some // cases, a unit test may only be for a particular type of loop. -TEST(MessageLoopTest, PostTask) { - RunTest_PostTask(MessageLoop::TYPE_DEFAULT); - RunTest_PostTask(MessageLoop::TYPE_UI); - RunTest_PostTask(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostTask_SEH) { - RunTest_PostTask_SEH(MessageLoop::TYPE_DEFAULT); - RunTest_PostTask_SEH(MessageLoop::TYPE_UI); - RunTest_PostTask_SEH(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_Basic) { - RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_InDelayOrder) { - RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_InPostOrder) { - RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_InPostOrder_2) { - RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_InPostOrder_3) { - RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, PostDelayedTask_SharedTimer) { - RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_DEFAULT); - RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_UI); - RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_IO); -} +RUN_MESSAGE_LOOP_TESTS(Default, &TypeDefaultMessagePumpFactory); +RUN_MESSAGE_LOOP_TESTS(UI, &TypeUIMessagePumpFactory); +RUN_MESSAGE_LOOP_TESTS(IO, &TypeIOMessagePumpFactory); #if defined(OS_WIN) TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) { RunTest_PostDelayedTask_SharedTimer_SubPump(); } -#endif - -// TODO(darin): MessageLoop does not support deleting all tasks in the -// destructor. -// Fails, http://crbug.com/50272. -TEST(MessageLoopTest, DISABLED_EnsureDeletion) { - RunTest_EnsureDeletion(MessageLoop::TYPE_DEFAULT); - RunTest_EnsureDeletion(MessageLoop::TYPE_UI); - RunTest_EnsureDeletion(MessageLoop::TYPE_IO); -} - -// TODO(darin): MessageLoop does not support deleting all tasks in the -// destructor. -// Fails, http://crbug.com/50272. -TEST(MessageLoopTest, DISABLED_EnsureDeletion_Chain) { - RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_DEFAULT); - RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_UI); - RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_IO); -} -#if defined(OS_WIN) TEST(MessageLoopTest, Crasher) { RunTest_Crasher(MessageLoop::TYPE_DEFAULT); RunTest_Crasher(MessageLoop::TYPE_UI); @@ -1704,33 +792,7 @@ TEST(MessageLoopTest, CrasherNasty) { RunTest_CrasherNasty(MessageLoop::TYPE_UI); RunTest_CrasherNasty(MessageLoop::TYPE_IO); } -#endif // defined(OS_WIN) - -TEST(MessageLoopTest, Nesting) { - RunTest_Nesting(MessageLoop::TYPE_DEFAULT); - RunTest_Nesting(MessageLoop::TYPE_UI); - RunTest_Nesting(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RecursiveDenial1) { - RunTest_RecursiveDenial1(MessageLoop::TYPE_DEFAULT); - RunTest_RecursiveDenial1(MessageLoop::TYPE_UI); - RunTest_RecursiveDenial1(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RecursiveDenial3) { - RunTest_RecursiveDenial3(MessageLoop::TYPE_DEFAULT); - RunTest_RecursiveDenial3(MessageLoop::TYPE_UI); - RunTest_RecursiveDenial3(MessageLoop::TYPE_IO); -} -TEST(MessageLoopTest, RecursiveSupport1) { - RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT); - RunTest_RecursiveSupport1(MessageLoop::TYPE_UI); - RunTest_RecursiveSupport1(MessageLoop::TYPE_IO); -} - -#if defined(OS_WIN) // This test occasionally hangs http://crbug.com/44567 TEST(MessageLoopTest, DISABLED_RecursiveDenial2) { RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT); @@ -1744,72 +806,6 @@ TEST(MessageLoopTest, RecursiveSupport2) { } #endif // defined(OS_WIN) -TEST(MessageLoopTest, NonNestableWithNoNesting) { - RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_DEFAULT); - RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_UI); - RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, NonNestableInNestedLoop) { - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, false); - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, false); - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, false); -} - -TEST(MessageLoopTest, NonNestableDelayedInNestedLoop) { - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, true); - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, true); - RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, true); -} - -TEST(MessageLoopTest, QuitNow) { - RunTest_QuitNow(MessageLoop::TYPE_DEFAULT); - RunTest_QuitNow(MessageLoop::TYPE_UI); - RunTest_QuitNow(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitTop) { - RunTest_RunLoopQuitTop(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitTop(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitTop(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitNested) { - RunTest_RunLoopQuitNested(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitNested(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitNested(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitBogus) { - RunTest_RunLoopQuitBogus(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitBogus(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitBogus(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitDeep) { - RunTest_RunLoopQuitDeep(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitDeep(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitDeep(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitOrderBefore) { - RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitOrderDuring) { - RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_IO); -} - -TEST(MessageLoopTest, RunLoopQuitOrderAfter) { - RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_DEFAULT); - RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_UI); - RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_IO); -} - class DummyTaskObserver : public MessageLoop::TaskObserver { public: explicit DummyTaskObserver(int num_tasks) @@ -1948,9 +944,9 @@ TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) { // and don't run the message loop, just destroy it. } } - if (HANDLE_EINTR(close(pipefds[0])) < 0) + if (IGNORE_EINTR(close(pipefds[0])) < 0) PLOG(ERROR) << "close"; - if (HANDLE_EINTR(close(pipefds[1])) < 0) + if (IGNORE_EINTR(close(pipefds[1])) < 0) PLOG(ERROR) << "close"; } @@ -1973,9 +969,9 @@ TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) { controller.StopWatchingFileDescriptor(); } } - if (HANDLE_EINTR(close(pipefds[0])) < 0) + if (IGNORE_EINTR(close(pipefds[0])) < 0) PLOG(ERROR) << "close"; - if (HANDLE_EINTR(close(pipefds[1])) < 0) + if (IGNORE_EINTR(close(pipefds[1])) < 0) PLOG(ERROR) << "close"; } @@ -2086,19 +1082,92 @@ TEST(MessageLoopTest, IsType) { EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_DEFAULT)); } -TEST(MessageLoopTest, RecursivePosts) { - // There was a bug in the MessagePumpGLib where posting tasks recursively - // caused the message loop to hang, due to the buffer of the internal pipe - // becoming full. Test all MessageLoop types to ensure this issue does not - // exist in other MessagePumps. - - // On Linux, the pipe buffer size is 64KiB by default. The bug caused one - // byte accumulated in the pipe per two posts, so we should repeat 128K - // times to reproduce the bug. - const int kNumTimes = 1 << 17; - RunTest_RecursivePosts(MessageLoop::TYPE_DEFAULT, kNumTimes); - RunTest_RecursivePosts(MessageLoop::TYPE_UI, kNumTimes); - RunTest_RecursivePosts(MessageLoop::TYPE_IO, kNumTimes); +#if defined(OS_WIN) +void EmptyFunction() {} + +void PostMultipleTasks() { + MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&EmptyFunction)); + MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&EmptyFunction)); +} + +static const int kSignalMsg = WM_USER + 2; + +void PostWindowsMessage(HWND message_hwnd) { + PostMessage(message_hwnd, kSignalMsg, 0, 2); +} + +void EndTest(bool* did_run, HWND hwnd) { + *did_run = true; + PostMessage(hwnd, WM_CLOSE, 0, 0); +} + +int kMyMessageFilterCode = 0x5002; + +LRESULT CALLBACK TestWndProcThunk(HWND hwnd, UINT message, + WPARAM wparam, LPARAM lparam) { + if (message == WM_CLOSE) + EXPECT_TRUE(DestroyWindow(hwnd)); + if (message != kSignalMsg) + return DefWindowProc(hwnd, message, wparam, lparam); + + switch (lparam) { + case 1: + // First, we post a task that will post multiple no-op tasks to make sure + // that the pump's incoming task queue does not become empty during the + // test. + MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&PostMultipleTasks)); + // Next, we post a task that posts a windows message to trigger the second + // stage of the test. + MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(&PostWindowsMessage, hwnd)); + break; + case 2: + // Since we're about to enter a modal loop, tell the message loop that we + // intend to nest tasks. + MessageLoop::current()->SetNestableTasksAllowed(true); + bool did_run = false; + MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(&EndTest, &did_run, hwnd)); + // Run a nested windows-style message loop and verify that our task runs. If + // it doesn't, then we'll loop here until the test times out. + MSG msg; + while (GetMessage(&msg, 0, 0, 0)) { + if (!CallMsgFilter(&msg, kMyMessageFilterCode)) + DispatchMessage(&msg); + // If this message is a WM_CLOSE, explicitly exit the modal loop. Posting + // a WM_QUIT should handle this, but unfortunately MessagePumpWin eats + // WM_QUIT messages even when running inside a modal loop. + if (msg.message == WM_CLOSE) + break; + } + EXPECT_TRUE(did_run); + MessageLoop::current()->Quit(); + break; + } + return 0; +} + +TEST(MessageLoopTest, AlwaysHaveUserMessageWhenNesting) { + MessageLoop loop(MessageLoop::TYPE_UI); + HINSTANCE instance = GetModuleFromAddress(&TestWndProcThunk); + WNDCLASSEX wc = {0}; + wc.cbSize = sizeof(wc); + wc.lpfnWndProc = TestWndProcThunk; + wc.hInstance = instance; + wc.lpszClassName = L"MessageLoopTest_HWND"; + ATOM atom = RegisterClassEx(&wc); + ASSERT_TRUE(atom); + + HWND message_hwnd = CreateWindow(MAKEINTATOM(atom), 0, 0, 0, 0, 0, 0, + HWND_MESSAGE, 0, instance, 0); + ASSERT_TRUE(message_hwnd) << GetLastError(); + + ASSERT_TRUE(PostMessage(message_hwnd, kSignalMsg, 0, 1)); + + loop.Run(); + + ASSERT_TRUE(UnregisterClass(MAKEINTATOM(atom), instance)); } +#endif // defined(OS_WIN) } // namespace base diff --git a/chromium/base/message_loop/message_pump_android.cc b/chromium/base/message_loop/message_pump_android.cc index f3f1c9bcb4d..e756fdd3f52 100644 --- a/chromium/base/message_loop/message_pump_android.cc +++ b/chromium/base/message_loop/message_pump_android.cc @@ -21,7 +21,7 @@ using base::android::ScopedJavaLocalRef; // ---------------------------------------------------------------------------- // This method can not move to anonymous namespace as it has been declared as // 'static' in system_message_handler_jni.h. -static void DoRunLoopOnce(JNIEnv* env, jobject obj, jint native_delegate) { +static void DoRunLoopOnce(JNIEnv* env, jobject obj, jlong native_delegate) { base::MessagePump::Delegate* delegate = reinterpret_cast<base::MessagePump::Delegate*>(native_delegate); DCHECK(delegate); @@ -81,7 +81,8 @@ void MessagePumpForUI::Start(Delegate* delegate) { DCHECK(env); system_message_handler_obj_.Reset( - Java_SystemMessageHandler_create(env, reinterpret_cast<jint>(delegate))); + Java_SystemMessageHandler_create( + env, reinterpret_cast<intptr_t>(delegate))); } void MessagePumpForUI::Quit() { diff --git a/chromium/base/message_loop/message_pump_io_ios_unittest.cc b/chromium/base/message_loop/message_pump_io_ios_unittest.cc index 9c7a8fbf651..f3b598c6ba6 100644 --- a/chromium/base/message_loop/message_pump_io_ios_unittest.cc +++ b/chromium/base/message_loop/message_pump_io_ios_unittest.cc @@ -31,9 +31,9 @@ class MessagePumpIOSForIOTest : public testing::Test { } virtual void TearDown() OVERRIDE { - if (HANDLE_EINTR(close(pipefds_[0])) < 0) + if (IGNORE_EINTR(close(pipefds_[0])) < 0) PLOG(ERROR) << "close"; - if (HANDLE_EINTR(close(pipefds_[1])) < 0) + if (IGNORE_EINTR(close(pipefds_[1])) < 0) PLOG(ERROR) << "close"; } diff --git a/chromium/base/message_loop/message_pump_libevent.cc b/chromium/base/message_loop/message_pump_libevent.cc index 6d862d1d266..26be687c6dd 100644 --- a/chromium/base/message_loop/message_pump_libevent.cc +++ b/chromium/base/message_loop/message_pump_libevent.cc @@ -125,11 +125,11 @@ MessagePumpLibevent::~MessagePumpLibevent() { event_del(wakeup_event_); delete wakeup_event_; if (wakeup_pipe_in_ >= 0) { - if (HANDLE_EINTR(close(wakeup_pipe_in_)) < 0) + if (IGNORE_EINTR(close(wakeup_pipe_in_)) < 0) DPLOG(ERROR) << "close"; } if (wakeup_pipe_out_ >= 0) { - if (HANDLE_EINTR(close(wakeup_pipe_out_)) < 0) + if (IGNORE_EINTR(close(wakeup_pipe_out_)) < 0) DPLOG(ERROR) << "close"; } event_base_free(event_base_); diff --git a/chromium/base/message_loop/message_pump_libevent_unittest.cc b/chromium/base/message_loop/message_pump_libevent_unittest.cc index 52ca95bebf7..bf6d21c3280 100644 --- a/chromium/base/message_loop/message_pump_libevent_unittest.cc +++ b/chromium/base/message_loop/message_pump_libevent_unittest.cc @@ -30,9 +30,9 @@ class MessagePumpLibeventTest : public testing::Test { } virtual void TearDown() OVERRIDE { - if (HANDLE_EINTR(close(pipefds_[0])) < 0) + if (IGNORE_EINTR(close(pipefds_[0])) < 0) PLOG(ERROR) << "close"; - if (HANDLE_EINTR(close(pipefds_[1])) < 0) + if (IGNORE_EINTR(close(pipefds_[1])) < 0) PLOG(ERROR) << "close"; } diff --git a/chromium/base/message_loop/message_pump_win.cc b/chromium/base/message_loop/message_pump_win.cc index 589d0775410..1927473b1eb 100644 --- a/chromium/base/message_loop/message_pump_win.cc +++ b/chromium/base/message_loop/message_pump_win.cc @@ -172,30 +172,6 @@ void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { MESSAGE_LOOP_PROBLEM_MAX); } -void MessagePumpForUI::PumpOutPendingPaintMessages() { - // If we are being called outside of the context of Run, then don't try to do - // any work. - if (!state_) - return; - - // Create a mini-message-pump to force immediate processing of only Windows - // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking - // to get the job done. Actual common max is 4 peeks, but we'll be a little - // safe here. - const int kMaxPeekCount = 20; - int peek_count; - for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) { - MSG msg; - if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) - break; - ProcessMessageHelper(msg); - if (state_->should_quit) // Handle WM_QUIT. - break; - } - // Histogram what was really being used, to help to adjust kMaxPeekCount. - DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); -} - //----------------------------------------------------------------------------- // MessagePumpForUI private: diff --git a/chromium/base/message_loop/message_pump_win.h b/chromium/base/message_loop/message_pump_win.h index 2d833540e03..9184058a6c0 100644 --- a/chromium/base/message_loop/message_pump_win.h +++ b/chromium/base/message_loop/message_pump_win.h @@ -169,11 +169,6 @@ class BASE_EXPORT MessagePumpForUI : public MessagePumpWin { virtual void ScheduleWork(); virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time); - // Applications can call this to encourage us to process all pending WM_PAINT - // messages. This method will process all paint messages the Windows Message - // queue can provide, up to some fixed number (to avoid any infinite loops). - void PumpOutPendingPaintMessages(); - private: static LRESULT CALLBACK WndProcThunk(HWND window_handle, UINT message, diff --git a/chromium/base/message_loop/message_pump_x11.cc b/chromium/base/message_loop/message_pump_x11.cc index dd8b965e695..35dcc040348 100644 --- a/chromium/base/message_loop/message_pump_x11.cc +++ b/chromium/base/message_loop/message_pump_x11.cc @@ -53,7 +53,7 @@ GSourceFuncs XSourceFuncs = { Display* g_xdisplay = NULL; int g_xinput_opcode = -1; -bool InitializeXInput2Internal() { +bool InitializeXInput2() { Display* display = MessagePumpX11::GetDefaultXDisplay(); if (!display) return false; @@ -97,11 +97,6 @@ Window FindEventTarget(const NativeEvent& xev) { return target; } -bool InitializeXInput2() { - static bool xinput2_supported = InitializeXInput2Internal(); - return xinput2_supported; -} - bool InitializeXkb() { Display* display = MessagePumpX11::GetDefaultXDisplay(); if (!display) @@ -153,11 +148,6 @@ Display* MessagePumpX11::GetDefaultXDisplay() { return g_xdisplay; } -// static -bool MessagePumpX11::HasXInput2() { - return InitializeXInput2(); -} - #if defined(TOOLKIT_GTK) // static MessagePumpX11* MessagePumpX11::Current() { diff --git a/chromium/base/message_loop/message_pump_x11.h b/chromium/base/message_loop/message_pump_x11.h index f1f678a79c7..015c230a700 100644 --- a/chromium/base/message_loop/message_pump_x11.h +++ b/chromium/base/message_loop/message_pump_x11.h @@ -40,9 +40,6 @@ class BASE_EXPORT MessagePumpX11 : public MessagePumpGlib, // Returns default X Display. static Display* GetDefaultXDisplay(); - // Returns true if the system supports XINPUT2. - static bool HasXInput2(); - // Returns the UI or GPU message pump. static MessagePumpX11* Current(); |