blob: 7eb4f4a02ccb7318a1e7ffb4298f49864b041a1c [file] [log] [blame]
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001// Copyright (c) 2011 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"
willchan@chromium.orga9047632010-06-10 06:20:41 +090014#include "base/task.h"
brettw@chromium.org61391822011-01-01 05:02:16 +090015#include "base/threading/platform_thread.h"
brettw@chromium.org5b5f5e02011-01-01 10:01:06 +090016#include "base/threading/thread.h"
initial.commit3f4a7322008-07-27 06:49:38 +090017#include "testing/gtest/include/gtest/gtest.h"
18
darin@google.coma2ac02b2008-08-15 13:32:57 +090019#if defined(OS_WIN)
20#include "base/message_pump_win.h"
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +090021#include "base/win/scoped_handle.h"
darin@google.coma2ac02b2008-08-15 13:32:57 +090022#endif
23
brettw@chromium.org61391822011-01-01 05:02:16 +090024using base::PlatformThread;
darin@google.comd936b5b2008-08-26 14:53:57 +090025using base::Thread;
dsh@google.com0f8dd262008-10-28 05:43:33 +090026using base::Time;
27using base::TimeDelta;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +090028using base::TimeTicks;
darin@google.comd936b5b2008-08-26 14:53:57 +090029
30// TODO(darin): Platform-specific MessageLoop tests should be grouped together
31// to avoid chopping this file up with so many #ifdefs.
darin@google.com12d40bb2008-08-20 03:36:23 +090032
initial.commit3f4a7322008-07-27 06:49:38 +090033namespace {
34
darin@google.comd936b5b2008-08-26 14:53:57 +090035class MessageLoopTest : public testing::Test {};
initial.commit3f4a7322008-07-27 06:49:38 +090036
37class Foo : public base::RefCounted<Foo> {
38 public:
39 Foo() : test_count_(0) {
40 }
41
42 void Test0() {
43 ++test_count_;
44 }
45
46 void Test1ConstRef(const std::string& a) {
47 ++test_count_;
48 result_.append(a);
49 }
50
51 void Test1Ptr(std::string* a) {
52 ++test_count_;
53 result_.append(*a);
54 }
55
56 void Test1Int(int a) {
57 test_count_ += a;
58 }
59
60 void Test2Ptr(std::string* a, std::string* b) {
61 ++test_count_;
62 result_.append(*a);
63 result_.append(*b);
64 }
65
66 void Test2Mixed(const std::string& a, std::string* b) {
67 ++test_count_;
68 result_.append(a);
69 result_.append(*b);
70 }
71
72 int test_count() const { return test_count_; }
73 const std::string& result() const { return result_; }
74
75 private:
jam@chromium.orgb1f47b22009-11-06 06:53:08 +090076 friend class base::RefCounted<Foo>;
77
78 ~Foo() {}
79
initial.commit3f4a7322008-07-27 06:49:38 +090080 int test_count_;
81 std::string result_;
82};
83
ajwong@chromium.org94d2a582011-04-21 01:02:23 +090084// TODO(ajwong): Remove this once we've finished getting rid of the PostTask()
85// compatibility methods.
86void RunTest_PostLegacyTask(MessageLoop::Type message_loop_type) {
darin@google.comd936b5b2008-08-26 14:53:57 +090087 MessageLoop loop(message_loop_type);
initial.commit3f4a7322008-07-27 06:49:38 +090088
initial.commit3f4a7322008-07-27 06:49:38 +090089 // Add tests to message loop
thakis@chromium.org625aa232010-11-01 13:16:27 +090090 scoped_refptr<Foo> foo(new Foo());
initial.commit3f4a7322008-07-27 06:49:38 +090091 std::string a("a"), b("b"), c("c"), d("d");
92 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
93 foo.get(), &Foo::Test0));
94 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
95 foo.get(), &Foo::Test1ConstRef, a));
96 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
97 foo.get(), &Foo::Test1Ptr, &b));
98 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
99 foo.get(), &Foo::Test1Int, 100));
100 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
101 foo.get(), &Foo::Test2Ptr, &a, &c));
102 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
103 foo.get(), &Foo::Test2Mixed, a, &d));
104
105 // After all tests, post a message that will shut down the message loop
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900106 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
107 &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
108
109 // Now kick things off
110 MessageLoop::current()->Run();
111
112 EXPECT_EQ(foo->test_count(), 105);
113 EXPECT_EQ(foo->result(), "abacad");
114}
115
116void RunTest_PostTask(MessageLoop::Type message_loop_type) {
117 MessageLoop loop(message_loop_type);
118
119 // Add tests to message loop
120 scoped_refptr<Foo> foo(new Foo());
121 std::string a("a"), b("b"), c("c"), d("d");
122 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
123 &Foo::Test0, foo.get()));
124 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
125 &Foo::Test1ConstRef, foo.get(), a));
126 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
127 &Foo::Test1Ptr, foo.get(), &b));
128 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
129 &Foo::Test1Int, foo.get(), 100));
130 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
131 &Foo::Test2Ptr, foo.get(), &a, &c));
132 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
133 &Foo::Test2Mixed, foo.get(), a, &d));
134
135 // After all tests, post a message that will shut down the message loop
136 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
137 &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
initial.commit3f4a7322008-07-27 06:49:38 +0900138
139 // Now kick things off
140 MessageLoop::current()->Run();
141
142 EXPECT_EQ(foo->test_count(), 105);
143 EXPECT_EQ(foo->result(), "abacad");
144}
145
darin@google.comd936b5b2008-08-26 14:53:57 +0900146void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) {
147 MessageLoop loop(message_loop_type);
148
initial.commit3f4a7322008-07-27 06:49:38 +0900149 // Add tests to message loop
thakis@chromium.org625aa232010-11-01 13:16:27 +0900150 scoped_refptr<Foo> foo(new Foo());
initial.commit3f4a7322008-07-27 06:49:38 +0900151 std::string a("a"), b("b"), c("c"), d("d");
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900152 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
153 &Foo::Test0, foo.get()));
154 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
155 &Foo::Test1ConstRef, foo.get(), a));
156 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
157 &Foo::Test1Ptr, foo.get(), &b));
158 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
159 &Foo::Test1Int, foo.get(), 100));
160 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
161 &Foo::Test2Ptr, foo.get(), &a, &c));
162 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
163 &Foo::Test2Mixed, foo.get(), a, &d));
initial.commit3f4a7322008-07-27 06:49:38 +0900164
165 // After all tests, post a message that will shut down the message loop
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900166 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
167 &MessageLoop::Quit, base::Unretained(MessageLoop::current())));
initial.commit3f4a7322008-07-27 06:49:38 +0900168
169 // Now kick things off with the SEH block active.
170 MessageLoop::current()->set_exception_restoration(true);
171 MessageLoop::current()->Run();
172 MessageLoop::current()->set_exception_restoration(false);
173
174 EXPECT_EQ(foo->test_count(), 105);
175 EXPECT_EQ(foo->result(), "abacad");
176}
177
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900178// This function runs slowly to simulate a large amount of work being done.
179static void SlowFunc(int pause_ms, int* quit_counter) {
180 PlatformThread::Sleep(pause_ms);
181 if (--(*quit_counter) == 0)
darin@google.combe165ae2008-09-07 17:08:29 +0900182 MessageLoop::current()->Quit();
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900183}
darin@google.combe165ae2008-09-07 17:08:29 +0900184
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900185// This function records the time when Run was called in a Time object, which is
darin@google.combe165ae2008-09-07 17:08:29 +0900186// useful for building a variety of MessageLoop tests.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900187static void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
188 *run_time = Time::Now();
189
darin@google.combe165ae2008-09-07 17:08:29 +0900190 // Cause our Run function to take some time to execute. As a result we can
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900191 // count on subsequent RecordRunTimeFunc()s running at a future time,
darin@google.combe165ae2008-09-07 17:08:29 +0900192 // without worry about the resolution of our system clock being an issue.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900193 SlowFunc(10, quit_counter);
194}
darin@google.combe165ae2008-09-07 17:08:29 +0900195
196void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) {
197 MessageLoop loop(message_loop_type);
198
199 // Test that PostDelayedTask results in a delayed task.
200
201 const int kDelayMS = 100;
202
203 int num_tasks = 1;
204 Time run_time;
205
206 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900207 FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
208 kDelayMS);
darin@google.combe165ae2008-09-07 17:08:29 +0900209
210 Time time_before_run = Time::Now();
211 loop.Run();
212 Time time_after_run = Time::Now();
213
214 EXPECT_EQ(0, num_tasks);
215 EXPECT_LT(kDelayMS, (time_after_run - time_before_run).InMilliseconds());
216}
217
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900218void RunTest_PostDelayedTask_InDelayOrder(
219 MessageLoop::Type message_loop_type) {
darin@google.combe165ae2008-09-07 17:08:29 +0900220 MessageLoop loop(message_loop_type);
221
222 // Test that two tasks with different delays run in the right order.
darin@google.combe165ae2008-09-07 17:08:29 +0900223 int num_tasks = 2;
224 Time run_time1, run_time2;
225
226 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900227 FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), 200);
darin@google.combe165ae2008-09-07 17:08:29 +0900228 // If we get a large pause in execution (due to a context switch) here, this
229 // test could fail.
230 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900231 FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), 10);
darin@google.combe165ae2008-09-07 17:08:29 +0900232
233 loop.Run();
234 EXPECT_EQ(0, num_tasks);
235
236 EXPECT_TRUE(run_time2 < run_time1);
237}
238
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900239void RunTest_PostDelayedTask_InPostOrder(
240 MessageLoop::Type message_loop_type) {
darin@google.combe165ae2008-09-07 17:08:29 +0900241 MessageLoop loop(message_loop_type);
242
243 // Test that two tasks with the same delay run in the order in which they
244 // were posted.
245 //
246 // NOTE: This is actually an approximate test since the API only takes a
247 // "delay" parameter, so we are not exactly simulating two tasks that get
248 // posted at the exact same time. It would be nice if the API allowed us to
249 // specify the desired run time.
250
251 const int kDelayMS = 100;
252
253 int num_tasks = 2;
254 Time run_time1, run_time2;
255
256 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900257 FROM_HERE,
258 base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelayMS);
darin@google.combe165ae2008-09-07 17:08:29 +0900259 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900260 FROM_HERE,
261 base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelayMS);
darin@google.combe165ae2008-09-07 17:08:29 +0900262
263 loop.Run();
264 EXPECT_EQ(0, num_tasks);
265
266 EXPECT_TRUE(run_time1 < run_time2);
267}
268
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900269void RunTest_PostDelayedTask_InPostOrder_2(
270 MessageLoop::Type message_loop_type) {
darin@google.combe165ae2008-09-07 17:08:29 +0900271 MessageLoop loop(message_loop_type);
272
273 // Test that a delayed task still runs after a normal tasks even if the
274 // normal tasks take a long time to run.
275
276 const int kPauseMS = 50;
277
278 int num_tasks = 2;
279 Time run_time;
280
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900281 loop.PostTask(FROM_HERE, base::Bind(&SlowFunc, kPauseMS, &num_tasks));
darin@google.combe165ae2008-09-07 17:08:29 +0900282 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900283 FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks), 10);
darin@google.combe165ae2008-09-07 17:08:29 +0900284
285 Time time_before_run = Time::Now();
286 loop.Run();
287 Time time_after_run = Time::Now();
288
289 EXPECT_EQ(0, num_tasks);
290
291 EXPECT_LT(kPauseMS, (time_after_run - time_before_run).InMilliseconds());
292}
293
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900294void RunTest_PostDelayedTask_InPostOrder_3(
295 MessageLoop::Type message_loop_type) {
darin@google.combe165ae2008-09-07 17:08:29 +0900296 MessageLoop loop(message_loop_type);
297
298 // Test that a delayed task still runs after a pile of normal tasks. The key
299 // difference between this test and the previous one is that here we return
300 // the MessageLoop a lot so we give the MessageLoop plenty of opportunities
301 // to maybe run the delayed task. It should know not to do so until the
302 // delayed task's delay has passed.
303
304 int num_tasks = 11;
305 Time run_time1, run_time2;
306
307 // Clutter the ML with tasks.
308 for (int i = 1; i < num_tasks; ++i)
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900309 loop.PostTask(FROM_HERE,
310 base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks));
darin@google.combe165ae2008-09-07 17:08:29 +0900311
312 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900313 FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), 1);
darin@google.combe165ae2008-09-07 17:08:29 +0900314
315 loop.Run();
316 EXPECT_EQ(0, num_tasks);
317
318 EXPECT_TRUE(run_time2 > run_time1);
319}
320
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900321void RunTest_PostDelayedTask_SharedTimer(
322 MessageLoop::Type message_loop_type) {
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900323 MessageLoop loop(message_loop_type);
324
325 // Test that the interval of the timer, used to run the next delayed task, is
326 // set to a value corresponding to when the next delayed task should run.
327
328 // By setting num_tasks to 1, we ensure that the first task to run causes the
329 // run loop to exit.
330 int num_tasks = 1;
331 Time run_time1, run_time2;
332
333 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900334 FROM_HERE,
335 base::Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
336 1000000);
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900337 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900338 FROM_HERE, base::Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), 10);
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900339
340 Time start_time = Time::Now();
341
342 loop.Run();
343 EXPECT_EQ(0, num_tasks);
344
345 // Ensure that we ran in far less time than the slower timer.
darin@chromium.orgaa119c22008-09-24 04:22:33 +0900346 TimeDelta total_time = Time::Now() - start_time;
347 EXPECT_GT(5000, total_time.InMilliseconds());
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900348
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900349 // In case both timers somehow run at nearly the same time, sleep a little
350 // and then run all pending to force them both to have run. This is just
351 // encouraging flakiness if there is any.
352 PlatformThread::Sleep(100);
353 loop.RunAllPending();
354
355 EXPECT_TRUE(run_time1.is_null());
356 EXPECT_FALSE(run_time2.is_null());
357}
358
359#if defined(OS_WIN)
360
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900361void SubPumpFunc() {
362 MessageLoop::current()->SetNestableTasksAllowed(true);
363 MSG msg;
364 while (GetMessage(&msg, NULL, 0, 0)) {
365 TranslateMessage(&msg);
366 DispatchMessage(&msg);
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900367 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900368 MessageLoop::current()->Quit();
369}
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900370
371void RunTest_PostDelayedTask_SharedTimer_SubPump() {
372 MessageLoop loop(MessageLoop::TYPE_UI);
373
374 // Test that the interval of the timer, used to run the next delayed task, is
375 // set to a value corresponding to when the next delayed task should run.
376
377 // By setting num_tasks to 1, we ensure that the first task to run causes the
378 // run loop to exit.
379 int num_tasks = 1;
380 Time run_time;
381
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900382 loop.PostTask(FROM_HERE, base::Bind(&SubPumpFunc));
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900383
384 // This very delayed task should never run.
385 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900386 FROM_HERE,
387 base::Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
388 1000000);
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900389
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900390 // This slightly delayed task should run from within SubPumpFunc).
391 loop.PostDelayedTask(FROM_HERE, base::Bind(&PostQuitMessage, 0), 10);
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900392
393 Time start_time = Time::Now();
394
395 loop.Run();
396 EXPECT_EQ(1, num_tasks);
397
398 // Ensure that we ran in far less time than the slower timer.
darin@chromium.orgaa119c22008-09-24 04:22:33 +0900399 TimeDelta total_time = Time::Now() - start_time;
400 EXPECT_GT(5000, total_time.InMilliseconds());
darin@chromium.orgb2d33452008-09-24 04:19:20 +0900401
402 // In case both timers somehow run at nearly the same time, sleep a little
403 // and then run all pending to force them both to have run. This is just
404 // encouraging flakiness if there is any.
405 PlatformThread::Sleep(100);
406 loop.RunAllPending();
407
408 EXPECT_TRUE(run_time.is_null());
409}
410
411#endif // defined(OS_WIN)
412
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900413// This is used to inject a test point for recording the destructor calls for
414// Closure objects send to MessageLoop::PostTask(). It is awkward usage since we
415// are trying to hook the actual destruction, which is not a common operation.
416class RecordDeletionProbe : public base::RefCounted<RecordDeletionProbe> {
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900417 public:
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900418 RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted)
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900419 : post_on_delete_(post_on_delete), was_deleted_(was_deleted) {
420 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900421 ~RecordDeletionProbe() {
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900422 *was_deleted_ = true;
423 if (post_on_delete_)
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900424 MessageLoop::current()->PostTask(
425 FROM_HERE,
426 base::Bind(&RecordDeletionProbe::Run, post_on_delete_.get()));
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900427 }
thakis@chromium.org2d8d5922011-06-08 11:20:21 +0900428 void Run() {}
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900429 private:
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900430 scoped_refptr<RecordDeletionProbe> post_on_delete_;
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900431 bool* was_deleted_;
432};
433
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900434void RunTest_EnsureDeletion(MessageLoop::Type message_loop_type) {
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900435 bool a_was_deleted = false;
436 bool b_was_deleted = false;
437 {
438 MessageLoop loop(message_loop_type);
439 loop.PostTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900440 FROM_HERE, base::Bind(&RecordDeletionProbe::Run,
441 new RecordDeletionProbe(NULL, &a_was_deleted)));
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900442 loop.PostDelayedTask(
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900443 FROM_HERE, base::Bind(&RecordDeletionProbe::Run,
444 new RecordDeletionProbe(NULL, &b_was_deleted)),
445 1000); // TODO(ajwong): Do we really need 1000ms here?
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900446 }
447 EXPECT_TRUE(a_was_deleted);
448 EXPECT_TRUE(b_was_deleted);
449}
450
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900451void RunTest_EnsureDeletion_Chain(MessageLoop::Type message_loop_type) {
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900452 bool a_was_deleted = false;
453 bool b_was_deleted = false;
454 bool c_was_deleted = false;
455 {
456 MessageLoop loop(message_loop_type);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900457 // The scoped_refptr for each of the below is held either by the chained
458 // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback.
459 RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted);
460 RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted);
461 RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted);
462 loop.PostTask(FROM_HERE, base::Bind(&RecordDeletionProbe::Run, c));
darin@chromium.orge3af17f2008-09-10 09:37:07 +0900463 }
464 EXPECT_TRUE(a_was_deleted);
465 EXPECT_TRUE(b_was_deleted);
466 EXPECT_TRUE(c_was_deleted);
467}
468
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900469void NestingFunc(int* depth) {
470 if (*depth > 0) {
471 *depth -= 1;
472 MessageLoop::current()->PostTask(FROM_HERE,
473 base::Bind(&NestingFunc, depth));
initial.commit3f4a7322008-07-27 06:49:38 +0900474
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900475 MessageLoop::current()->SetNestableTasksAllowed(true);
476 MessageLoop::current()->Run();
initial.commit3f4a7322008-07-27 06:49:38 +0900477 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900478 MessageLoop::current()->Quit();
479}
initial.commit3f4a7322008-07-27 06:49:38 +0900480
darin@google.com12d40bb2008-08-20 03:36:23 +0900481#if defined(OS_WIN)
482
initial.commit3f4a7322008-07-27 06:49:38 +0900483LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) {
484 ADD_FAILURE() << "bad exception handler";
485 ::ExitProcess(ex_info->ExceptionRecord->ExceptionCode);
486 return EXCEPTION_EXECUTE_HANDLER;
487}
488
489// This task throws an SEH exception: initially write to an invalid address.
490// If the right SEH filter is installed, it will fix the error.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900491class Crasher : public base::RefCounted<Crasher> {
initial.commit3f4a7322008-07-27 06:49:38 +0900492 public:
493 // Ctor. If trash_SEH_handler is true, the task will override the unhandled
494 // exception handler with one sure to crash this test.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900495 explicit Crasher(bool trash_SEH_handler)
initial.commit3f4a7322008-07-27 06:49:38 +0900496 : trash_SEH_handler_(trash_SEH_handler) {
497 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900498
initial.commit3f4a7322008-07-27 06:49:38 +0900499 void Run() {
darin@google.com12d40bb2008-08-20 03:36:23 +0900500 PlatformThread::Sleep(1);
initial.commit3f4a7322008-07-27 06:49:38 +0900501 if (trash_SEH_handler_)
502 ::SetUnhandledExceptionFilter(&BadExceptionHandler);
503 // Generate a SEH fault. We do it in asm to make sure we know how to undo
504 // the damage.
maruel@google.coma855b0f2008-07-30 22:02:03 +0900505
506#if defined(_M_IX86)
507
initial.commit3f4a7322008-07-27 06:49:38 +0900508 __asm {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900509 mov eax, dword ptr [Crasher::bad_array_]
initial.commit3f4a7322008-07-27 06:49:38 +0900510 mov byte ptr [eax], 66
511 }
maruel@google.coma855b0f2008-07-30 22:02:03 +0900512
513#elif defined(_M_X64)
514
515 bad_array_[0] = 66;
516
darin@google.com12d40bb2008-08-20 03:36:23 +0900517#else
518#error "needs architecture support"
maruel@google.coma855b0f2008-07-30 22:02:03 +0900519#endif
520
initial.commit3f4a7322008-07-27 06:49:38 +0900521 MessageLoop::current()->Quit();
522 }
523 // Points the bad array to a valid memory location.
524 static void FixError() {
525 bad_array_ = &valid_store_;
526 }
527
528 private:
529 bool trash_SEH_handler_;
530 static volatile char* bad_array_;
531 static char valid_store_;
532};
533
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900534volatile char* Crasher::bad_array_ = 0;
535char Crasher::valid_store_ = 0;
initial.commit3f4a7322008-07-27 06:49:38 +0900536
537// This SEH filter fixes the problem and retries execution. Fixing requires
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900538// that the last instruction: mov eax, [Crasher::bad_array_] to be retried
initial.commit3f4a7322008-07-27 06:49:38 +0900539// so we move the instruction pointer 5 bytes back.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900540LONG WINAPI HandleCrasherException(EXCEPTION_POINTERS *ex_info) {
initial.commit3f4a7322008-07-27 06:49:38 +0900541 if (ex_info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
542 return EXCEPTION_EXECUTE_HANDLER;
543
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900544 Crasher::FixError();
maruel@google.coma855b0f2008-07-30 22:02:03 +0900545
546#if defined(_M_IX86)
547
initial.commit3f4a7322008-07-27 06:49:38 +0900548 ex_info->ContextRecord->Eip -= 5;
maruel@google.coma855b0f2008-07-30 22:02:03 +0900549
550#elif defined(_M_X64)
551
552 ex_info->ContextRecord->Rip -= 5;
553
554#endif
555
initial.commit3f4a7322008-07-27 06:49:38 +0900556 return EXCEPTION_CONTINUE_EXECUTION;
557}
558
darin@google.comd936b5b2008-08-26 14:53:57 +0900559void RunTest_Crasher(MessageLoop::Type message_loop_type) {
560 MessageLoop loop(message_loop_type);
darin@google.com12d40bb2008-08-20 03:36:23 +0900561
initial.commit3f4a7322008-07-27 06:49:38 +0900562 if (::IsDebuggerPresent())
563 return;
564
565 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900566 ::SetUnhandledExceptionFilter(&HandleCrasherException);
initial.commit3f4a7322008-07-27 06:49:38 +0900567
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900568 MessageLoop::current()->PostTask(
569 FROM_HERE,
570 base::Bind(&Crasher::Run, new Crasher(false)));
initial.commit3f4a7322008-07-27 06:49:38 +0900571 MessageLoop::current()->set_exception_restoration(true);
572 MessageLoop::current()->Run();
573 MessageLoop::current()->set_exception_restoration(false);
574
575 ::SetUnhandledExceptionFilter(old_SEH_filter);
576}
577
darin@google.comd936b5b2008-08-26 14:53:57 +0900578void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) {
579 MessageLoop loop(message_loop_type);
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900580
initial.commit3f4a7322008-07-27 06:49:38 +0900581 if (::IsDebuggerPresent())
582 return;
583
584 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter =
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900585 ::SetUnhandledExceptionFilter(&HandleCrasherException);
initial.commit3f4a7322008-07-27 06:49:38 +0900586
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900587 MessageLoop::current()->PostTask(
588 FROM_HERE,
589 base::Bind(&Crasher::Run, new Crasher(true)));
initial.commit3f4a7322008-07-27 06:49:38 +0900590 MessageLoop::current()->set_exception_restoration(true);
591 MessageLoop::current()->Run();
592 MessageLoop::current()->set_exception_restoration(false);
593
594 ::SetUnhandledExceptionFilter(old_SEH_filter);
595}
596
darin@google.coma2ac02b2008-08-15 13:32:57 +0900597#endif // defined(OS_WIN)
598
darin@google.comd936b5b2008-08-26 14:53:57 +0900599void RunTest_Nesting(MessageLoop::Type message_loop_type) {
600 MessageLoop loop(message_loop_type);
maruel@google.coma855b0f2008-07-30 22:02:03 +0900601
initial.commit3f4a7322008-07-27 06:49:38 +0900602 int depth = 100;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900603 MessageLoop::current()->PostTask(FROM_HERE,
604 base::Bind(&NestingFunc, &depth));
initial.commit3f4a7322008-07-27 06:49:38 +0900605 MessageLoop::current()->Run();
606 EXPECT_EQ(depth, 0);
607}
608
initial.commit3f4a7322008-07-27 06:49:38 +0900609const wchar_t* const kMessageBoxTitle = L"MessageLoop Unit Test";
610
611enum TaskType {
612 MESSAGEBOX,
613 ENDDIALOG,
614 RECURSIVE,
615 TIMEDMESSAGELOOP,
616 QUITMESSAGELOOP,
617 ORDERERD,
618 PUMPS,
mark@chromium.org3ae027a2009-06-26 04:23:11 +0900619 SLEEP,
initial.commit3f4a7322008-07-27 06:49:38 +0900620};
621
622// Saves the order in which the tasks executed.
623struct TaskItem {
624 TaskItem(TaskType t, int c, bool s)
625 : type(t),
626 cookie(c),
627 start(s) {
628 }
629
630 TaskType type;
631 int cookie;
632 bool start;
633
634 bool operator == (const TaskItem& other) const {
635 return type == other.type && cookie == other.cookie && start == other.start;
636 }
637};
638
initial.commit3f4a7322008-07-27 06:49:38 +0900639std::ostream& operator <<(std::ostream& os, TaskType type) {
640 switch (type) {
641 case MESSAGEBOX: os << "MESSAGEBOX"; break;
642 case ENDDIALOG: os << "ENDDIALOG"; break;
643 case RECURSIVE: os << "RECURSIVE"; break;
644 case TIMEDMESSAGELOOP: os << "TIMEDMESSAGELOOP"; break;
645 case QUITMESSAGELOOP: os << "QUITMESSAGELOOP"; break;
646 case ORDERERD: os << "ORDERERD"; break;
647 case PUMPS: os << "PUMPS"; break;
mark@chromium.org3ae027a2009-06-26 04:23:11 +0900648 case SLEEP: os << "SLEEP"; break;
initial.commit3f4a7322008-07-27 06:49:38 +0900649 default:
650 NOTREACHED();
651 os << "Unknown TaskType";
652 break;
653 }
654 return os;
655}
656
657std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
658 if (item.start)
659 return os << item.type << " " << item.cookie << " starts";
660 else
661 return os << item.type << " " << item.cookie << " ends";
662}
663
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900664class TaskList {
initial.commit3f4a7322008-07-27 06:49:38 +0900665 public:
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900666 void RecordStart(TaskType type, int cookie) {
667 TaskItem item(type, cookie, true);
pkasting@chromium.org9fc87072010-10-19 11:31:03 +0900668 DVLOG(1) << item;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900669 task_list_.push_back(item);
initial.commit3f4a7322008-07-27 06:49:38 +0900670 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900671
672 void RecordEnd(TaskType type, int cookie) {
673 TaskItem item(type, cookie, false);
pkasting@chromium.org9fc87072010-10-19 11:31:03 +0900674 DVLOG(1) << item;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900675 task_list_.push_back(item);
initial.commit3f4a7322008-07-27 06:49:38 +0900676 }
677
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900678 size_t Size() {
679 return task_list_.size();
initial.commit3f4a7322008-07-27 06:49:38 +0900680 }
681
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900682 TaskItem Get(int n) {
683 return task_list_[n];
initial.commit3f4a7322008-07-27 06:49:38 +0900684 }
685
686 private:
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900687 std::vector<TaskItem> task_list_;
initial.commit3f4a7322008-07-27 06:49:38 +0900688};
689
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900690// Saves the order the tasks ran.
691void OrderedFunc(TaskList* order, int cookie) {
692 order->RecordStart(ORDERERD, cookie);
693 order->RecordEnd(ORDERERD, cookie);
694}
695
darin@google.com12d40bb2008-08-20 03:36:23 +0900696#if defined(OS_WIN)
697
initial.commit3f4a7322008-07-27 06:49:38 +0900698// MessageLoop implicitly start a "modal message loop". Modal dialog boxes,
699// common controls (like OpenFile) and StartDoc printing function can cause
700// implicit message loops.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900701void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) {
702 order->RecordStart(MESSAGEBOX, cookie);
703 if (is_reentrant)
704 MessageLoop::current()->SetNestableTasksAllowed(true);
705 MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK);
706 order->RecordEnd(MESSAGEBOX, cookie);
707}
initial.commit3f4a7322008-07-27 06:49:38 +0900708
709// Will end the MessageBox.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900710void EndDialogFunc(TaskList* order, int cookie) {
711 order->RecordStart(ENDDIALOG, cookie);
712 HWND window = GetActiveWindow();
713 if (window != NULL) {
714 EXPECT_NE(EndDialog(window, IDCONTINUE), 0);
715 // Cheap way to signal that the window wasn't found if RunEnd() isn't
716 // called.
717 order->RecordEnd(ENDDIALOG, cookie);
initial.commit3f4a7322008-07-27 06:49:38 +0900718 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900719}
initial.commit3f4a7322008-07-27 06:49:38 +0900720
darin@google.com12d40bb2008-08-20 03:36:23 +0900721#endif // defined(OS_WIN)
722
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900723void RecursiveFunc(TaskList* order, int cookie, int depth,
724 bool is_reentrant) {
725 order->RecordStart(RECURSIVE, cookie);
726 if (depth > 0) {
727 if (is_reentrant)
728 MessageLoop::current()->SetNestableTasksAllowed(true);
729 MessageLoop::current()->PostTask(
730 FROM_HERE,
731 base::Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant));
initial.commit3f4a7322008-07-27 06:49:38 +0900732 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900733 order->RecordEnd(RECURSIVE, cookie);
734}
initial.commit3f4a7322008-07-27 06:49:38 +0900735
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900736void RecursiveSlowFunc(TaskList* order, int cookie, int depth,
737 bool is_reentrant) {
738 RecursiveFunc(order, cookie, depth, is_reentrant);
739 PlatformThread::Sleep(10); // milliseconds
740}
initial.commit3f4a7322008-07-27 06:49:38 +0900741
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900742void QuitFunc(TaskList* order, int cookie) {
743 order->RecordStart(QUITMESSAGELOOP, cookie);
744 MessageLoop::current()->Quit();
745 order->RecordEnd(QUITMESSAGELOOP, cookie);
746}
initial.commit3f4a7322008-07-27 06:49:38 +0900747
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900748void SleepFunc(TaskList* order, int cookie, int ms) {
749 order->RecordStart(SLEEP, cookie);
750 PlatformThread::Sleep(ms);
751 order->RecordEnd(SLEEP, cookie);
752}
mark@chromium.org3ae027a2009-06-26 04:23:11 +0900753
darin@google.coma2ac02b2008-08-15 13:32:57 +0900754#if defined(OS_WIN)
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900755void RecursiveFuncWin(MessageLoop* target,
756 HANDLE event,
757 bool expect_window,
758 TaskList* order,
759 bool is_reentrant) {
760 target->PostTask(FROM_HERE,
761 base::Bind(&RecursiveFunc, order, 1, 2, is_reentrant));
762 target->PostTask(FROM_HERE,
763 base::Bind(&MessageBoxFunc, order, 2, is_reentrant));
764 target->PostTask(FROM_HERE,
765 base::Bind(&RecursiveFunc, order, 3, 2, is_reentrant));
766 // The trick here is that for recursive task processing, this task will be
767 // ran _inside_ the MessageBox message loop, dismissing the MessageBox
768 // without a chance.
769 // For non-recursive task processing, this will be executed _after_ the
770 // MessageBox will have been dismissed by the code below, where
771 // expect_window_ is true.
772 target->PostTask(FROM_HERE,
773 base::Bind(&EndDialogFunc, order, 4));
774 target->PostTask(FROM_HERE,
775 base::Bind(&QuitFunc, order, 5));
darin@google.coma2ac02b2008-08-15 13:32:57 +0900776
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900777 // Enforce that every tasks are sent before starting to run the main thread
778 // message loop.
779 ASSERT_TRUE(SetEvent(event));
initial.commit3f4a7322008-07-27 06:49:38 +0900780
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900781 // Poll for the MessageBox. Don't do this at home! At the speed we do it,
782 // you will never realize one MessageBox was shown.
783 for (; expect_window;) {
784 HWND window = FindWindow(L"#32770", kMessageBoxTitle);
785 if (window) {
786 // Dismiss it.
787 for (;;) {
788 HWND button = FindWindowEx(window, NULL, L"Button", NULL);
789 if (button != NULL) {
790 EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0));
791 EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0));
792 break;
initial.commit3f4a7322008-07-27 06:49:38 +0900793 }
initial.commit3f4a7322008-07-27 06:49:38 +0900794 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900795 break;
initial.commit3f4a7322008-07-27 06:49:38 +0900796 }
797 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900798}
initial.commit3f4a7322008-07-27 06:49:38 +0900799
darin@google.coma2ac02b2008-08-15 13:32:57 +0900800#endif // defined(OS_WIN)
801
darin@google.comd936b5b2008-08-26 14:53:57 +0900802void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) {
803 MessageLoop loop(message_loop_type);
initial.commit3f4a7322008-07-27 06:49:38 +0900804
initial.commit3f4a7322008-07-27 06:49:38 +0900805 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
806 TaskList order;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900807 MessageLoop::current()->PostTask(
808 FROM_HERE,
809 base::Bind(&RecursiveFunc, &order, 1, 2, false));
810 MessageLoop::current()->PostTask(
811 FROM_HERE,
812 base::Bind(&RecursiveFunc, &order, 2, 2, false));
813 MessageLoop::current()->PostTask(
814 FROM_HERE,
815 base::Bind(&QuitFunc, &order, 3));
initial.commit3f4a7322008-07-27 06:49:38 +0900816
817 MessageLoop::current()->Run();
818
819 // FIFO order.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900820 ASSERT_EQ(14U, order.Size());
821 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
822 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
823 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
824 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
825 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
826 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
827 EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
828 EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
829 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
830 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
831 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
832 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
833 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
834 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
initial.commit3f4a7322008-07-27 06:49:38 +0900835}
836
mark@chromium.orgee945952011-02-18 04:25:04 +0900837void RunTest_RecursiveDenial3(MessageLoop::Type message_loop_type) {
838 MessageLoop loop(message_loop_type);
839
840 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
841 TaskList order;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900842 MessageLoop::current()->PostTask(
843 FROM_HERE, base::Bind(&RecursiveSlowFunc, &order, 1, 2, false));
844 MessageLoop::current()->PostTask(
845 FROM_HERE, base::Bind(&RecursiveSlowFunc, &order, 2, 2, false));
846 MessageLoop::current()->PostDelayedTask(
847 FROM_HERE, base::Bind(&OrderedFunc, &order, 3), 5);
848 MessageLoop::current()->PostDelayedTask(
849 FROM_HERE, base::Bind(&QuitFunc, &order, 4), 5);
mark@chromium.orgee945952011-02-18 04:25:04 +0900850
851 MessageLoop::current()->Run();
852
853 // FIFO order.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900854 ASSERT_EQ(16U, order.Size());
855 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
856 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
857 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
858 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
859 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true));
860 EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false));
861 EXPECT_EQ(order.Get(6), TaskItem(ORDERERD, 3, true));
862 EXPECT_EQ(order.Get(7), TaskItem(ORDERERD, 3, false));
863 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
864 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
865 EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true));
866 EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false));
867 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true));
868 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false));
869 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true));
870 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false));
mark@chromium.orgee945952011-02-18 04:25:04 +0900871}
872
darin@google.comd936b5b2008-08-26 14:53:57 +0900873void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) {
874 MessageLoop loop(message_loop_type);
rvargas@google.com9e49aa22008-10-10 08:58:43 +0900875
initial.commit3f4a7322008-07-27 06:49:38 +0900876 TaskList order;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900877 MessageLoop::current()->PostTask(
878 FROM_HERE, base::Bind(&RecursiveFunc, &order, 1, 2, true));
879 MessageLoop::current()->PostTask(
880 FROM_HERE, base::Bind(&RecursiveFunc, &order, 2, 2, true));
881 MessageLoop::current()->PostTask(
882 FROM_HERE, base::Bind(&QuitFunc, &order, 3));
initial.commit3f4a7322008-07-27 06:49:38 +0900883
884 MessageLoop::current()->Run();
885
886 // FIFO order.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900887 ASSERT_EQ(14U, order.Size());
888 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
889 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
890 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
891 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
892 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
893 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
894 EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
895 EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
896 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
897 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
898 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
899 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
900 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
901 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
initial.commit3f4a7322008-07-27 06:49:38 +0900902}
903
darin@google.coma2ac02b2008-08-15 13:32:57 +0900904#if defined(OS_WIN)
905// TODO(darin): These tests need to be ported since they test critical
906// message loop functionality.
907
initial.commit3f4a7322008-07-27 06:49:38 +0900908// A side effect of this test is the generation a beep. Sorry.
darin@google.comd936b5b2008-08-26 14:53:57 +0900909void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
910 MessageLoop loop(message_loop_type);
911
initial.commit3f4a7322008-07-27 06:49:38 +0900912 Thread worker("RecursiveDenial2_worker");
darin@google.comd936b5b2008-08-26 14:53:57 +0900913 Thread::Options options;
914 options.message_loop_type = message_loop_type;
915 ASSERT_EQ(true, worker.StartWithOptions(options));
initial.commit3f4a7322008-07-27 06:49:38 +0900916 TaskList order;
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +0900917 base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
initial.commit3f4a7322008-07-27 06:49:38 +0900918 worker.message_loop()->PostTask(FROM_HERE,
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900919 base::Bind(&RecursiveFuncWin,
920 MessageLoop::current(),
921 event.Get(),
922 true,
923 &order,
924 false));
initial.commit3f4a7322008-07-27 06:49:38 +0900925 // Let the other thread execute.
926 WaitForSingleObject(event, INFINITE);
927 MessageLoop::current()->Run();
928
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900929 ASSERT_EQ(order.Size(), 17);
930 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
931 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
932 EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
933 EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false));
934 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true));
935 EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false));
936 // When EndDialogFunc is processed, the window is already dismissed, hence no
initial.commit3f4a7322008-07-27 06:49:38 +0900937 // "end" entry.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900938 EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true));
939 EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true));
940 EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false));
941 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true));
942 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false));
943 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true));
944 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false));
945 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true));
946 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false));
947 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true));
948 EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false));
initial.commit3f4a7322008-07-27 06:49:38 +0900949}
950
darin@google.comd936b5b2008-08-26 14:53:57 +0900951// A side effect of this test is the generation a beep. Sorry. This test also
952// needs to process windows messages on the current thread.
953void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
954 MessageLoop loop(message_loop_type);
955
initial.commit3f4a7322008-07-27 06:49:38 +0900956 Thread worker("RecursiveSupport2_worker");
darin@google.comd936b5b2008-08-26 14:53:57 +0900957 Thread::Options options;
958 options.message_loop_type = message_loop_type;
959 ASSERT_EQ(true, worker.StartWithOptions(options));
initial.commit3f4a7322008-07-27 06:49:38 +0900960 TaskList order;
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +0900961 base::win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
initial.commit3f4a7322008-07-27 06:49:38 +0900962 worker.message_loop()->PostTask(FROM_HERE,
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900963 base::Bind(&RecursiveFuncWin,
964 MessageLoop::current(),
965 event.Get(),
966 false,
967 &order,
968 true));
initial.commit3f4a7322008-07-27 06:49:38 +0900969 // Let the other thread execute.
970 WaitForSingleObject(event, INFINITE);
971 MessageLoop::current()->Run();
972
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900973 ASSERT_EQ(order.Size(), 18);
974 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
975 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
976 EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
initial.commit3f4a7322008-07-27 06:49:38 +0900977 // Note that this executes in the MessageBox modal loop.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900978 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true));
979 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false));
980 EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true));
981 EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false));
982 EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false));
983 /* The order can subtly change here. The reason is that when RecursiveFunc(1)
initial.commit3f4a7322008-07-27 06:49:38 +0900984 is called in the main thread, if it is faster than getting to the
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900985 PostTask(FROM_HERE, base::Bind(&QuitFunc) execution, the order of task
986 execution can change. We don't care anyway that the order isn't correct.
987 EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, true));
988 EXPECT_EQ(order.Get(9), TaskItem(QUITMESSAGELOOP, 5, false));
989 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
990 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
initial.commit3f4a7322008-07-27 06:49:38 +0900991 */
ajwong@chromium.org94d2a582011-04-21 01:02:23 +0900992 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, true));
993 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 3, false));
994 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, true));
995 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 1, false));
996 EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, true));
997 EXPECT_EQ(order.Get(17), TaskItem(RECURSIVE, 3, false));
initial.commit3f4a7322008-07-27 06:49:38 +0900998}
999
darin@google.coma2ac02b2008-08-15 13:32:57 +09001000#endif // defined(OS_WIN)
1001
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001002void FuncThatPumps(TaskList* order, int cookie) {
1003 order->RecordStart(PUMPS, cookie);
1004 bool old_state = MessageLoop::current()->NestableTasksAllowed();
1005 MessageLoop::current()->SetNestableTasksAllowed(true);
1006 MessageLoop::current()->RunAllPending();
1007 MessageLoop::current()->SetNestableTasksAllowed(old_state);
1008 order->RecordEnd(PUMPS, cookie);
1009}
initial.commit3f4a7322008-07-27 06:49:38 +09001010
initial.commit3f4a7322008-07-27 06:49:38 +09001011// Tests that non nestable tasks run in FIFO if there are no nested loops.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001012void RunTest_NonNestableWithNoNesting(
1013 MessageLoop::Type message_loop_type) {
darin@google.comd936b5b2008-08-26 14:53:57 +09001014 MessageLoop loop(message_loop_type);
1015
initial.commit3f4a7322008-07-27 06:49:38 +09001016 TaskList order;
1017
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001018 MessageLoop::current()->PostNonNestableTask(
1019 FROM_HERE,
1020 base::Bind(&OrderedFunc, &order, 1));
1021 MessageLoop::current()->PostTask(FROM_HERE,
1022 base::Bind(&OrderedFunc, &order, 2));
1023 MessageLoop::current()->PostTask(FROM_HERE,
1024 base::Bind(&QuitFunc, &order, 3));
initial.commit3f4a7322008-07-27 06:49:38 +09001025 MessageLoop::current()->Run();
1026
1027 // FIFO order.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001028 ASSERT_EQ(6U, order.Size());
1029 EXPECT_EQ(order.Get(0), TaskItem(ORDERERD, 1, true));
1030 EXPECT_EQ(order.Get(1), TaskItem(ORDERERD, 1, false));
1031 EXPECT_EQ(order.Get(2), TaskItem(ORDERERD, 2, true));
1032 EXPECT_EQ(order.Get(3), TaskItem(ORDERERD, 2, false));
1033 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
1034 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
initial.commit3f4a7322008-07-27 06:49:38 +09001035}
1036
1037// Tests that non nestable tasks don't run when there's code in the call stack.
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001038void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type,
1039 bool use_delayed) {
darin@google.comd936b5b2008-08-26 14:53:57 +09001040 MessageLoop loop(message_loop_type);
1041
initial.commit3f4a7322008-07-27 06:49:38 +09001042 TaskList order;
1043
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001044 MessageLoop::current()->PostTask(
1045 FROM_HERE,
1046 base::Bind(&FuncThatPumps, &order, 1));
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001047 if (use_delayed) {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001048 MessageLoop::current()->PostNonNestableDelayedTask(
1049 FROM_HERE,
1050 base::Bind(&OrderedFunc, &order, 2),
1051 1);
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001052 } else {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001053 MessageLoop::current()->PostNonNestableTask(
1054 FROM_HERE,
1055 base::Bind(&OrderedFunc, &order, 2));
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001056 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001057 MessageLoop::current()->PostTask(FROM_HERE,
1058 base::Bind(&OrderedFunc, &order, 3));
1059 MessageLoop::current()->PostTask(FROM_HERE,
1060 base::Bind(&SleepFunc, &order, 4, 50));
1061 MessageLoop::current()->PostTask(FROM_HERE,
1062 base::Bind(&OrderedFunc, &order, 5));
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001063 if (use_delayed) {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001064 MessageLoop::current()->PostNonNestableDelayedTask(
1065 FROM_HERE,
1066 base::Bind(&QuitFunc, &order, 6),
1067 2);
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001068 } else {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001069 MessageLoop::current()->PostNonNestableTask(
1070 FROM_HERE,
1071 base::Bind(&QuitFunc, &order, 6));
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001072 }
initial.commit3f4a7322008-07-27 06:49:38 +09001073
initial.commit3f4a7322008-07-27 06:49:38 +09001074 MessageLoop::current()->Run();
1075
1076 // FIFO order.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001077 ASSERT_EQ(12U, order.Size());
1078 EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true));
1079 EXPECT_EQ(order.Get(1), TaskItem(ORDERERD, 3, true));
1080 EXPECT_EQ(order.Get(2), TaskItem(ORDERERD, 3, false));
1081 EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true));
1082 EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false));
1083 EXPECT_EQ(order.Get(5), TaskItem(ORDERERD, 5, true));
1084 EXPECT_EQ(order.Get(6), TaskItem(ORDERERD, 5, false));
1085 EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false));
1086 EXPECT_EQ(order.Get(8), TaskItem(ORDERERD, 2, true));
1087 EXPECT_EQ(order.Get(9), TaskItem(ORDERERD, 2, false));
1088 EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true));
1089 EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false));
initial.commit3f4a7322008-07-27 06:49:38 +09001090}
1091
darin@google.coma2ac02b2008-08-15 13:32:57 +09001092#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +09001093
darin@google.comd936b5b2008-08-26 14:53:57 +09001094class DispatcherImpl : public MessageLoopForUI::Dispatcher {
initial.commit3f4a7322008-07-27 06:49:38 +09001095 public:
1096 DispatcherImpl() : dispatch_count_(0) {}
1097
1098 virtual bool Dispatch(const MSG& msg) {
1099 ::TranslateMessage(&msg);
1100 ::DispatchMessage(&msg);
jianli@chromium.orga0ce9582010-01-16 03:49:58 +09001101 // Do not count WM_TIMER since it is not what we post and it will cause
1102 // flakiness.
1103 if (msg.message != WM_TIMER)
1104 ++dispatch_count_;
1105 // We treat WM_LBUTTONUP as the last message.
1106 return msg.message != WM_LBUTTONUP;
initial.commit3f4a7322008-07-27 06:49:38 +09001107 }
1108
1109 int dispatch_count_;
1110};
1111
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001112void MouseDownUp() {
1113 PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
1114 PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
1115}
1116
darin@google.comd936b5b2008-08-26 14:53:57 +09001117void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
1118 MessageLoop loop(message_loop_type);
initial.commit3f4a7322008-07-27 06:49:38 +09001119
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001120 MessageLoop::current()->PostDelayedTask(FROM_HERE,
1121 base::Bind(&MouseDownUp), 100);
initial.commit3f4a7322008-07-27 06:49:38 +09001122 DispatcherImpl dispatcher;
oshima@google.com08ff65e2011-10-24 16:19:51 +09001123 MessageLoopForUI::current()->RunWithDispatcher(&dispatcher);
initial.commit3f4a7322008-07-27 06:49:38 +09001124 ASSERT_EQ(2, dispatcher.dispatch_count_);
1125}
darin@google.coma2ac02b2008-08-15 13:32:57 +09001126
jianli@chromium.orga0ce9582010-01-16 03:49:58 +09001127LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) {
1128 if (code == base::MessagePumpForUI::kMessageFilterCode) {
1129 MSG* msg = reinterpret_cast<MSG*>(lparam);
1130 if (msg->message == WM_LBUTTONDOWN)
1131 return TRUE;
1132 }
1133 return FALSE;
1134}
1135
1136void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) {
1137 MessageLoop loop(message_loop_type);
1138
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001139 MessageLoop::current()->PostDelayedTask(FROM_HERE,
1140 base::Bind(&MouseDownUp), 100);
jianli@chromium.orga0ce9582010-01-16 03:49:58 +09001141 HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER,
1142 MsgFilterProc,
1143 NULL,
1144 GetCurrentThreadId());
1145 DispatcherImpl dispatcher;
oshima@google.com08ff65e2011-10-24 16:19:51 +09001146 MessageLoopForUI::current()->RunWithDispatcher(&dispatcher);
jianli@chromium.orga0ce9582010-01-16 03:49:58 +09001147 ASSERT_EQ(1, dispatcher.dispatch_count_);
1148 UnhookWindowsHookEx(msg_hook);
1149}
1150
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001151class TestIOHandler : public MessageLoopForIO::IOHandler {
1152 public:
rvargas@google.com73887542008-11-08 06:52:15 +09001153 TestIOHandler(const wchar_t* name, HANDLE signal, bool wait);
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001154
rvargas@google.com73887542008-11-08 06:52:15 +09001155 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
1156 DWORD bytes_transfered, DWORD error);
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001157
rvargas@google.com73887542008-11-08 06:52:15 +09001158 void Init();
1159 void WaitForIO();
1160 OVERLAPPED* context() { return &context_.overlapped; }
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001161 DWORD size() { return sizeof(buffer_); }
1162
1163 private:
1164 char buffer_[48];
rvargas@google.com73887542008-11-08 06:52:15 +09001165 MessageLoopForIO::IOContext context_;
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001166 HANDLE signal_;
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001167 base::win::ScopedHandle file_;
rvargas@google.com73887542008-11-08 06:52:15 +09001168 bool wait_;
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001169};
1170
rvargas@google.com73887542008-11-08 06:52:15 +09001171TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait)
1172 : signal_(signal), wait_(wait) {
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001173 memset(buffer_, 0, sizeof(buffer_));
1174 memset(&context_, 0, sizeof(context_));
rvargas@google.com73887542008-11-08 06:52:15 +09001175 context_.handler = this;
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001176
1177 file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
1178 FILE_FLAG_OVERLAPPED, NULL));
1179 EXPECT_TRUE(file_.IsValid());
1180}
1181
rvargas@google.com73887542008-11-08 06:52:15 +09001182void TestIOHandler::Init() {
1183 MessageLoopForIO::current()->RegisterIOHandler(file_, this);
1184
1185 DWORD read;
1186 EXPECT_FALSE(ReadFile(file_, buffer_, size(), &read, context()));
1187 EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
1188 if (wait_)
1189 WaitForIO();
1190}
1191
1192void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
1193 DWORD bytes_transfered, DWORD error) {
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001194 ASSERT_TRUE(context == &context_);
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001195 ASSERT_TRUE(SetEvent(signal_));
1196}
1197
rvargas@google.com73887542008-11-08 06:52:15 +09001198void TestIOHandler::WaitForIO() {
1199 EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this));
1200 EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this));
1201}
1202
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001203void RunTest_IOHandler() {
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001204 base::win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001205 ASSERT_TRUE(callback_called.IsValid());
1206
1207 const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe";
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001208 base::win::ScopedHandle server(
1209 CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001210 ASSERT_TRUE(server.IsValid());
1211
1212 Thread thread("IOHandler test");
1213 Thread::Options options;
1214 options.message_loop_type = MessageLoop::TYPE_IO;
1215 ASSERT_TRUE(thread.StartWithOptions(options));
1216
1217 MessageLoop* thread_loop = thread.message_loop();
1218 ASSERT_TRUE(NULL != thread_loop);
1219
rvargas@google.com73887542008-11-08 06:52:15 +09001220 TestIOHandler handler(kPipeName, callback_called, false);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001221 thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
1222 base::Unretained(&handler)));
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001223 Sleep(100); // Make sure the thread runs and sleeps for lack of work.
1224
1225 const char buffer[] = "Hello there!";
1226 DWORD written;
1227 EXPECT_TRUE(WriteFile(server, buffer, sizeof(buffer), &written, NULL));
1228
1229 DWORD result = WaitForSingleObject(callback_called, 1000);
1230 EXPECT_EQ(WAIT_OBJECT_0, result);
1231
1232 thread.Stop();
1233}
1234
rvargas@google.com73887542008-11-08 06:52:15 +09001235void RunTest_WaitForIO() {
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001236 base::win::ScopedHandle callback1_called(
1237 CreateEvent(NULL, TRUE, FALSE, NULL));
1238 base::win::ScopedHandle callback2_called(
1239 CreateEvent(NULL, TRUE, FALSE, NULL));
rvargas@google.com73887542008-11-08 06:52:15 +09001240 ASSERT_TRUE(callback1_called.IsValid());
1241 ASSERT_TRUE(callback2_called.IsValid());
1242
1243 const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1";
1244 const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2";
tfarina@chromium.orgc89216a2011-01-10 01:32:20 +09001245 base::win::ScopedHandle server1(
1246 CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
1247 base::win::ScopedHandle server2(
1248 CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
rvargas@google.com73887542008-11-08 06:52:15 +09001249 ASSERT_TRUE(server1.IsValid());
1250 ASSERT_TRUE(server2.IsValid());
1251
1252 Thread thread("IOHandler test");
1253 Thread::Options options;
1254 options.message_loop_type = MessageLoop::TYPE_IO;
1255 ASSERT_TRUE(thread.StartWithOptions(options));
1256
1257 MessageLoop* thread_loop = thread.message_loop();
1258 ASSERT_TRUE(NULL != thread_loop);
1259
1260 TestIOHandler handler1(kPipeName1, callback1_called, false);
1261 TestIOHandler handler2(kPipeName2, callback2_called, true);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001262 thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
1263 base::Unretained(&handler1)));
1264 // TODO(ajwong): Do we really need such long Sleeps in ths function?
rvargas@google.com73887542008-11-08 06:52:15 +09001265 Sleep(100); // Make sure the thread runs and sleeps for lack of work.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001266 thread_loop->PostTask(FROM_HERE, base::Bind(&TestIOHandler::Init,
1267 base::Unretained(&handler2)));
rvargas@google.com73887542008-11-08 06:52:15 +09001268 Sleep(100);
1269
1270 // At this time handler1 is waiting to be called, and the thread is waiting
1271 // on the Init method of handler2, filtering only handler2 callbacks.
1272
1273 const char buffer[] = "Hello there!";
1274 DWORD written;
1275 EXPECT_TRUE(WriteFile(server1, buffer, sizeof(buffer), &written, NULL));
1276 Sleep(200);
1277 EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called, 0)) <<
1278 "handler1 has not been called";
1279
1280 EXPECT_TRUE(WriteFile(server2, buffer, sizeof(buffer), &written, NULL));
1281
1282 HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() };
1283 DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000);
1284 EXPECT_EQ(WAIT_OBJECT_0, result);
1285
1286 thread.Stop();
1287}
1288
darin@google.comd936b5b2008-08-26 14:53:57 +09001289#endif // defined(OS_WIN)
license.botf003cfe2008-08-24 09:55:55 +09001290
darin@google.comd936b5b2008-08-26 14:53:57 +09001291} // namespace
1292
1293//-----------------------------------------------------------------------------
1294// Each test is run against each type of MessageLoop. That way we are sure
1295// that message loops work properly in all configurations. Of course, in some
1296// cases, a unit test may only be for a particular type of loop.
1297
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001298TEST(MessageLoopTest, PostLegacyTask) {
1299 RunTest_PostLegacyTask(MessageLoop::TYPE_DEFAULT);
1300 RunTest_PostLegacyTask(MessageLoop::TYPE_UI);
1301 RunTest_PostLegacyTask(MessageLoop::TYPE_IO);
1302}
1303
darin@google.comd936b5b2008-08-26 14:53:57 +09001304TEST(MessageLoopTest, PostTask) {
1305 RunTest_PostTask(MessageLoop::TYPE_DEFAULT);
1306 RunTest_PostTask(MessageLoop::TYPE_UI);
1307 RunTest_PostTask(MessageLoop::TYPE_IO);
1308}
1309
1310TEST(MessageLoopTest, PostTask_SEH) {
1311 RunTest_PostTask_SEH(MessageLoop::TYPE_DEFAULT);
1312 RunTest_PostTask_SEH(MessageLoop::TYPE_UI);
1313 RunTest_PostTask_SEH(MessageLoop::TYPE_IO);
1314}
1315
darin@google.combe165ae2008-09-07 17:08:29 +09001316TEST(MessageLoopTest, PostDelayedTask_Basic) {
1317 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_DEFAULT);
1318 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_UI);
1319 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_IO);
1320}
1321
1322TEST(MessageLoopTest, PostDelayedTask_InDelayOrder) {
1323 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_DEFAULT);
1324 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_UI);
1325 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_IO);
1326}
1327
1328TEST(MessageLoopTest, PostDelayedTask_InPostOrder) {
1329 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_DEFAULT);
1330 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_UI);
1331 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_IO);
1332}
1333
1334TEST(MessageLoopTest, PostDelayedTask_InPostOrder_2) {
1335 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_DEFAULT);
1336 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_UI);
1337 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_IO);
1338}
1339
1340TEST(MessageLoopTest, PostDelayedTask_InPostOrder_3) {
1341 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_DEFAULT);
1342 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_UI);
1343 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_IO);
1344}
1345
darin@chromium.orgb2d33452008-09-24 04:19:20 +09001346TEST(MessageLoopTest, PostDelayedTask_SharedTimer) {
1347 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_DEFAULT);
1348 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_UI);
1349 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_IO);
1350}
1351
1352#if defined(OS_WIN)
1353TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
1354 RunTest_PostDelayedTask_SharedTimer_SubPump();
1355}
1356#endif
1357
jhawkins@chromium.org9b8ceac2010-05-26 05:13:36 +09001358// TODO(darin): MessageLoop does not support deleting all tasks in the
1359// destructor.
phajdan.jr@chromium.org101b63b2010-07-27 06:23:18 +09001360// Fails, http://crbug.com/50272.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001361TEST(MessageLoopTest, FAILS_EnsureDeletion) {
1362 RunTest_EnsureDeletion(MessageLoop::TYPE_DEFAULT);
1363 RunTest_EnsureDeletion(MessageLoop::TYPE_UI);
1364 RunTest_EnsureDeletion(MessageLoop::TYPE_IO);
darin@chromium.orge3af17f2008-09-10 09:37:07 +09001365}
1366
jhawkins@chromium.org9b8ceac2010-05-26 05:13:36 +09001367// TODO(darin): MessageLoop does not support deleting all tasks in the
1368// destructor.
phajdan.jr@chromium.org101b63b2010-07-27 06:23:18 +09001369// Fails, http://crbug.com/50272.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001370TEST(MessageLoopTest, FAILS_EnsureDeletion_Chain) {
1371 RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_DEFAULT);
1372 RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_UI);
1373 RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_IO);
darin@chromium.orge3af17f2008-09-10 09:37:07 +09001374}
1375
darin@google.comd936b5b2008-08-26 14:53:57 +09001376#if defined(OS_WIN)
1377TEST(MessageLoopTest, Crasher) {
1378 RunTest_Crasher(MessageLoop::TYPE_DEFAULT);
1379 RunTest_Crasher(MessageLoop::TYPE_UI);
1380 RunTest_Crasher(MessageLoop::TYPE_IO);
1381}
1382
1383TEST(MessageLoopTest, CrasherNasty) {
1384 RunTest_CrasherNasty(MessageLoop::TYPE_DEFAULT);
1385 RunTest_CrasherNasty(MessageLoop::TYPE_UI);
1386 RunTest_CrasherNasty(MessageLoop::TYPE_IO);
1387}
1388#endif // defined(OS_WIN)
1389
1390TEST(MessageLoopTest, Nesting) {
1391 RunTest_Nesting(MessageLoop::TYPE_DEFAULT);
1392 RunTest_Nesting(MessageLoop::TYPE_UI);
1393 RunTest_Nesting(MessageLoop::TYPE_IO);
1394}
1395
1396TEST(MessageLoopTest, RecursiveDenial1) {
1397 RunTest_RecursiveDenial1(MessageLoop::TYPE_DEFAULT);
1398 RunTest_RecursiveDenial1(MessageLoop::TYPE_UI);
1399 RunTest_RecursiveDenial1(MessageLoop::TYPE_IO);
1400}
1401
mark@chromium.orgee945952011-02-18 04:25:04 +09001402TEST(MessageLoopTest, RecursiveDenial3) {
1403 RunTest_RecursiveDenial3(MessageLoop::TYPE_DEFAULT);
1404 RunTest_RecursiveDenial3(MessageLoop::TYPE_UI);
1405 RunTest_RecursiveDenial3(MessageLoop::TYPE_IO);
1406}
1407
darin@google.comd936b5b2008-08-26 14:53:57 +09001408TEST(MessageLoopTest, RecursiveSupport1) {
1409 RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT);
1410 RunTest_RecursiveSupport1(MessageLoop::TYPE_UI);
1411 RunTest_RecursiveSupport1(MessageLoop::TYPE_IO);
1412}
1413
1414#if defined(OS_WIN)
maruel@chromium.orga989c1f2010-05-19 23:33:44 +09001415// This test occasionally hangs http://crbug.com/44567
1416TEST(MessageLoopTest, DISABLED_RecursiveDenial2) {
darin@google.comd936b5b2008-08-26 14:53:57 +09001417 RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
1418 RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
1419 RunTest_RecursiveDenial2(MessageLoop::TYPE_IO);
1420}
1421
1422TEST(MessageLoopTest, RecursiveSupport2) {
1423 // This test requires a UI loop
1424 RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
1425}
1426#endif // defined(OS_WIN)
1427
1428TEST(MessageLoopTest, NonNestableWithNoNesting) {
1429 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_DEFAULT);
1430 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_UI);
1431 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_IO);
1432}
1433
1434TEST(MessageLoopTest, NonNestableInNestedLoop) {
mark@chromium.org3ae027a2009-06-26 04:23:11 +09001435 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, false);
1436 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, false);
1437 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, false);
1438}
1439
1440TEST(MessageLoopTest, NonNestableDelayedInNestedLoop) {
1441 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, true);
1442 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, true);
1443 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, true);
darin@google.comd936b5b2008-08-26 14:53:57 +09001444}
1445
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001446void PostNTasksThenQuit(int posts_remaining) {
1447 if (posts_remaining > 1) {
1448 MessageLoop::current()->PostTask(
1449 FROM_HERE,
1450 base::Bind(&PostNTasksThenQuit, posts_remaining - 1));
1451 } else {
1452 MessageLoop::current()->Quit();
willchan@chromium.orga9047632010-06-10 06:20:41 +09001453 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001454}
willchan@chromium.orga9047632010-06-10 06:20:41 +09001455
1456class DummyTaskObserver : public MessageLoop::TaskObserver {
1457 public:
thestig@chromium.org60bd7c02010-07-23 14:23:13 +09001458 explicit DummyTaskObserver(int num_tasks)
willchan@chromium.orga9047632010-06-10 06:20:41 +09001459 : num_tasks_started_(0),
1460 num_tasks_processed_(0),
1461 num_tasks_(num_tasks) {}
1462
1463 virtual ~DummyTaskObserver() {}
1464
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001465 virtual void WillProcessTask(TimeTicks time_posted) OVERRIDE {
willchan@chromium.orga9047632010-06-10 06:20:41 +09001466 num_tasks_started_++;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001467 EXPECT_TRUE(time_posted != TimeTicks());
willchan@chromium.orga9047632010-06-10 06:20:41 +09001468 EXPECT_LE(num_tasks_started_, num_tasks_);
1469 EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
1470 }
1471
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001472 virtual void DidProcessTask(TimeTicks time_posted) OVERRIDE {
willchan@chromium.orga9047632010-06-10 06:20:41 +09001473 num_tasks_processed_++;
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001474 EXPECT_TRUE(time_posted != TimeTicks());
willchan@chromium.orga9047632010-06-10 06:20:41 +09001475 EXPECT_LE(num_tasks_started_, num_tasks_);
1476 EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
1477 }
1478
1479 int num_tasks_started() const { return num_tasks_started_; }
1480 int num_tasks_processed() const { return num_tasks_processed_; }
1481
1482 private:
1483 int num_tasks_started_;
1484 int num_tasks_processed_;
1485 const int num_tasks_;
1486
1487 DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver);
1488};
1489
1490TEST(MessageLoopTest, TaskObserver) {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001491 const int kNumPosts = 6;
1492 DummyTaskObserver observer(kNumPosts);
willchan@chromium.orga9047632010-06-10 06:20:41 +09001493
1494 MessageLoop loop;
1495 loop.AddTaskObserver(&observer);
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001496 loop.PostTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, kNumPosts));
willchan@chromium.orga9047632010-06-10 06:20:41 +09001497 loop.Run();
1498 loop.RemoveTaskObserver(&observer);
1499
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001500 EXPECT_EQ(kNumPosts, observer.num_tasks_started());
1501 EXPECT_EQ(kNumPosts, observer.num_tasks_processed());
willchan@chromium.orga9047632010-06-10 06:20:41 +09001502}
1503
darin@google.comd936b5b2008-08-26 14:53:57 +09001504#if defined(OS_WIN)
darin@google.comd936b5b2008-08-26 14:53:57 +09001505TEST(MessageLoopTest, Dispatcher) {
1506 // This test requires a UI loop
1507 RunTest_Dispatcher(MessageLoop::TYPE_UI);
1508}
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001509
jianli@chromium.orga0ce9582010-01-16 03:49:58 +09001510TEST(MessageLoopTest, DispatcherWithMessageHook) {
1511 // This test requires a UI loop
1512 RunTest_DispatcherWithMessageHook(MessageLoop::TYPE_UI);
1513}
1514
rvargas@google.com9e49aa22008-10-10 08:58:43 +09001515TEST(MessageLoopTest, IOHandler) {
1516 RunTest_IOHandler();
1517}
rvargas@google.com73887542008-11-08 06:52:15 +09001518
1519TEST(MessageLoopTest, WaitForIO) {
1520 RunTest_WaitForIO();
1521}
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001522
1523TEST(MessageLoopTest, HighResolutionTimer) {
1524 MessageLoop loop;
1525
1526 const int kFastTimerMs = 5;
1527 const int kSlowTimerMs = 100;
1528
hans@chromium.orgfa5bf992011-01-14 19:36:28 +09001529 EXPECT_FALSE(loop.high_resolution_timers_enabled());
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001530
1531 // Post a fast task to enable the high resolution timers.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001532 loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
1533 kFastTimerMs);
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001534 loop.Run();
hans@chromium.orgfa5bf992011-01-14 19:36:28 +09001535 EXPECT_TRUE(loop.high_resolution_timers_enabled());
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001536
1537 // Post a slow task and verify high resolution timers
1538 // are still enabled.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001539 loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
1540 kSlowTimerMs);
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001541 loop.Run();
hans@chromium.orgfa5bf992011-01-14 19:36:28 +09001542 EXPECT_TRUE(loop.high_resolution_timers_enabled());
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001543
1544 // Wait for a while so that high-resolution mode elapses.
1545 Sleep(MessageLoop::kHighResolutionTimerModeLeaseTimeMs);
1546
1547 // Post a slow task to disable the high resolution timers.
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001548 loop.PostDelayedTask(FROM_HERE, base::Bind(&PostNTasksThenQuit, 1),
1549 kSlowTimerMs);
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001550 loop.Run();
hans@chromium.orgfa5bf992011-01-14 19:36:28 +09001551 EXPECT_FALSE(loop.high_resolution_timers_enabled());
mbelshe@chromium.orgde50b7d2010-06-29 13:58:15 +09001552}
1553
darin@google.comd936b5b2008-08-26 14:53:57 +09001554#endif // defined(OS_WIN)
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001555
abarth@chromium.org1f1c2172010-12-01 17:45:51 +09001556#if defined(OS_POSIX) && !defined(OS_NACL)
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001557
1558namespace {
1559
wtc@chromium.org961d6d12011-06-22 15:33:05 +09001560class QuitDelegate : public MessageLoopForIO::Watcher {
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001561 public:
1562 virtual void OnFileCanWriteWithoutBlocking(int fd) {
1563 MessageLoop::current()->Quit();
1564 }
1565 virtual void OnFileCanReadWithoutBlocking(int fd) {
1566 MessageLoop::current()->Quit();
1567 }
1568};
1569
jhawkins@chromium.org37848382010-06-11 09:06:19 +09001570TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) {
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001571 // Simulate a MessageLoop that dies before an FileDescriptorWatcher.
1572 // This could happen when people use the Singleton pattern or atexit.
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001573
1574 // Create a file descriptor. Doesn't need to be readable or writable,
1575 // as we don't need to actually get any notifications.
1576 // pipe() is just the easiest way to do it.
1577 int pipefds[2];
1578 int err = pipe(pipefds);
thestig@chromium.org60bd7c02010-07-23 14:23:13 +09001579 ASSERT_EQ(0, err);
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001580 int fd = pipefds[1];
1581 {
1582 // Arrange for controller to live longer than message loop.
wtc@chromium.org961d6d12011-06-22 15:33:05 +09001583 MessageLoopForIO::FileDescriptorWatcher controller;
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001584 {
1585 MessageLoopForIO message_loop;
1586
1587 QuitDelegate delegate;
1588 message_loop.WatchFileDescriptor(fd,
1589 true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
1590 // and don't run the message loop, just destroy it.
1591 }
1592 }
thakis@chromium.org965db9a2010-06-23 09:37:46 +09001593 if (HANDLE_EINTR(close(pipefds[0])) < 0)
1594 PLOG(ERROR) << "close";
1595 if (HANDLE_EINTR(close(pipefds[1])) < 0)
1596 PLOG(ERROR) << "close";
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001597}
1598
1599TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) {
1600 // Verify that it's ok to call StopWatchingFileDescriptor().
1601 // (Errors only showed up in valgrind.)
1602 int pipefds[2];
1603 int err = pipe(pipefds);
thestig@chromium.org60bd7c02010-07-23 14:23:13 +09001604 ASSERT_EQ(0, err);
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001605 int fd = pipefds[1];
1606 {
1607 // Arrange for message loop to live longer than controller.
1608 MessageLoopForIO message_loop;
1609 {
wtc@chromium.org961d6d12011-06-22 15:33:05 +09001610 MessageLoopForIO::FileDescriptorWatcher controller;
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001611
1612 QuitDelegate delegate;
1613 message_loop.WatchFileDescriptor(fd,
1614 true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
1615 controller.StopWatchingFileDescriptor();
1616 }
1617 }
thakis@chromium.org965db9a2010-06-23 09:37:46 +09001618 if (HANDLE_EINTR(close(pipefds[0])) < 0)
1619 PLOG(ERROR) << "close";
1620 if (HANDLE_EINTR(close(pipefds[1])) < 0)
1621 PLOG(ERROR) << "close";
dkegel@google.com41b5fd92009-04-23 05:01:36 +09001622}
1623
willchan@chromium.orga9047632010-06-10 06:20:41 +09001624} // namespace
1625
abarth@chromium.org1f1c2172010-12-01 17:45:51 +09001626#endif // defined(OS_POSIX) && !defined(OS_NACL)
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001627
1628namespace {
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001629// Inject a test point for recording the destructor calls for Closure objects
1630// send to MessageLoop::PostTask(). It is awkward usage since we are trying to
1631// hook the actual destruction, which is not a common operation.
1632class DestructionObserverProbe :
1633 public base::RefCounted<DestructionObserverProbe> {
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001634 public:
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001635 DestructionObserverProbe(bool* task_destroyed,
1636 bool* destruction_observer_called)
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001637 : task_destroyed_(task_destroyed),
1638 destruction_observer_called_(destruction_observer_called) {
1639 }
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001640 virtual ~DestructionObserverProbe() {
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001641 EXPECT_FALSE(*destruction_observer_called_);
1642 *task_destroyed_ = true;
1643 }
1644 virtual void Run() {
1645 // This task should never run.
1646 ADD_FAILURE();
1647 }
1648 private:
1649 bool* task_destroyed_;
1650 bool* destruction_observer_called_;
1651};
1652
1653class MLDestructionObserver : public MessageLoop::DestructionObserver {
1654 public:
1655 MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called)
1656 : task_destroyed_(task_destroyed),
1657 destruction_observer_called_(destruction_observer_called),
1658 task_destroyed_before_message_loop_(false) {
1659 }
1660 virtual void WillDestroyCurrentMessageLoop() {
1661 task_destroyed_before_message_loop_ = *task_destroyed_;
1662 *destruction_observer_called_ = true;
1663 }
1664 bool task_destroyed_before_message_loop() const {
1665 return task_destroyed_before_message_loop_;
1666 }
1667 private:
1668 bool* task_destroyed_;
1669 bool* destruction_observer_called_;
1670 bool task_destroyed_before_message_loop_;
1671};
1672
1673} // namespace
1674
1675TEST(MessageLoopTest, DestructionObserverTest) {
1676 // Verify that the destruction observer gets called at the very end (after
1677 // all the pending tasks have been destroyed).
1678 MessageLoop* loop = new MessageLoop;
1679 const int kDelayMS = 100;
1680
1681 bool task_destroyed = false;
1682 bool destruction_observer_called = false;
1683
1684 MLDestructionObserver observer(&task_destroyed, &destruction_observer_called);
1685 loop->AddDestructionObserver(&observer);
1686 loop->PostDelayedTask(
1687 FROM_HERE,
ajwong@chromium.org94d2a582011-04-21 01:02:23 +09001688 base::Bind(&DestructionObserverProbe::Run,
1689 new DestructionObserverProbe(&task_destroyed,
1690 &destruction_observer_called)),
sanjeevr@chromium.org03b44d52010-11-30 09:25:29 +09001691 kDelayMS);
1692 delete loop;
1693 EXPECT_TRUE(observer.task_destroyed_before_message_loop());
1694 // The task should have been destroyed when we deleted the loop.
1695 EXPECT_TRUE(task_destroyed);
1696 EXPECT_TRUE(destruction_observer_called);
1697}