blob: b404dc80a2d9f88d7ce1d18e4a493cb992a78ceb [file] [log] [blame]
ajwong@chromium.org22a8a0d2012-01-04 09:57:39 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botf003cfe2008-08-24 09:55:55 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit3f4a7322008-07-27 06:49:38 +09004
thestig@chromium.org60bd7c02010-07-23 14:23:13 +09005#include <vector>
6
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09007#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/compiler_specific.h"
willchan@chromium.orga9047632010-06-10 06:20:41 +090010#include "base/eintr_wrapper.h"
initial.commit3f4a7322008-07-27 06:49:38 +090011#include "base/logging.h"
levin@chromium.org5c528682011-03-28 10:54:15 +090012#include "base/memory/ref_counted.h"
initial.commit3f4a7322008-07-27 06:49:38 +090013#include "base/message_loop.h"
brettw@chromium.org61391822011-01-01 05:02:16 +090014#include "base/threading/platform_thread.h"
brettw@chromium.org5b5f5e02011-01-01 10:01:06 +090015#include "base/threading/thread.h"
initial.commit3f4a7322008-07-27 06:49:38 +090016#include "testing/gtest/include/gtest/gtest.h"
17
darin@google.coma2ac02b2008-08-15 13:32:57 +090018#if defined(OS_WIN)
19#include "base/message_pump_win.h"
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +090020#include "base/win/scoped_handle.h"
darin@google.coma2ac02b2008-08-15 13:32:57 +090021#endif
22
brettw@chromium.org61391822011-01-01 05:02:16 +090023using base::PlatformThread;
darin@google.comd936b5b2008-08-26 14:53:57 +090024using base::Thread;
dsh@google.com0f8dd262008-10-28 05:43:33 +090025using base::Time;
26using base::TimeDelta;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +090027using base::TimeTicks;
darin@google.comd936b5b2008-08-26 14:53:57 +090028
29// TODO(darin): Platform-specific MessageLoop tests should be grouped together
30// to avoid chopping this file up with so many #ifdefs.
darin@google.com12d40bb2008-08-20 03:36:23 +090031
initial.commit3f4a7322008-07-27 06:49:38 +090032namespace {
33
darin@google.comd936b5b2008-08-26 14:53:57 +090034class MessageLoopTest : public testing::Test {};
initial.commit3f4a7322008-07-27 06:49:38 +090035
36class Foo : public base::RefCounted<Foo> {
37 public:
38 Foo() : test_count_(0) {
39 }
40
41 void Test0() {
42 ++test_count_;
43 }
44
45 void Test1ConstRef(const std::string& a) {
46 ++test_count_;
47 result_.append(a);
48 }
49
50 void Test1Ptr(std::string* a) {
51 ++test_count_;
52 result_.append(*a);
53 }
54
55 void Test1Int(int a) {
56 test_count_ += a;
57 }
58
59 void Test2Ptr(std::string* a, std::string* b) {
60 ++test_count_;
61 result_.append(*a);
62 result_.append(*b);
63 }
64
65 void Test2Mixed(const std::string& a, std::string* b) {
66 ++test_count_;
67 result_.append(a);
68 result_.append(*b);
69 }
70
71 int test_count() const { return test_count_; }
72 const std::string& result() const { return result_; }
73
74 private:
jam@chromium.orgb1f47b22009-11-06 06:53:08 +090075 friend class base::RefCounted<Foo>;
76
77 ~Foo() {}
78
initial.commit3f4a7322008-07-27 06:49:38 +090079 int test_count_;
80 std::string result_;
81};
82
ajwong@chromium.org94d2a582011-04-21 01:02:23 +090083void RunTest_PostTask(MessageLoop::Type message_loop_type) {
84 MessageLoop loop(message_loop_type);
85
86 // Add tests to message loop
87 scoped_refptr<Foo> foo(new Foo());
88 std::string a("a"), b("b"), c("c"), d("d");
89 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
90 &Foo::Test0, foo.get()));
91 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
92 &Foo::Test1ConstRef, foo.get(), a));
93 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
94 &Foo::Test1Ptr, foo.get(), &b));
95 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
96 &Foo::Test1Int, foo.get(), 100));
97 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
98 &Foo::Test2Ptr, foo.get(), &a, &c));
99 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
100 &Foo::Test2Mixed, foo.get(), a, &d));
101
102 // After all tests, post a message that will shut down the message loop
103 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
104 &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
initial.commit3f4a7322008-07-27 06:49:38 +0900105
106 // Now kick things off
107 MessageLoop::current()->Run();
108
109 EXPECT_EQ(foo->test_count(), 105);
110 EXPECT_EQ(foo->result(), "abacad");
111}
112
darin@google.comd936b5b2008-08-26 14:53:57 +0900113void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) {
114 MessageLoop loop(message_loop_type);
115
initial.commit3f4a7322008-07-27 06:49:38 +0900116 // Add tests to message loop
thakis@chromium.org625aa232010-11-01 13:16:27 +0900117 scoped_refptr<Foo> foo(new Foo());
initial.commit3f4a7322008-07-27 06:49:38 +0900118 std::string a("a"), b("b"), c("c"), d("d");
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900119 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
120 &Foo::Test0, foo.get()));
121 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
122 &Foo::Test1ConstRef, foo.get(), a));
123 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
124 &Foo::Test1Ptr, foo.get(), &b));
125 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
126 &Foo::Test1Int, foo.get(), 100));
127 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
128 &Foo::Test2Ptr, foo.get(), &a, &c));
129 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
130 &Foo::Test2Mixed, foo.get(), a, &d));
initial.commit3f4a7322008-07-27 06:49:38 +0900131
132 // After all tests, post a message that will shut down the message loop
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900133 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
134 &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
initial.commit3f4a7322008-07-27 06:49:38 +0900135
136 // Now kick things off with the SEH block active.
137 MessageLoop::current()->set_exception_restoration(true);
138 MessageLoop::current()->Run();
139 MessageLoop::current()->set_exception_restoration(false);
140
141 EXPECT_EQ(foo->test_count(), 105);
142 EXPECT_EQ(foo->result(), "abacad");
143}
144
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900145// This function runs slowly to simulate a large amount of work being done.
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900146static void SlowFunc(TimeDelta pause, int* quit_counter) {
147 PlatformThread::Sleep(pause);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900148 if (--(*quit_counter) == 0)
darin@google.combe165ae2008-09-07 17:08:29 +0900149 MessageLoop::current()->Quit();
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900150}
darin@google.combe165ae2008-09-07 17:08:29 +0900151
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900152// This function records the time when Run was called in a Time object, which is
darin@google.combe165ae2008-09-07 17:08:29 +0900153// useful for building a variety of MessageLoop tests.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900154static void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
155 *run_time = Time::Now();
156
darin@google.combe165ae2008-09-07 17:08:29 +0900157 // Cause our Run function to take some time to execute. As a result we can
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900158 // count on subsequent RecordRunTimeFunc()s running at a future time,
darin@google.combe165ae2008-09-07 17:08:29 +0900159 // without worry about the resolution of our system clock being an issue.
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900160 SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900161}
darin@google.combe165ae2008-09-07 17:08:29 +0900162
163void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) {
164 MessageLoop loop(message_loop_type);
165
166 // Test that PostDelayedTask results in a delayed task.
167
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900168 const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
darin@google.combe165ae2008-09-07 17:08:29 +0900169
170 int num_tasks = 1;
171 Time run_time;
172
173 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900174 FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900175 kDelay);
darin@google.combe165ae2008-09-07 17:08:29 +0900176
177 Time time_before_run = Time::Now();
178 loop.Run();
179 Time time_after_run = Time::Now();
180
181 EXPECT_EQ(0, num_tasks);
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900182 EXPECT_LT(kDelay, time_after_run - time_before_run);
darin@google.combe165ae2008-09-07 17:08:29 +0900183}
184
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900185void RunTest_PostDelayedTask_InDelayOrder(
186 MessageLoop::Type message_loop_type) {
darin@google.combe165ae2008-09-07 17:08:29 +0900187 MessageLoop loop(message_loop_type);
188
189 // Test that two tasks with different delays run in the right order.
darin@google.combe165ae2008-09-07 17:08:29 +0900190 int num_tasks = 2;
191 Time run_time1, run_time2;
192
193 loop.PostDelayedTask(
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900194 FROM_HERE,
195 base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
196 TimeDelta::FromMilliseconds(200));
darin@google.combe165ae2008-09-07 17:08:29 +0900197 // If we get a large pause in execution (due to a context switch) here, this
198 // test could fail.
199 loop.PostDelayedTask(
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900200 FROM_HERE,
201 base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
202 TimeDelta::FromMilliseconds(10));
darin@google.combe165ae2008-09-07 17:08:29 +0900203
204 loop.Run();
205 EXPECT_EQ(0, num_tasks);
206
207 EXPECT_TRUE(run_time2 < run_time1);
208}
209
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900210void RunTest_PostDelayedTask_InPostOrder(
211 MessageLoop::Type message_loop_type) {
darin@google.combe165ae2008-09-07 17:08:29 +0900212 MessageLoop loop(message_loop_type);
213
214 // Test that two tasks with the same delay run in the order in which they
215 // were posted.
216 //
217 // NOTE: This is actually an approximate test since the API only takes a
218 // "delay" parameter, so we are not exactly simulating two tasks that get
219 // posted at the exact same time. It would be nice if the API allowed us to
220 // specify the desired run time.
221
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900222 const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
darin@google.combe165ae2008-09-07 17:08:29 +0900223
224 int num_tasks = 2;
225 Time run_time1, run_time2;
226
227 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900228 FROM_HERE,
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900229 base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay);
darin@google.combe165ae2008-09-07 17:08:29 +0900230 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900231 FROM_HERE,
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900232 base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay);
darin@google.combe165ae2008-09-07 17:08:29 +0900233
234 loop.Run();
235 EXPECT_EQ(0, num_tasks);
236
237 EXPECT_TRUE(run_time1 < run_time2);
238}
239
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900240void RunTest_PostDelayedTask_InPostOrder_2(
241 MessageLoop::Type message_loop_type) {
darin@google.combe165ae2008-09-07 17:08:29 +0900242 MessageLoop loop(message_loop_type);
243
244 // Test that a delayed task still runs after a normal tasks even if the
245 // normal tasks take a long time to run.
246
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900247 const TimeDelta kPause = TimeDelta::FromMilliseconds(50);
darin@google.combe165ae2008-09-07 17:08:29 +0900248
249 int num_tasks = 2;
250 Time run_time;
251
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900252 loop.PostTask(FROM_HERE, base::Bind(&SlowFunc, kPause, &num_tasks));
darin@google.combe165ae2008-09-07 17:08:29 +0900253 loop.PostDelayedTask(
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900254 FROM_HERE,
255 base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
256 TimeDelta::FromMilliseconds(10));
darin@google.combe165ae2008-09-07 17:08:29 +0900257
258 Time time_before_run = Time::Now();
259 loop.Run();
260 Time time_after_run = Time::Now();
261
262 EXPECT_EQ(0, num_tasks);
263
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900264 EXPECT_LT(kPause, time_after_run - time_before_run);
darin@google.combe165ae2008-09-07 17:08:29 +0900265}
266
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900267void RunTest_PostDelayedTask_InPostOrder_3(
268 MessageLoop::Type message_loop_type) {
darin@google.combe165ae2008-09-07 17:08:29 +0900269 MessageLoop loop(message_loop_type);
270
271 // Test that a delayed task still runs after a pile of normal tasks. The key
272 // difference between this test and the previous one is that here we return
273 // the MessageLoop a lot so we give the MessageLoop plenty of opportunities
274 // to maybe run the delayed task. It should know not to do so until the
275 // delayed task's delay has passed.
276
277 int num_tasks = 11;
278 Time run_time1, run_time2;
279
280 // Clutter the ML with tasks.
281 for (int i = 1; i < num_tasks; ++i)
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900282 loop.PostTask(FROM_HERE,
283 base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks));
darin@google.combe165ae2008-09-07 17:08:29 +0900284
285 loop.PostDelayedTask(
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900286 FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
287 TimeDelta::FromMilliseconds(1));
darin@google.combe165ae2008-09-07 17:08:29 +0900288
289 loop.Run();
290 EXPECT_EQ(0, num_tasks);
291
292 EXPECT_TRUE(run_time2 > run_time1);
293}
294
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900295void RunTest_PostDelayedTask_SharedTimer(
296 MessageLoop::Type message_loop_type) {
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900297 MessageLoop loop(message_loop_type);
298
299 // Test that the interval of the timer, used to run the next delayed task, is
300 // set to a value corresponding to when the next delayed task should run.
301
302 // By setting num_tasks to 1, we ensure that the first task to run causes the
303 // run loop to exit.
304 int num_tasks = 1;
305 Time run_time1, run_time2;
306
307 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900308 FROM_HERE,
309 base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900310 TimeDelta::FromSeconds(1000));
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900311 loop.PostDelayedTask(
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900312 FROM_HERE,
313 base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
314 TimeDelta::FromMilliseconds(10));
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900315
316 Time start_time = Time::Now();
317
318 loop.Run();
319 EXPECT_EQ(0, num_tasks);
320
321 // Ensure that we ran in far less time than the slower timer.
darin@chromium.orgaa119c22008-09-24 04:22:33 +0900322 TimeDelta total_time = Time::Now() - start_time;
323 EXPECT_GT(5000, total_time.InMilliseconds());
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900324
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900325 // In case both timers somehow run at nearly the same time, sleep a little
326 // and then run all pending to force them both to have run. This is just
327 // encouraging flakiness if there is any.
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900328 PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900329 loop.RunAllPending();
330
331 EXPECT_TRUE(run_time1.is_null());
332 EXPECT_FALSE(run_time2.is_null());
333}
334
335#if defined(OS_WIN)
336
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900337void SubPumpFunc() {
338 MessageLoop::current()->SetNestableTasksAllowed(true);
339 MSG msg;
340 while (GetMessage(&msg, NULL, 0, 0)) {
341 TranslateMessage(&msg);
342 DispatchMessage(&msg);
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900343 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900344 MessageLoop::current()->Quit();
345}
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900346
347void RunTest_PostDelayedTask_SharedTimer_SubPump() {
348 MessageLoop loop(MessageLoop::TYPE_UI);
349
350 // Test that the interval of the timer, used to run the next delayed task, is
351 // set to a value corresponding to when the next delayed task should run.
352
353 // By setting num_tasks to 1, we ensure that the first task to run causes the
354 // run loop to exit.
355 int num_tasks = 1;
356 Time run_time;
357
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900358 loop.PostTask(FROM_HERE, base::Bind(&SubPumpFunc));
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900359
360 // This very delayed task should never run.
361 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900362 FROM_HERE,
363 base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900364 TimeDelta::FromSeconds(1000));
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900365
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900366 // This slightly delayed task should run from within SubPumpFunc).
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900367 loop.PostDelayedTask(
368 FROM_HERE,
369 base::Bind(&PostQuitMessage, 0),
370 TimeDelta::FromMilliseconds(10));
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900371
372 Time start_time = Time::Now();
373
374 loop.Run();
375 EXPECT_EQ(1, num_tasks);
376
377 // Ensure that we ran in far less time than the slower timer.
darin@chromium.orgaa119c22008-09-24 04:22:33 +0900378 TimeDelta total_time = Time::Now() - start_time;
379 EXPECT_GT(5000, total_time.InMilliseconds());
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900380
381 // In case both timers somehow run at nearly the same time, sleep a little
382 // and then run all pending to force them both to have run. This is just
383 // encouraging flakiness if there is any.
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900384 PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900385 loop.RunAllPending();
386
387 EXPECT_TRUE(run_time.is_null());
388}
389
390#endif // defined(OS_WIN)
391
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900392// This is used to inject a test point for recording the destructor calls for
393// Closure objects send to MessageLoop::PostTask(). It is awkward usage since we
394// are trying to hook the actual destruction, which is not a common operation.
395class RecordDeletionProbe : public base::RefCounted<RecordDeletionProbe> {
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900396 public:
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900397 RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted)
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900398 : post_on_delete_(post_on_delete), was_deleted_(was_deleted) {
399 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900400 ~RecordDeletionProbe() {
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900401 *was_deleted_ = true;
402 if (post_on_delete_)
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900403 MessageLoop::current()->PostTask(
404 FROM_HERE,
405 base::Bind(&RecordDeletionProbe::Run, post_on_delete_.get()));
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900406 }
thakis@chromium.org2d8d5922011-06-08 11:20:21 +0900407 void Run() {}
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900408 private:
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900409 scoped_refptr<RecordDeletionProbe> post_on_delete_;
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900410 bool* was_deleted_;
411};
412
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900413void RunTest_EnsureDeletion(MessageLoop::Type message_loop_type) {
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900414 bool a_was_deleted = false;
415 bool b_was_deleted = false;
416 {
417 MessageLoop loop(message_loop_type);
418 loop.PostTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900419 FROM_HERE, base::Bind(&RecordDeletionProbe::Run,
420 new RecordDeletionProbe(NULL, &a_was_deleted)));
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900421 // TODO(ajwong): Do we really need 1000ms here?
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900422 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900423 FROM_HERE, base::Bind(&RecordDeletionProbe::Run,
424 new RecordDeletionProbe(NULL, &b_was_deleted)),
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900425 TimeDelta::FromMilliseconds(1000));
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900426 }
427 EXPECT_TRUE(a_was_deleted);
428 EXPECT_TRUE(b_was_deleted);
429}
430
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900431void RunTest_EnsureDeletion_Chain(MessageLoop::Type message_loop_type) {
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900432 bool a_was_deleted = false;
433 bool b_was_deleted = false;
434 bool c_was_deleted = false;
435 {
436 MessageLoop loop(message_loop_type);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900437 // The scoped_refptr for each of the below is held either by the chained
438 // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback.
439 RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted);
440 RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted);
441 RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted);
442 loop.PostTask(FROM_HERE, base::Bind(&RecordDeletionProbe::Run, c));
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900443 }
444 EXPECT_TRUE(a_was_deleted);
445 EXPECT_TRUE(b_was_deleted);
446 EXPECT_TRUE(c_was_deleted);
447}
448
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900449void NestingFunc(int* depth) {
450 if (*depth > 0) {
451 *depth -= 1;
452 MessageLoop::current()->PostTask(FROM_HERE,
453 base::Bind(&NestingFunc, depth));
initial.commit3f4a7322008-07-27 06:49:38 +0900454
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900455 MessageLoop::current()->SetNestableTasksAllowed(true);
456 MessageLoop::current()->Run();
initial.commit3f4a7322008-07-27 06:49:38 +0900457 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900458 MessageLoop::current()->Quit();
459}
initial.commit3f4a7322008-07-27 06:49:38 +0900460
darin@google.com12d40bb2008-08-20 03:36:23 +0900461#if defined(OS_WIN)
462
initial.commit3f4a7322008-07-27 06:49:38 +0900463LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) {
464 ADD_FAILURE() << "bad exception handler";
465 ::ExitProcess(ex_info->ExceptionRecord->ExceptionCode);
466 return EXCEPTION_EXECUTE_HANDLER;
467}
468
469// This task throws an SEH exception: initially write to an invalid address.
470// If the right SEH filter is installed, it will fix the error.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900471class Crasher : public base::RefCounted<Crasher> {
initial.commit3f4a7322008-07-27 06:49:38 +0900472 public:
473 // Ctor. If trash_SEH_handler is true, the task will override the unhandled
474 // exception handler with one sure to crash this test.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900475 explicit Crasher(bool trash_SEH_handler)
initial.commit3f4a7322008-07-27 06:49:38 +0900476 : trash_SEH_handler_(trash_SEH_handler) {
477 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900478
initial.commit3f4a7322008-07-27 06:49:38 +0900479 void Run() {
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900480 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
initial.commit3f4a7322008-07-27 06:49:38 +0900481 if (trash_SEH_handler_)
482 ::SetUnhandledExceptionFilter(&BadExceptionHandler);
483 // Generate a SEH fault. We do it in asm to make sure we know how to undo
484 // the damage.
maruel@google.coma855b0f2008-07-30 22:02:03 +0900485
486#if defined(_M_IX86)
487
initial.commit3f4a7322008-07-27 06:49:38 +0900488 __asm {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900489 mov eax, dword ptr [Crasher::bad_array_]
initial.commit3f4a7322008-07-27 06:49:38 +0900490 mov byte ptr [eax], 66
491 }
maruel@google.coma855b0f2008-07-30 22:02:03 +0900492
493#elif defined(_M_X64)
494
495 bad_array_[0] = 66;
496
darin@google.com12d40bb2008-08-20 03:36:23 +0900497#else
498#error "needs architecture support"
maruel@google.coma855b0f2008-07-30 22:02:03 +0900499#endif
500
initial.commit3f4a7322008-07-27 06:49:38 +0900501 MessageLoop::current()->Quit();
502 }
503 // Points the bad array to a valid memory location.
504 static void FixError() {
505 bad_array_ = &valid_store_;
506 }
507
508 private:
509 bool trash_SEH_handler_;
510 static volatile char* bad_array_;
511 static char valid_store_;
512};
513
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900514volatile char* Crasher::bad_array_ = 0;
515char Crasher::valid_store_ = 0;
initial.commit3f4a7322008-07-27 06:49:38 +0900516
517// This SEH filter fixes the problem and retries execution. Fixing requires
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900518// that the last instruction: mov eax, [Crasher::bad_array_] to be retried
initial.commit3f4a7322008-07-27 06:49:38 +0900519// so we move the instruction pointer 5 bytes back.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900520LONG WINAPI HandleCrasherException(EXCEPTION_POINTERS *ex_info) {
initial.commit3f4a7322008-07-27 06:49:38 +0900521 if (ex_info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
522 return EXCEPTION_EXECUTE_HANDLER;
523
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900524 Crasher::FixError();
maruel@google.coma855b0f2008-07-30 22:02:03 +0900525
526#if defined(_M_IX86)
527
initial.commit3f4a7322008-07-27 06:49:38 +0900528 ex_info->ContextRecord->Eip -= 5;
maruel@google.coma855b0f2008-07-30 22:02:03 +0900529
530#elif defined(_M_X64)
531
532 ex_info->ContextRecord->Rip -= 5;
533
534#endif
535
initial.commit3f4a7322008-07-27 06:49:38 +0900536 return EXCEPTION_CONTINUE_EXECUTION;
537}
538
darin@google.comd936b5b2008-08-26 14:53:57 +0900539void RunTest_Crasher(MessageLoop::Type message_loop_type) {
540 MessageLoop loop(message_loop_type);
darin@google.com12d40bb2008-08-20 03:36:23 +0900541
initial.commit3f4a7322008-07-27 06:49:38 +0900542 if (::IsDebuggerPresent())
543 return;
544
545 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900546 ::SetUnhandledExceptionFilter(&HandleCrasherException);
initial.commit3f4a7322008-07-27 06:49:38 +0900547
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900548 MessageLoop::current()->PostTask(
549 FROM_HERE,
550 base::Bind(&Crasher::Run, new Crasher(false)));
initial.commit3f4a7322008-07-27 06:49:38 +0900551 MessageLoop::current()->set_exception_restoration(true);
552 MessageLoop::current()->Run();
553 MessageLoop::current()->set_exception_restoration(false);
554
555 ::SetUnhandledExceptionFilter(old_SEH_filter);
556}
557
darin@google.comd936b5b2008-08-26 14:53:57 +0900558void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) {
559 MessageLoop loop(message_loop_type);
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900560
initial.commit3f4a7322008-07-27 06:49:38 +0900561 if (::IsDebuggerPresent())
562 return;
563
564 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900565 ::SetUnhandledExceptionFilter(&HandleCrasherException);
initial.commit3f4a7322008-07-27 06:49:38 +0900566
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900567 MessageLoop::current()->PostTask(
568 FROM_HERE,
569 base::Bind(&Crasher::Run, new Crasher(true)));
initial.commit3f4a7322008-07-27 06:49:38 +0900570 MessageLoop::current()->set_exception_restoration(true);
571 MessageLoop::current()->Run();
572 MessageLoop::current()->set_exception_restoration(false);
573
574 ::SetUnhandledExceptionFilter(old_SEH_filter);
575}
576
darin@google.coma2ac02b2008-08-15 13:32:57 +0900577#endif // defined(OS_WIN)
578
darin@google.comd936b5b2008-08-26 14:53:57 +0900579void RunTest_Nesting(MessageLoop::Type message_loop_type) {
580 MessageLoop loop(message_loop_type);
maruel@google.coma855b0f2008-07-30 22:02:03 +0900581
initial.commit3f4a7322008-07-27 06:49:38 +0900582 int depth = 100;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900583 MessageLoop::current()->PostTask(FROM_HERE,
584 base::Bind(&NestingFunc, &depth));
initial.commit3f4a7322008-07-27 06:49:38 +0900585 MessageLoop::current()->Run();
586 EXPECT_EQ(depth, 0);
587}
588
initial.commit3f4a7322008-07-27 06:49:38 +0900589const wchar_t* const kMessageBoxTitle = L"MessageLoop Unit Test";
590
591enum TaskType {
592 MESSAGEBOX,
593 ENDDIALOG,
594 RECURSIVE,
595 TIMEDMESSAGELOOP,
596 QUITMESSAGELOOP,
597 ORDERERD,
598 PUMPS,
mark@chromium.org3ae027a2009-06-26 04:23:11 +0900599 SLEEP,
initial.commit3f4a7322008-07-27 06:49:38 +0900600};
601
602// Saves the order in which the tasks executed.
603struct TaskItem {
604 TaskItem(TaskType t, int c, bool s)
605 : type(t),
606 cookie(c),
607 start(s) {
608 }
609
610 TaskType type;
611 int cookie;
612 bool start;
613
614 bool operator == (const TaskItem& other) const {
615 return type == other.type && cookie == other.cookie && start == other.start;
616 }
617};
618
initial.commit3f4a7322008-07-27 06:49:38 +0900619std::ostream& operator <<(std::ostream& os, TaskType type) {
620 switch (type) {
621 case MESSAGEBOX: os << "MESSAGEBOX"; break;
622 case ENDDIALOG: os << "ENDDIALOG"; break;
623 case RECURSIVE: os << "RECURSIVE"; break;
624 case TIMEDMESSAGELOOP: os << "TIMEDMESSAGELOOP"; break;
625 case QUITMESSAGELOOP: os << "QUITMESSAGELOOP"; break;
626 case ORDERERD: os << "ORDERERD"; break;
627 case PUMPS: os << "PUMPS"; break;
mark@chromium.org3ae027a2009-06-26 04:23:11 +0900628 case SLEEP: os << "SLEEP"; break;
initial.commit3f4a7322008-07-27 06:49:38 +0900629 default:
630 NOTREACHED();
631 os << "Unknown TaskType";
632 break;
633 }
634 return os;
635}
636
637std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
638 if (item.start)
639 return os << item.type << " " << item.cookie << " starts";
640 else
641 return os << item.type << " " << item.cookie << " ends";
642}
643
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900644class TaskList {
initial.commit3f4a7322008-07-27 06:49:38 +0900645 public:
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900646 void RecordStart(TaskType type, int cookie) {
647 TaskItem item(type, cookie, true);
pkasting@chromium.org9fc87072010-10-19 11:31:03 +0900648 DVLOG(1) << item;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900649 task_list_.push_back(item);
initial.commit3f4a7322008-07-27 06:49:38 +0900650 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900651
652 void RecordEnd(TaskType type, int cookie) {
653 TaskItem item(type, cookie, false);
pkasting@chromium.org9fc87072010-10-19 11:31:03 +0900654 DVLOG(1) << item;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900655 task_list_.push_back(item);
initial.commit3f4a7322008-07-27 06:49:38 +0900656 }
657
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900658 size_t Size() {
659 return task_list_.size();
initial.commit3f4a7322008-07-27 06:49:38 +0900660 }
661
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900662 TaskItem Get(int n) {
663 return task_list_[n];
initial.commit3f4a7322008-07-27 06:49:38 +0900664 }
665
666 private:
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900667 std::vector<TaskItem> task_list_;
initial.commit3f4a7322008-07-27 06:49:38 +0900668};
669
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900670// Saves the order the tasks ran.
671void OrderedFunc(TaskList* order, int cookie) {
672 order->RecordStart(ORDERERD, cookie);
673 order->RecordEnd(ORDERERD, cookie);
674}
675
darin@google.com12d40bb2008-08-20 03:36:23 +0900676#if defined(OS_WIN)
677
initial.commit3f4a7322008-07-27 06:49:38 +0900678// MessageLoop implicitly start a "modal message loop". Modal dialog boxes,
679// common controls (like OpenFile) and StartDoc printing function can cause
680// implicit message loops.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900681void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) {
682 order->RecordStart(MESSAGEBOX, cookie);
683 if (is_reentrant)
684 MessageLoop::current()->SetNestableTasksAllowed(true);
685 MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK);
686 order->RecordEnd(MESSAGEBOX, cookie);
687}
initial.commit3f4a7322008-07-27 06:49:38 +0900688
689// Will end the MessageBox.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900690void EndDialogFunc(TaskList* order, int cookie) {
691 order->RecordStart(ENDDIALOG, cookie);
692 HWND window = GetActiveWindow();
693 if (window != NULL) {
694 EXPECT_NE(EndDialog(window, IDCONTINUE), 0);
695 // Cheap way to signal that the window wasn't found if RunEnd() isn't
696 // called.
697 order->RecordEnd(ENDDIALOG, cookie);
initial.commit3f4a7322008-07-27 06:49:38 +0900698 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900699}
initial.commit3f4a7322008-07-27 06:49:38 +0900700
darin@google.com12d40bb2008-08-20 03:36:23 +0900701#endif // defined(OS_WIN)
702
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900703void RecursiveFunc(TaskList* order, int cookie, int depth,
704 bool is_reentrant) {
705 order->RecordStart(RECURSIVE, cookie);
706 if (depth > 0) {
707 if (is_reentrant)
708 MessageLoop::current()->SetNestableTasksAllowed(true);
709 MessageLoop::current()->PostTask(
710 FROM_HERE,
711 base::Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant));
initial.commit3f4a7322008-07-27 06:49:38 +0900712 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900713 order->RecordEnd(RECURSIVE, cookie);
714}
initial.commit3f4a7322008-07-27 06:49:38 +0900715
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900716void RecursiveSlowFunc(TaskList* order, int cookie, int depth,
717 bool is_reentrant) {
718 RecursiveFunc(order, cookie, depth, is_reentrant);
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900719 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900720}
initial.commit3f4a7322008-07-27 06:49:38 +0900721
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900722void QuitFunc(TaskList* order, int cookie) {
723 order->RecordStart(QUITMESSAGELOOP, cookie);
724 MessageLoop::current()->Quit();
725 order->RecordEnd(QUITMESSAGELOOP, cookie);
726}
initial.commit3f4a7322008-07-27 06:49:38 +0900727
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900728void SleepFunc(TaskList* order, int cookie, TimeDelta delay) {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900729 order->RecordStart(SLEEP, cookie);
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +0900730 PlatformThread::Sleep(delay);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900731 order->RecordEnd(SLEEP, cookie);
732}
mark@chromium.org3ae027a2009-06-26 04:23:11 +0900733
darin@google.coma2ac02b2008-08-15 13:32:57 +0900734#if defined(OS_WIN)
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900735void RecursiveFuncWin(MessageLoop* target,
736 HANDLE event,
737 bool expect_window,
738 TaskList* order,
739 bool is_reentrant) {
740 target->PostTask(FROM_HERE,
741 base::Bind(&RecursiveFunc, order, 1, 2, is_reentrant));
742 target->PostTask(FROM_HERE,
743 base::Bind(&MessageBoxFunc, order, 2, is_reentrant));
744 target->PostTask(FROM_HERE,
745 base::Bind(&RecursiveFunc, order, 3, 2, is_reentrant));
746 // The trick here is that for recursive task processing, this task will be
747 // ran _inside_ the MessageBox message loop, dismissing the MessageBox
748 // without a chance.
749 // For non-recursive task processing, this will be executed _after_ the
750 // MessageBox will have been dismissed by the code below, where
751 // expect_window_ is true.
752 target->PostTask(FROM_HERE,
753 base::Bind(&EndDialogFunc, order, 4));
754 target->PostTask(FROM_HERE,
755 base::Bind(&QuitFunc, order, 5));
darin@google.coma2ac02b2008-08-15 13:32:57 +0900756
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900757 // Enforce that every tasks are sent before starting to run the main thread
758 // message loop.
759 ASSERT_TRUE(SetEvent(event));
initial.commit3f4a7322008-07-27 06:49:38 +0900760
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900761 // Poll for the MessageBox. Don't do this at home! At the speed we do it,
762 // you will never realize one MessageBox was shown.
763 for (; expect_window;) {
764 HWND window = FindWindow(L"#32770", kMessageBoxTitle);
765 if (window) {
766 // Dismiss it.
767 for (;;) {
768 HWND button = FindWindowEx(window, NULL, L"Button", NULL);
769 if (button != NULL) {
770 EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0));
771 EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0));
772 break;
initial.commit3f4a7322008-07-27 06:49:38 +0900773 }
initial.commit3f4a7322008-07-27 06:49:38 +0900774 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900775 break;
initial.commit3f4a7322008-07-27 06:49:38 +0900776 }
777 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900778}
initial.commit3f4a7322008-07-27 06:49:38 +0900779
darin@google.coma2ac02b2008-08-15 13:32:57 +0900780#endif // defined(OS_WIN)
781
darin@google.comd936b5b2008-08-26 14:53:57 +0900782void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) {
783 MessageLoop loop(message_loop_type);
initial.commit3f4a7322008-07-27 06:49:38 +0900784
initial.commit3f4a7322008-07-27 06:49:38 +0900785 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
786 TaskList order;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900787 MessageLoop::current()->PostTask(
788 FROM_HERE,
789 base::Bind(&RecursiveFunc, &order, 1, 2, false));
790 MessageLoop::current()->PostTask(
791 FROM_HERE,
792 base::Bind(&RecursiveFunc, &order, 2, 2, false));
793 MessageLoop::current()->PostTask(
794 FROM_HERE,
795 base::Bind(&QuitFunc, &order, 3));
initial.commit3f4a7322008-07-27 06:49:38 +0900796
797 MessageLoop::current()->Run();
798
799 // FIFO order.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900800 ASSERT_EQ(14U, order.Size());
801 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
802 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
803 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
804 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
805 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
806 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
807 EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
808 EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
809 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
810 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
811 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
812 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
813 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
814 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
initial.commit3f4a7322008-07-27 06:49:38 +0900815}
816
mark@chromium.orgee945952011-02-18 04:25:04 +0900817void RunTest_RecursiveDenial3(MessageLoop::Type message_loop_type) {
818 MessageLoop loop(message_loop_type);
819
820 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
821 TaskList order;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900822 MessageLoop::current()->PostTask(
823 FROM_HERE, base::Bind(&RecursiveSlowFunc, &order, 1, 2, false));
824 MessageLoop::current()->PostTask(
825 FROM_HERE, base::Bind(&RecursiveSlowFunc, &order, 2, 2, false));
826 MessageLoop::current()->PostDelayedTask(
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900827 FROM_HERE,
828 base::Bind(&OrderedFunc, &order, 3),
829 TimeDelta::FromMilliseconds(5));
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900830 MessageLoop::current()->PostDelayedTask(
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +0900831 FROM_HERE,
832 base::Bind(&QuitFunc, &order, 4),
833 TimeDelta::FromMilliseconds(5));
mark@chromium.orgee945952011-02-18 04:25:04 +0900834
835 MessageLoop::current()->Run();
836
837 // FIFO order.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900838 ASSERT_EQ(16U, order.Size());
839 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
840 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
841 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
842 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
843 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true));
844 EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false));
845 EXPECT_EQ(order.Get(6), TaskItem(ORDERERD, 3, true));
846 EXPECT_EQ(order.Get(7), TaskItem(ORDERERD, 3, false));
847 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
848 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
849 EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true));
850 EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false));
851 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true));
852 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false));
853 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true));
854 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false));
mark@chromium.orgee945952011-02-18 04:25:04 +0900855}
856
darin@google.comd936b5b2008-08-26 14:53:57 +0900857void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) {
858 MessageLoop loop(message_loop_type);
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900859
initial.commit3f4a7322008-07-27 06:49:38 +0900860 TaskList order;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900861 MessageLoop::current()->PostTask(
862 FROM_HERE, base::Bind(&RecursiveFunc, &order, 1, 2, true));
863 MessageLoop::current()->PostTask(
864 FROM_HERE, base::Bind(&RecursiveFunc, &order, 2, 2, true));
865 MessageLoop::current()->PostTask(
866 FROM_HERE, base::Bind(&QuitFunc, &order, 3));
initial.commit3f4a7322008-07-27 06:49:38 +0900867
868 MessageLoop::current()->Run();
869
870 // FIFO order.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900871 ASSERT_EQ(14U, order.Size());
872 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
873 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
874 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
875 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
876 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
877 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
878 EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
879 EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
880 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
881 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
882 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
883 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
884 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
885 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
initial.commit3f4a7322008-07-27 06:49:38 +0900886}
887
darin@google.coma2ac02b2008-08-15 13:32:57 +0900888#if defined(OS_WIN)
889// TODO(darin): These tests need to be ported since they test critical
890// message loop functionality.
891
initial.commit3f4a7322008-07-27 06:49:38 +0900892// A side effect of this test is the generation a beep. Sorry.
darin@google.comd936b5b2008-08-26 14:53:57 +0900893void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
894 MessageLoop loop(message_loop_type);
895
initial.commit3f4a7322008-07-27 06:49:38 +0900896 Thread worker("RecursiveDenial2_worker");
darin@google.comd936b5b2008-08-26 14:53:57 +0900897 Thread::Options options;
898 options.message_loop_type = message_loop_type;
899 ASSERT_EQ(true, worker.StartWithOptions(options));
initial.commit3f4a7322008-07-27 06:49:38 +0900900 TaskList order;
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +0900901 base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
initial.commit3f4a7322008-07-27 06:49:38 +0900902 worker.message_loop()->PostTask(FROM_HERE,
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900903 base::Bind(&RecursiveFuncWin,
904 MessageLoop::current(),
905 event.Get(),
906 true,
907 &order,
908 false));
initial.commit3f4a7322008-07-27 06:49:38 +0900909 // Let the other thread execute.
910 WaitForSingleObject(event, INFINITE);
911 MessageLoop::current()->Run();
912
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900913 ASSERT_EQ(order.Size(), 17);
914 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
915 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
916 EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
917 EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false));
918 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true));
919 EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false));
920 // When EndDialogFunc is processed, the window is already dismissed, hence no
initial.commit3f4a7322008-07-27 06:49:38 +0900921 // "end" entry.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900922 EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true));
923 EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true));
924 EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false));
925 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true));
926 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false));
927 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true));
928 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false));
929 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true));
930 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false));
931 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true));
932 EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false));
initial.commit3f4a7322008-07-27 06:49:38 +0900933}
934
darin@google.comd936b5b2008-08-26 14:53:57 +0900935// A side effect of this test is the generation a beep. Sorry. This test also
936// needs to process windows messages on the current thread.
937void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
938 MessageLoop loop(message_loop_type);
939
initial.commit3f4a7322008-07-27 06:49:38 +0900940 Thread worker("RecursiveSupport2_worker");
darin@google.comd936b5b2008-08-26 14:53:57 +0900941 Thread::Options options;
942 options.message_loop_type = message_loop_type;
943 ASSERT_EQ(true, worker.StartWithOptions(options));
initial.commit3f4a7322008-07-27 06:49:38 +0900944 TaskList order;
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +0900945 base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
initial.commit3f4a7322008-07-27 06:49:38 +0900946 worker.message_loop()->PostTask(FROM_HERE,
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900947 base::Bind(&RecursiveFuncWin,
948 MessageLoop::current(),
949 event.Get(),
950 false,
951 &order,
952 true));
initial.commit3f4a7322008-07-27 06:49:38 +0900953 // Let the other thread execute.
954 WaitForSingleObject(event, INFINITE);
955 MessageLoop::current()->Run();
956
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900957 ASSERT_EQ(order.Size(), 18);
958 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
959 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
960 EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
initial.commit3f4a7322008-07-27 06:49:38 +0900961 // Note that this executes in the MessageBox modal loop.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900962 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true));
963 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false));
964 EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true));
965 EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false));
966 EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false));
967 /* The order can subtly change here. The reason is that when RecursiveFunc(1)
initial.commit3f4a7322008-07-27 06:49:38 +0900968 is called in the main thread, if it is faster than getting to the
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900969 PostTask(FROM_HERE, base::Bind(&QuitFunc) execution, the order of task
970 execution can change. We don't care anyway that the order isn't correct.
971 EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, true));
972 EXPECT_EQ(order.Get(9), TaskItem(QUITMESSAGELOOP, 5, false));
973 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
974 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
initial.commit3f4a7322008-07-27 06:49:38 +0900975 */
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900976 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, true));
977 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 3, false));
978 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, true));
979 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 1, false));
980 EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, true));
981 EXPECT_EQ(order.Get(17), TaskItem(RECURSIVE, 3, false));
initial.commit3f4a7322008-07-27 06:49:38 +0900982}
983
darin@google.coma2ac02b2008-08-15 13:32:57 +0900984#endif // defined(OS_WIN)
985
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900986void FuncThatPumps(TaskList* order, int cookie) {
987 order->RecordStart(PUMPS, cookie);
dhollowa@chromium.orgec764192012-02-15 04:33:52 +0900988 {
989 MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
990 MessageLoop::current()->RunAllPending();
991 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900992 order->RecordEnd(PUMPS, cookie);
993}
initial.commit3f4a7322008-07-27 06:49:38 +0900994
initial.commit3f4a7322008-07-27 06:49:38 +0900995// Tests that non nestable tasks run in FIFO if there are no nested loops.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900996void RunTest_NonNestableWithNoNesting(
997 MessageLoop::Type message_loop_type) {
darin@google.comd936b5b2008-08-26 14:53:57 +0900998 MessageLoop loop(message_loop_type);
999
initial.commit3f4a7322008-07-27 06:49:38 +09001000 TaskList order;
1001
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001002 MessageLoop::current()->PostNonNestableTask(
1003 FROM_HERE,
1004 base::Bind(&OrderedFunc, &order, 1));
1005 MessageLoop::current()->PostTask(FROM_HERE,
1006 base::Bind(&OrderedFunc, &order, 2));
1007 MessageLoop::current()->PostTask(FROM_HERE,
1008 base::Bind(&QuitFunc, &order, 3));
initial.commit3f4a7322008-07-27 06:49:38 +09001009 MessageLoop::current()->Run();
1010
1011 // FIFO order.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001012 ASSERT_EQ(6U, order.Size());
1013 EXPECT_EQ(order.Get(0), TaskItem(ORDERERD, 1, true));
1014 EXPECT_EQ(order.Get(1), TaskItem(ORDERERD, 1, false));
1015 EXPECT_EQ(order.Get(2), TaskItem(ORDERERD, 2, true));
1016 EXPECT_EQ(order.Get(3), TaskItem(ORDERERD, 2, false));
1017 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
1018 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
initial.commit3f4a7322008-07-27 06:49:38 +09001019}
1020
1021// Tests that non nestable tasks don't run when there's code in the call stack.
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001022void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type,
1023 bool use_delayed) {
darin@google.comd936b5b2008-08-26 14:53:57 +09001024 MessageLoop loop(message_loop_type);
1025
initial.commit3f4a7322008-07-27 06:49:38 +09001026 TaskList order;
1027
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001028 MessageLoop::current()->PostTask(
1029 FROM_HERE,
1030 base::Bind(&FuncThatPumps, &order, 1));
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001031 if (use_delayed) {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001032 MessageLoop::current()->PostNonNestableDelayedTask(
1033 FROM_HERE,
1034 base::Bind(&OrderedFunc, &order, 2),
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001035 TimeDelta::FromMilliseconds(1));
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001036 } else {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001037 MessageLoop::current()->PostNonNestableTask(
1038 FROM_HERE,
1039 base::Bind(&OrderedFunc, &order, 2));
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001040 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001041 MessageLoop::current()->PostTask(FROM_HERE,
1042 base::Bind(&OrderedFunc, &order, 3));
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +09001043 MessageLoop::current()->PostTask(
1044 FROM_HERE,
1045 base::Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50)));
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001046 MessageLoop::current()->PostTask(FROM_HERE,
1047 base::Bind(&OrderedFunc, &order, 5));
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001048 if (use_delayed) {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001049 MessageLoop::current()->PostNonNestableDelayedTask(
1050 FROM_HERE,
1051 base::Bind(&QuitFunc, &order, 6),
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001052 TimeDelta::FromMilliseconds(2));
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001053 } else {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001054 MessageLoop::current()->PostNonNestableTask(
1055 FROM_HERE,
1056 base::Bind(&QuitFunc, &order, 6));
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001057 }
initial.commit3f4a7322008-07-27 06:49:38 +09001058
initial.commit3f4a7322008-07-27 06:49:38 +09001059 MessageLoop::current()->Run();
1060
1061 // FIFO order.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001062 ASSERT_EQ(12U, order.Size());
1063 EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true));
1064 EXPECT_EQ(order.Get(1), TaskItem(ORDERERD, 3, true));
1065 EXPECT_EQ(order.Get(2), TaskItem(ORDERERD, 3, false));
1066 EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true));
1067 EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false));
1068 EXPECT_EQ(order.Get(5), TaskItem(ORDERERD, 5, true));
1069 EXPECT_EQ(order.Get(6), TaskItem(ORDERERD, 5, false));
1070 EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false));
1071 EXPECT_EQ(order.Get(8), TaskItem(ORDERERD, 2, true));
1072 EXPECT_EQ(order.Get(9), TaskItem(ORDERERD, 2, false));
1073 EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true));
1074 EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false));
initial.commit3f4a7322008-07-27 06:49:38 +09001075}
1076
darin@google.coma2ac02b2008-08-15 13:32:57 +09001077#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +09001078
darin@google.comd936b5b2008-08-26 14:53:57 +09001079class DispatcherImpl : public MessageLoopForUI::Dispatcher {
initial.commit3f4a7322008-07-27 06:49:38 +09001080 public:
1081 DispatcherImpl() : dispatch_count_(0) {}
1082
1083 virtual bool Dispatch(const MSG& msg) {
1084 ::TranslateMessage(&msg);
1085 ::DispatchMessage(&msg);
jianli@chromium.orga0ce9582010-01-16 03:49:58 +09001086 // Do not count WM_TIMER since it is not what we post and it will cause
1087 // flakiness.
1088 if (msg.message != WM_TIMER)
1089 ++dispatch_count_;
1090 // We treat WM_LBUTTONUP as the last message.
1091 return msg.message != WM_LBUTTONUP;
initial.commit3f4a7322008-07-27 06:49:38 +09001092 }
1093
1094 int dispatch_count_;
1095};
1096
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001097void MouseDownUp() {
1098 PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
1099 PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
1100}
1101
darin@google.comd936b5b2008-08-26 14:53:57 +09001102void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
1103 MessageLoop loop(message_loop_type);
initial.commit3f4a7322008-07-27 06:49:38 +09001104
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001105 MessageLoop::current()->PostDelayedTask(
1106 FROM_HERE,
1107 base::Bind(&MouseDownUp),
1108 TimeDelta::FromMilliseconds(100));
initial.commit3f4a7322008-07-27 06:49:38 +09001109 DispatcherImpl dispatcher;
oshima@google.com08ff65e2011-10-24 16:19:51 +09001110 MessageLoopForUI::current()->RunWithDispatcher(&dispatcher);
initial.commit3f4a7322008-07-27 06:49:38 +09001111 ASSERT_EQ(2, dispatcher.dispatch_count_);
1112}
darin@google.coma2ac02b2008-08-15 13:32:57 +09001113
jianli@chromium.orga0ce9582010-01-16 03:49:58 +09001114LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) {
1115 if (code == base::MessagePumpForUI::kMessageFilterCode) {
1116 MSG* msg = reinterpret_cast<MSG*>(lparam);
1117 if (msg->message == WM_LBUTTONDOWN)
1118 return TRUE;
1119 }
1120 return FALSE;
1121}
1122
1123void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) {
1124 MessageLoop loop(message_loop_type);
1125
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001126 MessageLoop::current()->PostDelayedTask(
1127 FROM_HERE,
1128 base::Bind(&MouseDownUp),
1129 TimeDelta::FromMilliseconds(100));
jianli@chromium.orga0ce9582010-01-16 03:49:58 +09001130 HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER,
1131 MsgFilterProc,
1132 NULL,
1133 GetCurrentThreadId());
1134 DispatcherImpl dispatcher;
oshima@google.com08ff65e2011-10-24 16:19:51 +09001135 MessageLoopForUI::current()->RunWithDispatcher(&dispatcher);
jianli@chromium.orga0ce9582010-01-16 03:49:58 +09001136 ASSERT_EQ(1, dispatcher.dispatch_count_);
1137 UnhookWindowsHookEx(msg_hook);
1138}
1139
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001140class TestIOHandler : public MessageLoopForIO::IOHandler {
1141 public:
rvargas@google.com73887542008-11-08 06:52:15 +09001142 TestIOHandler(const wchar_t* name, HANDLE signal, bool wait);
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001143
rvargas@google.com73887542008-11-08 06:52:15 +09001144 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
1145 DWORD bytes_transfered, DWORD error);
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001146
rvargas@google.com73887542008-11-08 06:52:15 +09001147 void Init();
1148 void WaitForIO();
1149 OVERLAPPED* context() { return &context_.overlapped; }
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001150 DWORD size() { return sizeof(buffer_); }
1151
1152 private:
1153 char buffer_[48];
rvargas@google.com73887542008-11-08 06:52:15 +09001154 MessageLoopForIO::IOContext context_;
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001155 HANDLE signal_;
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001156 base::win::ScopedHandle file_;
rvargas@google.com73887542008-11-08 06:52:15 +09001157 bool wait_;
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001158};
1159
rvargas@google.com73887542008-11-08 06:52:15 +09001160TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait)
1161 : signal_(signal), wait_(wait) {
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001162 memset(buffer_, 0, sizeof(buffer_));
1163 memset(&context_, 0, sizeof(context_));
rvargas@google.com73887542008-11-08 06:52:15 +09001164 context_.handler = this;
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001165
1166 file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1167 FILE_FLAG_OVERLAPPED, NULL));
1168 EXPECT_TRUE(file_.IsValid());
1169}
1170
rvargas@google.com73887542008-11-08 06:52:15 +09001171void TestIOHandler::Init() {
1172 MessageLoopForIO::current()->RegisterIOHandler(file_, this);
1173
1174 DWORD read;
1175 EXPECT_FALSE(ReadFile(file_, buffer_, size(), &read, context()));
1176 EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
1177 if (wait_)
1178 WaitForIO();
1179}
1180
1181void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
1182 DWORD bytes_transfered, DWORD error) {
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001183 ASSERT_TRUE(context == &context_);
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001184 ASSERT_TRUE(SetEvent(signal_));
1185}
1186
rvargas@google.com73887542008-11-08 06:52:15 +09001187void TestIOHandler::WaitForIO() {
1188 EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this));
1189 EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this));
1190}
1191
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001192void RunTest_IOHandler() {
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001193 base::win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001194 ASSERT_TRUE(callback_called.IsValid());
1195
1196 const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe";
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001197 base::win::ScopedHandle server(
1198 CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001199 ASSERT_TRUE(server.IsValid());
1200
1201 Thread thread("IOHandler test");
1202 Thread::Options options;
1203 options.message_loop_type = MessageLoop::TYPE_IO;
1204 ASSERT_TRUE(thread.StartWithOptions(options));
1205
1206 MessageLoop* thread_loop = thread.message_loop();
1207 ASSERT_TRUE(NULL != thread_loop);
1208
rvargas@google.com73887542008-11-08 06:52:15 +09001209 TestIOHandler handler(kPipeName, callback_called, false);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001210 thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
1211 base::Unretained(&handler)));
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +09001212 // Make sure the thread runs and sleeps for lack of work.
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001213 base::PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001214
1215 const char buffer[] = "Hello there!";
1216 DWORD written;
1217 EXPECT_TRUE(WriteFile(server, buffer, sizeof(buffer), &written, NULL));
1218
1219 DWORD result = WaitForSingleObject(callback_called, 1000);
1220 EXPECT_EQ(WAIT_OBJECT_0, result);
1221
1222 thread.Stop();
1223}
1224
rvargas@google.com73887542008-11-08 06:52:15 +09001225void RunTest_WaitForIO() {
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001226 base::win::ScopedHandle callback1_called(
1227 CreateEvent(NULL, TRUE, FALSE, NULL));
1228 base::win::ScopedHandle callback2_called(
1229 CreateEvent(NULL, TRUE, FALSE, NULL));
rvargas@google.com73887542008-11-08 06:52:15 +09001230 ASSERT_TRUE(callback1_called.IsValid());
1231 ASSERT_TRUE(callback2_called.IsValid());
1232
1233 const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1";
1234 const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2";
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001235 base::win::ScopedHandle server1(
1236 CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
1237 base::win::ScopedHandle server2(
1238 CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
rvargas@google.com73887542008-11-08 06:52:15 +09001239 ASSERT_TRUE(server1.IsValid());
1240 ASSERT_TRUE(server2.IsValid());
1241
1242 Thread thread("IOHandler test");
1243 Thread::Options options;
1244 options.message_loop_type = MessageLoop::TYPE_IO;
1245 ASSERT_TRUE(thread.StartWithOptions(options));
1246
1247 MessageLoop* thread_loop = thread.message_loop();
1248 ASSERT_TRUE(NULL != thread_loop);
1249
1250 TestIOHandler handler1(kPipeName1, callback1_called, false);
1251 TestIOHandler handler2(kPipeName2, callback2_called, true);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001252 thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
1253 base::Unretained(&handler1)));
1254 // TODO(ajwong): Do we really need such long Sleeps in ths function?
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +09001255 // Make sure the thread runs and sleeps for lack of work.
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001256 TimeDelta delay = TimeDelta::FromMilliseconds(100);
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +09001257 base::PlatformThread::Sleep(delay);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001258 thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
1259 base::Unretained(&handler2)));
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +09001260 base::PlatformThread::Sleep(delay);
rvargas@google.com73887542008-11-08 06:52:15 +09001261
1262 // At this time handler1 is waiting to be called, and the thread is waiting
1263 // on the Init method of handler2, filtering only handler2 callbacks.
1264
1265 const char buffer[] = "Hello there!";
1266 DWORD written;
1267 EXPECT_TRUE(WriteFile(server1, buffer, sizeof(buffer), &written, NULL));
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +09001268 base::PlatformThread::Sleep(2 * delay);
rvargas@google.com73887542008-11-08 06:52:15 +09001269 EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called, 0)) <<
1270 "handler1 has not been called";
1271
1272 EXPECT_TRUE(WriteFile(server2, buffer, sizeof(buffer), &written, NULL));
1273
1274 HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() };
1275 DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000);
1276 EXPECT_EQ(WAIT_OBJECT_0, result);
1277
1278 thread.Stop();
1279}
1280
darin@google.comd936b5b2008-08-26 14:53:57 +09001281#endif // defined(OS_WIN)
license.botf003cfe2008-08-24 09:55:55 +09001282
darin@google.comd936b5b2008-08-26 14:53:57 +09001283} // namespace
1284
1285//-----------------------------------------------------------------------------
1286// Each test is run against each type of MessageLoop. That way we are sure
1287// that message loops work properly in all configurations. Of course, in some
1288// cases, a unit test may only be for a particular type of loop.
1289
1290TEST(MessageLoopTest, PostTask) {
1291 RunTest_PostTask(MessageLoop::TYPE_DEFAULT);
1292 RunTest_PostTask(MessageLoop::TYPE_UI);
1293 RunTest_PostTask(MessageLoop::TYPE_IO);
1294}
1295
1296TEST(MessageLoopTest, PostTask_SEH) {
1297 RunTest_PostTask_SEH(MessageLoop::TYPE_DEFAULT);
1298 RunTest_PostTask_SEH(MessageLoop::TYPE_UI);
1299 RunTest_PostTask_SEH(MessageLoop::TYPE_IO);
1300}
1301
darin@google.combe165ae2008-09-07 17:08:29 +09001302TEST(MessageLoopTest, PostDelayedTask_Basic) {
1303 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_DEFAULT);
1304 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_UI);
1305 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_IO);
1306}
1307
1308TEST(MessageLoopTest, PostDelayedTask_InDelayOrder) {
1309 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_DEFAULT);
1310 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_UI);
1311 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_IO);
1312}
1313
1314TEST(MessageLoopTest, PostDelayedTask_InPostOrder) {
1315 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_DEFAULT);
1316 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_UI);
1317 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_IO);
1318}
1319
1320TEST(MessageLoopTest, PostDelayedTask_InPostOrder_2) {
1321 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_DEFAULT);
1322 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_UI);
1323 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_IO);
1324}
1325
1326TEST(MessageLoopTest, PostDelayedTask_InPostOrder_3) {
1327 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_DEFAULT);
1328 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_UI);
1329 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_IO);
1330}
1331
darin@chromium.orgb2d33452008-09-24 04:19:20 +09001332TEST(MessageLoopTest, PostDelayedTask_SharedTimer) {
1333 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_DEFAULT);
1334 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_UI);
1335 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_IO);
1336}
1337
1338#if defined(OS_WIN)
1339TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
1340 RunTest_PostDelayedTask_SharedTimer_SubPump();
1341}
1342#endif
1343
jhawkins@chromium.org9b8ceac2010-05-26 05:13:36 +09001344// TODO(darin): MessageLoop does not support deleting all tasks in the
1345// destructor.
phajdan.jr@chromium.org101b63b2010-07-27 06:23:18 +09001346// Fails, http://crbug.com/50272.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001347TEST(MessageLoopTest, FAILS_EnsureDeletion) {
1348 RunTest_EnsureDeletion(MessageLoop::TYPE_DEFAULT);
1349 RunTest_EnsureDeletion(MessageLoop::TYPE_UI);
1350 RunTest_EnsureDeletion(MessageLoop::TYPE_IO);
darin@chromium.orge3af17f2008-09-10 09:37:07 +09001351}
1352
jhawkins@chromium.org9b8ceac2010-05-26 05:13:36 +09001353// TODO(darin): MessageLoop does not support deleting all tasks in the
1354// destructor.
phajdan.jr@chromium.org101b63b2010-07-27 06:23:18 +09001355// Fails, http://crbug.com/50272.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001356TEST(MessageLoopTest, FAILS_EnsureDeletion_Chain) {
1357 RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_DEFAULT);
1358 RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_UI);
1359 RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_IO);
darin@chromium.orge3af17f2008-09-10 09:37:07 +09001360}
1361
darin@google.comd936b5b2008-08-26 14:53:57 +09001362#if defined(OS_WIN)
1363TEST(MessageLoopTest, Crasher) {
1364 RunTest_Crasher(MessageLoop::TYPE_DEFAULT);
1365 RunTest_Crasher(MessageLoop::TYPE_UI);
1366 RunTest_Crasher(MessageLoop::TYPE_IO);
1367}
1368
1369TEST(MessageLoopTest, CrasherNasty) {
1370 RunTest_CrasherNasty(MessageLoop::TYPE_DEFAULT);
1371 RunTest_CrasherNasty(MessageLoop::TYPE_UI);
1372 RunTest_CrasherNasty(MessageLoop::TYPE_IO);
1373}
1374#endif // defined(OS_WIN)
1375
1376TEST(MessageLoopTest, Nesting) {
1377 RunTest_Nesting(MessageLoop::TYPE_DEFAULT);
1378 RunTest_Nesting(MessageLoop::TYPE_UI);
1379 RunTest_Nesting(MessageLoop::TYPE_IO);
1380}
1381
1382TEST(MessageLoopTest, RecursiveDenial1) {
1383 RunTest_RecursiveDenial1(MessageLoop::TYPE_DEFAULT);
1384 RunTest_RecursiveDenial1(MessageLoop::TYPE_UI);
1385 RunTest_RecursiveDenial1(MessageLoop::TYPE_IO);
1386}
1387
mark@chromium.orgee945952011-02-18 04:25:04 +09001388TEST(MessageLoopTest, RecursiveDenial3) {
1389 RunTest_RecursiveDenial3(MessageLoop::TYPE_DEFAULT);
1390 RunTest_RecursiveDenial3(MessageLoop::TYPE_UI);
1391 RunTest_RecursiveDenial3(MessageLoop::TYPE_IO);
1392}
1393
darin@google.comd936b5b2008-08-26 14:53:57 +09001394TEST(MessageLoopTest, RecursiveSupport1) {
1395 RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT);
1396 RunTest_RecursiveSupport1(MessageLoop::TYPE_UI);
1397 RunTest_RecursiveSupport1(MessageLoop::TYPE_IO);
1398}
1399
1400#if defined(OS_WIN)
maruel@chromium.orga989c1f2010-05-19 23:33:44 +09001401// This test occasionally hangs http://crbug.com/44567
1402TEST(MessageLoopTest, DISABLED_RecursiveDenial2) {
darin@google.comd936b5b2008-08-26 14:53:57 +09001403 RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
1404 RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
1405 RunTest_RecursiveDenial2(MessageLoop::TYPE_IO);
1406}
1407
1408TEST(MessageLoopTest, RecursiveSupport2) {
1409 // This test requires a UI loop
1410 RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
1411}
1412#endif // defined(OS_WIN)
1413
1414TEST(MessageLoopTest, NonNestableWithNoNesting) {
1415 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_DEFAULT);
1416 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_UI);
1417 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_IO);
1418}
1419
1420TEST(MessageLoopTest, NonNestableInNestedLoop) {
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001421 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, false);
1422 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, false);
1423 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, false);
1424}
1425
1426TEST(MessageLoopTest, NonNestableDelayedInNestedLoop) {
1427 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, true);
1428 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, true);
1429 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, true);
darin@google.comd936b5b2008-08-26 14:53:57 +09001430}
1431
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001432void PostNTasksThenQuit(int posts_remaining) {
1433 if (posts_remaining > 1) {
1434 MessageLoop::current()->PostTask(
1435 FROM_HERE,
1436 base::Bind(&PostNTasksThenQuit, posts_remaining - 1));
1437 } else {
1438 MessageLoop::current()->Quit();
willchan@chromium.orga9047632010-06-10 06:20:41 +09001439 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001440}
willchan@chromium.orga9047632010-06-10 06:20:41 +09001441
1442class DummyTaskObserver : public MessageLoop::TaskObserver {
1443 public:
thestig@chromium.org60bd7c02010-07-23 14:23:13 +09001444 explicit DummyTaskObserver(int num_tasks)
willchan@chromium.orga9047632010-06-10 06:20:41 +09001445 : num_tasks_started_(0),
1446 num_tasks_processed_(0),
1447 num_tasks_(num_tasks) {}
1448
1449 virtual ~DummyTaskObserver() {}
1450
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001451 virtual void WillProcessTask(TimeTicks time_posted) OVERRIDE {
willchan@chromium.orga9047632010-06-10 06:20:41 +09001452 num_tasks_started_++;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001453 EXPECT_TRUE(time_posted != TimeTicks());
willchan@chromium.orga9047632010-06-10 06:20:41 +09001454 EXPECT_LE(num_tasks_started_, num_tasks_);
1455 EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
1456 }
1457
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001458 virtual void DidProcessTask(TimeTicks time_posted) OVERRIDE {
willchan@chromium.orga9047632010-06-10 06:20:41 +09001459 num_tasks_processed_++;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001460 EXPECT_TRUE(time_posted != TimeTicks());
willchan@chromium.orga9047632010-06-10 06:20:41 +09001461 EXPECT_LE(num_tasks_started_, num_tasks_);
1462 EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
1463 }
1464
1465 int num_tasks_started() const { return num_tasks_started_; }
1466 int num_tasks_processed() const { return num_tasks_processed_; }
1467
1468 private:
1469 int num_tasks_started_;
1470 int num_tasks_processed_;
1471 const int num_tasks_;
1472
1473 DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver);
1474};
1475
1476TEST(MessageLoopTest, TaskObserver) {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001477 const int kNumPosts = 6;
1478 DummyTaskObserver observer(kNumPosts);
willchan@chromium.orga9047632010-06-10 06:20:41 +09001479
1480 MessageLoop loop;
1481 loop.AddTaskObserver(&observer);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001482 loop.PostTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, kNumPosts));
willchan@chromium.orga9047632010-06-10 06:20:41 +09001483 loop.Run();
1484 loop.RemoveTaskObserver(&observer);
1485
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001486 EXPECT_EQ(kNumPosts, observer.num_tasks_started());
1487 EXPECT_EQ(kNumPosts, observer.num_tasks_processed());
willchan@chromium.orga9047632010-06-10 06:20:41 +09001488}
1489
darin@google.comd936b5b2008-08-26 14:53:57 +09001490#if defined(OS_WIN)
darin@google.comd936b5b2008-08-26 14:53:57 +09001491TEST(MessageLoopTest, Dispatcher) {
1492 // This test requires a UI loop
1493 RunTest_Dispatcher(MessageLoop::TYPE_UI);
1494}
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001495
jianli@chromium.orga0ce9582010-01-16 03:49:58 +09001496TEST(MessageLoopTest, DispatcherWithMessageHook) {
1497 // This test requires a UI loop
1498 RunTest_DispatcherWithMessageHook(MessageLoop::TYPE_UI);
1499}
1500
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001501TEST(MessageLoopTest, IOHandler) {
1502 RunTest_IOHandler();
1503}
rvargas@google.com73887542008-11-08 06:52:15 +09001504
1505TEST(MessageLoopTest, WaitForIO) {
1506 RunTest_WaitForIO();
1507}
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001508
1509TEST(MessageLoopTest, HighResolutionTimer) {
1510 MessageLoop loop;
1511
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001512 const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5);
1513 const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100);
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001514
hans@chromium.orgfa5bf992011-01-14 19:36:28 +09001515 EXPECT_FALSE(loop.high_resolution_timers_enabled());
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001516
1517 // Post a fast task to enable the high resolution timers.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001518 loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001519 kFastTimer);
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001520 loop.Run();
hans@chromium.orgfa5bf992011-01-14 19:36:28 +09001521 EXPECT_TRUE(loop.high_resolution_timers_enabled());
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001522
1523 // Post a slow task and verify high resolution timers
1524 // are still enabled.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001525 loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001526 kSlowTimer);
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001527 loop.Run();
hans@chromium.orgfa5bf992011-01-14 19:36:28 +09001528 EXPECT_TRUE(loop.high_resolution_timers_enabled());
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001529
1530 // Wait for a while so that high-resolution mode elapses.
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +09001531 base::PlatformThread::Sleep(TimeDelta::FromMilliseconds(
1532 MessageLoop::kHighResolutionTimerModeLeaseTimeMs));
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001533
1534 // Post a slow task to disable the high resolution timers.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001535 loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001536 kSlowTimer);
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001537 loop.Run();
hans@chromium.orgfa5bf992011-01-14 19:36:28 +09001538 EXPECT_FALSE(loop.high_resolution_timers_enabled());
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001539}
1540
darin@google.comd936b5b2008-08-26 14:53:57 +09001541#endif // defined(OS_WIN)
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001542
abarth@chromium.org1f1c2172010-12-01 17:45:51 +09001543#if defined(OS_POSIX) && !defined(OS_NACL)
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001544
1545namespace {
1546
wtc@chromium.org961d6d12011-06-22 15:33:05 +09001547class QuitDelegate : public MessageLoopForIO::Watcher {
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001548 public:
1549 virtual void OnFileCanWriteWithoutBlocking(int fd) {
1550 MessageLoop::current()->Quit();
1551 }
1552 virtual void OnFileCanReadWithoutBlocking(int fd) {
1553 MessageLoop::current()->Quit();
1554 }
1555};
1556
jhawkins@chromium.org37848382010-06-11 09:06:19 +09001557TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) {
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001558 // Simulate a MessageLoop that dies before an FileDescriptorWatcher.
1559 // This could happen when people use the Singleton pattern or atexit.
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001560
1561 // Create a file descriptor. Doesn't need to be readable or writable,
1562 // as we don't need to actually get any notifications.
1563 // pipe() is just the easiest way to do it.
1564 int pipefds[2];
1565 int err = pipe(pipefds);
thestig@chromium.org60bd7c02010-07-23 14:23:13 +09001566 ASSERT_EQ(0, err);
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001567 int fd = pipefds[1];
1568 {
1569 // Arrange for controller to live longer than message loop.
wtc@chromium.org961d6d12011-06-22 15:33:05 +09001570 MessageLoopForIO::FileDescriptorWatcher controller;
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001571 {
1572 MessageLoopForIO message_loop;
1573
1574 QuitDelegate delegate;
1575 message_loop.WatchFileDescriptor(fd,
1576 true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
1577 // and don't run the message loop, just destroy it.
1578 }
1579 }
thakis@chromium.org965db9a2010-06-23 09:37:46 +09001580 if (HANDLE_EINTR(close(pipefds[0])) < 0)
1581 PLOG(ERROR) << "close";
1582 if (HANDLE_EINTR(close(pipefds[1])) < 0)
1583 PLOG(ERROR) << "close";
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001584}
1585
1586TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) {
1587 // Verify that it's ok to call StopWatchingFileDescriptor().
1588 // (Errors only showed up in valgrind.)
1589 int pipefds[2];
1590 int err = pipe(pipefds);
thestig@chromium.org60bd7c02010-07-23 14:23:13 +09001591 ASSERT_EQ(0, err);
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001592 int fd = pipefds[1];
1593 {
1594 // Arrange for message loop to live longer than controller.
1595 MessageLoopForIO message_loop;
1596 {
wtc@chromium.org961d6d12011-06-22 15:33:05 +09001597 MessageLoopForIO::FileDescriptorWatcher controller;
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001598
1599 QuitDelegate delegate;
1600 message_loop.WatchFileDescriptor(fd,
1601 true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
1602 controller.StopWatchingFileDescriptor();
1603 }
1604 }
thakis@chromium.org965db9a2010-06-23 09:37:46 +09001605 if (HANDLE_EINTR(close(pipefds[0])) < 0)
1606 PLOG(ERROR) << "close";
1607 if (HANDLE_EINTR(close(pipefds[1])) < 0)
1608 PLOG(ERROR) << "close";
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001609}
1610
willchan@chromium.orga9047632010-06-10 06:20:41 +09001611} // namespace
1612
abarth@chromium.org1f1c2172010-12-01 17:45:51 +09001613#endif // defined(OS_POSIX) && !defined(OS_NACL)
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001614
1615namespace {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001616// Inject a test point for recording the destructor calls for Closure objects
1617// send to MessageLoop::PostTask(). It is awkward usage since we are trying to
1618// hook the actual destruction, which is not a common operation.
1619class DestructionObserverProbe :
1620 public base::RefCounted<DestructionObserverProbe> {
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001621 public:
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001622 DestructionObserverProbe(bool* task_destroyed,
1623 bool* destruction_observer_called)
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001624 : task_destroyed_(task_destroyed),
1625 destruction_observer_called_(destruction_observer_called) {
1626 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001627 virtual ~DestructionObserverProbe() {
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001628 EXPECT_FALSE(*destruction_observer_called_);
1629 *task_destroyed_ = true;
1630 }
1631 virtual void Run() {
1632 // This task should never run.
1633 ADD_FAILURE();
1634 }
1635 private:
1636 bool* task_destroyed_;
1637 bool* destruction_observer_called_;
1638};
1639
1640class MLDestructionObserver : public MessageLoop::DestructionObserver {
1641 public:
1642 MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called)
1643 : task_destroyed_(task_destroyed),
1644 destruction_observer_called_(destruction_observer_called),
1645 task_destroyed_before_message_loop_(false) {
1646 }
1647 virtual void WillDestroyCurrentMessageLoop() {
1648 task_destroyed_before_message_loop_ = *task_destroyed_;
1649 *destruction_observer_called_ = true;
1650 }
1651 bool task_destroyed_before_message_loop() const {
1652 return task_destroyed_before_message_loop_;
1653 }
1654 private:
1655 bool* task_destroyed_;
1656 bool* destruction_observer_called_;
1657 bool task_destroyed_before_message_loop_;
1658};
1659
1660} // namespace
1661
1662TEST(MessageLoopTest, DestructionObserverTest) {
1663 // Verify that the destruction observer gets called at the very end (after
1664 // all the pending tasks have been destroyed).
1665 MessageLoop* loop = new MessageLoop;
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001666 const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001667
1668 bool task_destroyed = false;
1669 bool destruction_observer_called = false;
1670
1671 MLDestructionObserver observer(&task_destroyed, &destruction_observer_called);
1672 loop->AddDestructionObserver(&observer);
1673 loop->PostDelayedTask(
1674 FROM_HERE,
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001675 base::Bind(&DestructionObserverProbe::Run,
1676 new DestructionObserverProbe(&task_destroyed,
1677 &destruction_observer_called)),
tedvessenes@gmail.com9b2870c2012-02-05 01:44:53 +09001678 kDelay);
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001679 delete loop;
1680 EXPECT_TRUE(observer.task_destroyed_before_message_loop());
1681 // The task should have been destroyed when we deleted the loop.
1682 EXPECT_TRUE(task_destroyed);
1683 EXPECT_TRUE(destruction_observer_called);
1684}