OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <vector> | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/compiler_specific.h" | |
10 #include "base/logging.h" | |
11 #include "base/memory/ref_counted.h" | |
12 #include "base/message_loop.h" | |
13 #include "base/pending_task.h" | |
14 #include "base/posix/eintr_wrapper.h" | |
15 #include "base/run_loop.h" | |
16 #include "base/synchronization/waitable_event.h" | |
17 #include "base/thread_task_runner_handle.h" | |
18 #include "base/threading/platform_thread.h" | |
19 #include "base/threading/thread.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 | |
22 #if defined(OS_WIN) | |
23 #include "base/message_pump_win.h" | |
24 #include "base/win/scoped_handle.h" | |
25 #endif | |
26 | |
27 namespace base { | |
28 | |
29 class MessageLoopLockTest { | |
30 public: | |
31 static void LockWaitUnLock(MessageLoop* loop, | |
32 base::WaitableEvent* caller_wait, | |
33 base::WaitableEvent* caller_signal) { | |
34 | |
35 loop->incoming_queue_lock_.Acquire(); | |
36 caller_wait->Signal(); | |
37 caller_signal->Wait(); | |
38 loop->incoming_queue_lock_.Release(); | |
39 } | |
40 }; | |
41 | |
42 // TODO(darin): Platform-specific MessageLoop tests should be grouped together | |
43 // to avoid chopping this file up with so many #ifdefs. | |
44 | |
45 namespace { | |
46 | |
47 class Foo : public RefCounted<Foo> { | |
48 public: | |
49 Foo() : test_count_(0) { | |
50 } | |
51 | |
52 void Test0() { | |
53 ++test_count_; | |
54 } | |
55 | |
56 void Test1ConstRef(const std::string& a) { | |
57 ++test_count_; | |
58 result_.append(a); | |
59 } | |
60 | |
61 void Test1Ptr(std::string* a) { | |
62 ++test_count_; | |
63 result_.append(*a); | |
64 } | |
65 | |
66 void Test1Int(int a) { | |
67 test_count_ += a; | |
68 } | |
69 | |
70 void Test2Ptr(std::string* a, std::string* b) { | |
71 ++test_count_; | |
72 result_.append(*a); | |
73 result_.append(*b); | |
74 } | |
75 | |
76 void Test2Mixed(const std::string& a, std::string* b) { | |
77 ++test_count_; | |
78 result_.append(a); | |
79 result_.append(*b); | |
80 } | |
81 | |
82 int test_count() const { return test_count_; } | |
83 const std::string& result() const { return result_; } | |
84 | |
85 private: | |
86 friend class RefCounted<Foo>; | |
87 | |
88 ~Foo() {} | |
89 | |
90 int test_count_; | |
91 std::string result_; | |
92 }; | |
93 | |
94 void RunTest_PostTask(MessageLoop::Type message_loop_type) { | |
95 MessageLoop loop(message_loop_type); | |
96 | |
97 // Add tests to message loop | |
98 scoped_refptr<Foo> foo(new Foo()); | |
99 std::string a("a"), b("b"), c("c"), d("d"); | |
100 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
101 &Foo::Test0, foo.get())); | |
102 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
103 &Foo::Test1ConstRef, foo.get(), a)); | |
104 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
105 &Foo::Test1Ptr, foo.get(), &b)); | |
106 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
107 &Foo::Test1Int, foo.get(), 100)); | |
108 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
109 &Foo::Test2Ptr, foo.get(), &a, &c)); | |
110 | |
111 // TryPost with no contention. It must succeed. | |
112 EXPECT_TRUE(MessageLoop::current()->TryPostTask(FROM_HERE, Bind( | |
113 &Foo::Test2Mixed, foo.get(), a, &d))); | |
114 | |
115 // TryPost with simulated contention. It must fail. We wait for a helper | |
116 // thread to lock the queue, we TryPost on this thread and finally we | |
117 // signal the helper to unlock and exit. | |
118 WaitableEvent wait(true, false); | |
119 WaitableEvent signal(true, false); | |
120 Thread thread("RunTest_PostTask_helper"); | |
121 thread.Start(); | |
122 thread.message_loop()->PostTask( | |
123 FROM_HERE, | |
124 base::Bind(&MessageLoopLockTest::LockWaitUnLock, | |
125 MessageLoop::current(), | |
126 &wait, | |
127 &signal)); | |
128 | |
129 wait.Wait(); | |
130 EXPECT_FALSE(MessageLoop::current()->TryPostTask(FROM_HERE, Bind( | |
131 &Foo::Test2Mixed, foo.get(), a, &d))); | |
132 signal.Signal(); | |
133 | |
134 // After all tests, post a message that will shut down the message loop | |
135 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
136 &MessageLoop::Quit, Unretained(MessageLoop::current()))); | |
137 | |
138 // Now kick things off | |
139 MessageLoop::current()->Run(); | |
140 | |
141 EXPECT_EQ(foo->test_count(), 105); | |
142 EXPECT_EQ(foo->result(), "abacad"); | |
143 } | |
144 | |
145 void RunTest_PostTask_SEH(MessageLoop::Type message_loop_type) { | |
146 MessageLoop loop(message_loop_type); | |
147 | |
148 // Add tests to message loop | |
149 scoped_refptr<Foo> foo(new Foo()); | |
150 std::string a("a"), b("b"), c("c"), d("d"); | |
151 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
152 &Foo::Test0, foo.get())); | |
153 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
154 &Foo::Test1ConstRef, foo.get(), a)); | |
155 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
156 &Foo::Test1Ptr, foo.get(), &b)); | |
157 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
158 &Foo::Test1Int, foo.get(), 100)); | |
159 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
160 &Foo::Test2Ptr, foo.get(), &a, &c)); | |
161 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
162 &Foo::Test2Mixed, foo.get(), a, &d)); | |
163 | |
164 // After all tests, post a message that will shut down the message loop | |
165 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
166 &MessageLoop::Quit, Unretained(MessageLoop::current()))); | |
167 | |
168 // Now kick things off with the SEH block active. | |
169 MessageLoop::current()->set_exception_restoration(true); | |
170 MessageLoop::current()->Run(); | |
171 MessageLoop::current()->set_exception_restoration(false); | |
172 | |
173 EXPECT_EQ(foo->test_count(), 105); | |
174 EXPECT_EQ(foo->result(), "abacad"); | |
175 } | |
176 | |
177 // This function runs slowly to simulate a large amount of work being done. | |
178 static void SlowFunc(TimeDelta pause, int* quit_counter) { | |
179 PlatformThread::Sleep(pause); | |
180 if (--(*quit_counter) == 0) | |
181 MessageLoop::current()->QuitWhenIdle(); | |
182 } | |
183 | |
184 // This function records the time when Run was called in a Time object, which is | |
185 // useful for building a variety of MessageLoop tests. | |
186 static void RecordRunTimeFunc(Time* run_time, int* quit_counter) { | |
187 *run_time = Time::Now(); | |
188 | |
189 // Cause our Run function to take some time to execute. As a result we can | |
190 // count on subsequent RecordRunTimeFunc()s running at a future time, | |
191 // without worry about the resolution of our system clock being an issue. | |
192 SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter); | |
193 } | |
194 | |
195 void RunTest_PostDelayedTask_Basic(MessageLoop::Type message_loop_type) { | |
196 MessageLoop loop(message_loop_type); | |
197 | |
198 // Test that PostDelayedTask results in a delayed task. | |
199 | |
200 const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); | |
201 | |
202 int num_tasks = 1; | |
203 Time run_time; | |
204 | |
205 loop.PostDelayedTask( | |
206 FROM_HERE, Bind(&RecordRunTimeFunc, &run_time, &num_tasks), | |
207 kDelay); | |
208 | |
209 Time time_before_run = Time::Now(); | |
210 loop.Run(); | |
211 Time time_after_run = Time::Now(); | |
212 | |
213 EXPECT_EQ(0, num_tasks); | |
214 EXPECT_LT(kDelay, time_after_run - time_before_run); | |
215 } | |
216 | |
217 void RunTest_PostDelayedTask_InDelayOrder( | |
218 MessageLoop::Type message_loop_type) { | |
219 MessageLoop loop(message_loop_type); | |
220 | |
221 // Test that two tasks with different delays run in the right order. | |
222 int num_tasks = 2; | |
223 Time run_time1, run_time2; | |
224 | |
225 loop.PostDelayedTask( | |
226 FROM_HERE, | |
227 Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), | |
228 TimeDelta::FromMilliseconds(200)); | |
229 // If we get a large pause in execution (due to a context switch) here, this | |
230 // test could fail. | |
231 loop.PostDelayedTask( | |
232 FROM_HERE, | |
233 Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), | |
234 TimeDelta::FromMilliseconds(10)); | |
235 | |
236 loop.Run(); | |
237 EXPECT_EQ(0, num_tasks); | |
238 | |
239 EXPECT_TRUE(run_time2 < run_time1); | |
240 } | |
241 | |
242 void RunTest_PostDelayedTask_InPostOrder( | |
243 MessageLoop::Type message_loop_type) { | |
244 MessageLoop loop(message_loop_type); | |
245 | |
246 // Test that two tasks with the same delay run in the order in which they | |
247 // were posted. | |
248 // | |
249 // NOTE: This is actually an approximate test since the API only takes a | |
250 // "delay" parameter, so we are not exactly simulating two tasks that get | |
251 // posted at the exact same time. It would be nice if the API allowed us to | |
252 // specify the desired run time. | |
253 | |
254 const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); | |
255 | |
256 int num_tasks = 2; | |
257 Time run_time1, run_time2; | |
258 | |
259 loop.PostDelayedTask( | |
260 FROM_HERE, | |
261 Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay); | |
262 loop.PostDelayedTask( | |
263 FROM_HERE, | |
264 Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay); | |
265 | |
266 loop.Run(); | |
267 EXPECT_EQ(0, num_tasks); | |
268 | |
269 EXPECT_TRUE(run_time1 < run_time2); | |
270 } | |
271 | |
272 void RunTest_PostDelayedTask_InPostOrder_2( | |
273 MessageLoop::Type message_loop_type) { | |
274 MessageLoop loop(message_loop_type); | |
275 | |
276 // Test that a delayed task still runs after a normal tasks even if the | |
277 // normal tasks take a long time to run. | |
278 | |
279 const TimeDelta kPause = TimeDelta::FromMilliseconds(50); | |
280 | |
281 int num_tasks = 2; | |
282 Time run_time; | |
283 | |
284 loop.PostTask(FROM_HERE, Bind(&SlowFunc, kPause, &num_tasks)); | |
285 loop.PostDelayedTask( | |
286 FROM_HERE, | |
287 Bind(&RecordRunTimeFunc, &run_time, &num_tasks), | |
288 TimeDelta::FromMilliseconds(10)); | |
289 | |
290 Time time_before_run = Time::Now(); | |
291 loop.Run(); | |
292 Time time_after_run = Time::Now(); | |
293 | |
294 EXPECT_EQ(0, num_tasks); | |
295 | |
296 EXPECT_LT(kPause, time_after_run - time_before_run); | |
297 } | |
298 | |
299 void RunTest_PostDelayedTask_InPostOrder_3( | |
300 MessageLoop::Type message_loop_type) { | |
301 MessageLoop loop(message_loop_type); | |
302 | |
303 // Test that a delayed task still runs after a pile of normal tasks. The key | |
304 // difference between this test and the previous one is that here we return | |
305 // the MessageLoop a lot so we give the MessageLoop plenty of opportunities | |
306 // to maybe run the delayed task. It should know not to do so until the | |
307 // delayed task's delay has passed. | |
308 | |
309 int num_tasks = 11; | |
310 Time run_time1, run_time2; | |
311 | |
312 // Clutter the ML with tasks. | |
313 for (int i = 1; i < num_tasks; ++i) | |
314 loop.PostTask(FROM_HERE, | |
315 Bind(&RecordRunTimeFunc, &run_time1, &num_tasks)); | |
316 | |
317 loop.PostDelayedTask( | |
318 FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), | |
319 TimeDelta::FromMilliseconds(1)); | |
320 | |
321 loop.Run(); | |
322 EXPECT_EQ(0, num_tasks); | |
323 | |
324 EXPECT_TRUE(run_time2 > run_time1); | |
325 } | |
326 | |
327 void RunTest_PostDelayedTask_SharedTimer( | |
328 MessageLoop::Type message_loop_type) { | |
329 MessageLoop loop(message_loop_type); | |
330 | |
331 // Test that the interval of the timer, used to run the next delayed task, is | |
332 // set to a value corresponding to when the next delayed task should run. | |
333 | |
334 // By setting num_tasks to 1, we ensure that the first task to run causes the | |
335 // run loop to exit. | |
336 int num_tasks = 1; | |
337 Time run_time1, run_time2; | |
338 | |
339 loop.PostDelayedTask( | |
340 FROM_HERE, | |
341 Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), | |
342 TimeDelta::FromSeconds(1000)); | |
343 loop.PostDelayedTask( | |
344 FROM_HERE, | |
345 Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), | |
346 TimeDelta::FromMilliseconds(10)); | |
347 | |
348 Time start_time = Time::Now(); | |
349 | |
350 loop.Run(); | |
351 EXPECT_EQ(0, num_tasks); | |
352 | |
353 // Ensure that we ran in far less time than the slower timer. | |
354 TimeDelta total_time = Time::Now() - start_time; | |
355 EXPECT_GT(5000, total_time.InMilliseconds()); | |
356 | |
357 // In case both timers somehow run at nearly the same time, sleep a little | |
358 // and then run all pending to force them both to have run. This is just | |
359 // encouraging flakiness if there is any. | |
360 PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); | |
361 RunLoop().RunUntilIdle(); | |
362 | |
363 EXPECT_TRUE(run_time1.is_null()); | |
364 EXPECT_FALSE(run_time2.is_null()); | |
365 } | |
366 | |
367 #if defined(OS_WIN) | |
368 | |
369 void SubPumpFunc() { | |
370 MessageLoop::current()->SetNestableTasksAllowed(true); | |
371 MSG msg; | |
372 while (GetMessage(&msg, NULL, 0, 0)) { | |
373 TranslateMessage(&msg); | |
374 DispatchMessage(&msg); | |
375 } | |
376 MessageLoop::current()->QuitWhenIdle(); | |
377 } | |
378 | |
379 void RunTest_PostDelayedTask_SharedTimer_SubPump() { | |
380 MessageLoop loop(MessageLoop::TYPE_UI); | |
381 | |
382 // Test that the interval of the timer, used to run the next delayed task, is | |
383 // set to a value corresponding to when the next delayed task should run. | |
384 | |
385 // By setting num_tasks to 1, we ensure that the first task to run causes the | |
386 // run loop to exit. | |
387 int num_tasks = 1; | |
388 Time run_time; | |
389 | |
390 loop.PostTask(FROM_HERE, Bind(&SubPumpFunc)); | |
391 | |
392 // This very delayed task should never run. | |
393 loop.PostDelayedTask( | |
394 FROM_HERE, | |
395 Bind(&RecordRunTimeFunc, &run_time, &num_tasks), | |
396 TimeDelta::FromSeconds(1000)); | |
397 | |
398 // This slightly delayed task should run from within SubPumpFunc). | |
399 loop.PostDelayedTask( | |
400 FROM_HERE, | |
401 Bind(&PostQuitMessage, 0), | |
402 TimeDelta::FromMilliseconds(10)); | |
403 | |
404 Time start_time = Time::Now(); | |
405 | |
406 loop.Run(); | |
407 EXPECT_EQ(1, num_tasks); | |
408 | |
409 // Ensure that we ran in far less time than the slower timer. | |
410 TimeDelta total_time = Time::Now() - start_time; | |
411 EXPECT_GT(5000, total_time.InMilliseconds()); | |
412 | |
413 // In case both timers somehow run at nearly the same time, sleep a little | |
414 // and then run all pending to force them both to have run. This is just | |
415 // encouraging flakiness if there is any. | |
416 PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); | |
417 RunLoop().RunUntilIdle(); | |
418 | |
419 EXPECT_TRUE(run_time.is_null()); | |
420 } | |
421 | |
422 #endif // defined(OS_WIN) | |
423 | |
424 // This is used to inject a test point for recording the destructor calls for | |
425 // Closure objects send to MessageLoop::PostTask(). It is awkward usage since we | |
426 // are trying to hook the actual destruction, which is not a common operation. | |
427 class RecordDeletionProbe : public RefCounted<RecordDeletionProbe> { | |
428 public: | |
429 RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted) | |
430 : post_on_delete_(post_on_delete), was_deleted_(was_deleted) { | |
431 } | |
432 void Run() {} | |
433 | |
434 private: | |
435 friend class RefCounted<RecordDeletionProbe>; | |
436 | |
437 ~RecordDeletionProbe() { | |
438 *was_deleted_ = true; | |
439 if (post_on_delete_.get()) | |
440 MessageLoop::current()->PostTask( | |
441 FROM_HERE, Bind(&RecordDeletionProbe::Run, post_on_delete_.get())); | |
442 } | |
443 | |
444 scoped_refptr<RecordDeletionProbe> post_on_delete_; | |
445 bool* was_deleted_; | |
446 }; | |
447 | |
448 void RunTest_EnsureDeletion(MessageLoop::Type message_loop_type) { | |
449 bool a_was_deleted = false; | |
450 bool b_was_deleted = false; | |
451 { | |
452 MessageLoop loop(message_loop_type); | |
453 loop.PostTask( | |
454 FROM_HERE, Bind(&RecordDeletionProbe::Run, | |
455 new RecordDeletionProbe(NULL, &a_was_deleted))); | |
456 // TODO(ajwong): Do we really need 1000ms here? | |
457 loop.PostDelayedTask( | |
458 FROM_HERE, Bind(&RecordDeletionProbe::Run, | |
459 new RecordDeletionProbe(NULL, &b_was_deleted)), | |
460 TimeDelta::FromMilliseconds(1000)); | |
461 } | |
462 EXPECT_TRUE(a_was_deleted); | |
463 EXPECT_TRUE(b_was_deleted); | |
464 } | |
465 | |
466 void RunTest_EnsureDeletion_Chain(MessageLoop::Type message_loop_type) { | |
467 bool a_was_deleted = false; | |
468 bool b_was_deleted = false; | |
469 bool c_was_deleted = false; | |
470 { | |
471 MessageLoop loop(message_loop_type); | |
472 // The scoped_refptr for each of the below is held either by the chained | |
473 // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback. | |
474 RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted); | |
475 RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted); | |
476 RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted); | |
477 loop.PostTask(FROM_HERE, Bind(&RecordDeletionProbe::Run, c)); | |
478 } | |
479 EXPECT_TRUE(a_was_deleted); | |
480 EXPECT_TRUE(b_was_deleted); | |
481 EXPECT_TRUE(c_was_deleted); | |
482 } | |
483 | |
484 void NestingFunc(int* depth) { | |
485 if (*depth > 0) { | |
486 *depth -= 1; | |
487 MessageLoop::current()->PostTask(FROM_HERE, | |
488 Bind(&NestingFunc, depth)); | |
489 | |
490 MessageLoop::current()->SetNestableTasksAllowed(true); | |
491 MessageLoop::current()->Run(); | |
492 } | |
493 MessageLoop::current()->QuitWhenIdle(); | |
494 } | |
495 | |
496 #if defined(OS_WIN) | |
497 | |
498 LONG WINAPI BadExceptionHandler(EXCEPTION_POINTERS *ex_info) { | |
499 ADD_FAILURE() << "bad exception handler"; | |
500 ::ExitProcess(ex_info->ExceptionRecord->ExceptionCode); | |
501 return EXCEPTION_EXECUTE_HANDLER; | |
502 } | |
503 | |
504 // This task throws an SEH exception: initially write to an invalid address. | |
505 // If the right SEH filter is installed, it will fix the error. | |
506 class Crasher : public RefCounted<Crasher> { | |
507 public: | |
508 // Ctor. If trash_SEH_handler is true, the task will override the unhandled | |
509 // exception handler with one sure to crash this test. | |
510 explicit Crasher(bool trash_SEH_handler) | |
511 : trash_SEH_handler_(trash_SEH_handler) { | |
512 } | |
513 | |
514 void Run() { | |
515 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1)); | |
516 if (trash_SEH_handler_) | |
517 ::SetUnhandledExceptionFilter(&BadExceptionHandler); | |
518 // Generate a SEH fault. We do it in asm to make sure we know how to undo | |
519 // the damage. | |
520 | |
521 #if defined(_M_IX86) | |
522 | |
523 __asm { | |
524 mov eax, dword ptr [Crasher::bad_array_] | |
525 mov byte ptr [eax], 66 | |
526 } | |
527 | |
528 #elif defined(_M_X64) | |
529 | |
530 bad_array_[0] = 66; | |
531 | |
532 #else | |
533 #error "needs architecture support" | |
534 #endif | |
535 | |
536 MessageLoop::current()->QuitWhenIdle(); | |
537 } | |
538 // Points the bad array to a valid memory location. | |
539 static void FixError() { | |
540 bad_array_ = &valid_store_; | |
541 } | |
542 | |
543 private: | |
544 bool trash_SEH_handler_; | |
545 static volatile char* bad_array_; | |
546 static char valid_store_; | |
547 }; | |
548 | |
549 volatile char* Crasher::bad_array_ = 0; | |
550 char Crasher::valid_store_ = 0; | |
551 | |
552 // This SEH filter fixes the problem and retries execution. Fixing requires | |
553 // that the last instruction: mov eax, [Crasher::bad_array_] to be retried | |
554 // so we move the instruction pointer 5 bytes back. | |
555 LONG WINAPI HandleCrasherException(EXCEPTION_POINTERS *ex_info) { | |
556 if (ex_info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION) | |
557 return EXCEPTION_EXECUTE_HANDLER; | |
558 | |
559 Crasher::FixError(); | |
560 | |
561 #if defined(_M_IX86) | |
562 | |
563 ex_info->ContextRecord->Eip -= 5; | |
564 | |
565 #elif defined(_M_X64) | |
566 | |
567 ex_info->ContextRecord->Rip -= 5; | |
568 | |
569 #endif | |
570 | |
571 return EXCEPTION_CONTINUE_EXECUTION; | |
572 } | |
573 | |
574 void RunTest_Crasher(MessageLoop::Type message_loop_type) { | |
575 MessageLoop loop(message_loop_type); | |
576 | |
577 if (::IsDebuggerPresent()) | |
578 return; | |
579 | |
580 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter = | |
581 ::SetUnhandledExceptionFilter(&HandleCrasherException); | |
582 | |
583 MessageLoop::current()->PostTask( | |
584 FROM_HERE, | |
585 Bind(&Crasher::Run, new Crasher(false))); | |
586 MessageLoop::current()->set_exception_restoration(true); | |
587 MessageLoop::current()->Run(); | |
588 MessageLoop::current()->set_exception_restoration(false); | |
589 | |
590 ::SetUnhandledExceptionFilter(old_SEH_filter); | |
591 } | |
592 | |
593 void RunTest_CrasherNasty(MessageLoop::Type message_loop_type) { | |
594 MessageLoop loop(message_loop_type); | |
595 | |
596 if (::IsDebuggerPresent()) | |
597 return; | |
598 | |
599 LPTOP_LEVEL_EXCEPTION_FILTER old_SEH_filter = | |
600 ::SetUnhandledExceptionFilter(&HandleCrasherException); | |
601 | |
602 MessageLoop::current()->PostTask( | |
603 FROM_HERE, | |
604 Bind(&Crasher::Run, new Crasher(true))); | |
605 MessageLoop::current()->set_exception_restoration(true); | |
606 MessageLoop::current()->Run(); | |
607 MessageLoop::current()->set_exception_restoration(false); | |
608 | |
609 ::SetUnhandledExceptionFilter(old_SEH_filter); | |
610 } | |
611 | |
612 #endif // defined(OS_WIN) | |
613 | |
614 void RunTest_Nesting(MessageLoop::Type message_loop_type) { | |
615 MessageLoop loop(message_loop_type); | |
616 | |
617 int depth = 100; | |
618 MessageLoop::current()->PostTask(FROM_HERE, | |
619 Bind(&NestingFunc, &depth)); | |
620 MessageLoop::current()->Run(); | |
621 EXPECT_EQ(depth, 0); | |
622 } | |
623 | |
624 const wchar_t* const kMessageBoxTitle = L"MessageLoop Unit Test"; | |
625 | |
626 enum TaskType { | |
627 MESSAGEBOX, | |
628 ENDDIALOG, | |
629 RECURSIVE, | |
630 TIMEDMESSAGELOOP, | |
631 QUITMESSAGELOOP, | |
632 ORDERED, | |
633 PUMPS, | |
634 SLEEP, | |
635 RUNS, | |
636 }; | |
637 | |
638 // Saves the order in which the tasks executed. | |
639 struct TaskItem { | |
640 TaskItem(TaskType t, int c, bool s) | |
641 : type(t), | |
642 cookie(c), | |
643 start(s) { | |
644 } | |
645 | |
646 TaskType type; | |
647 int cookie; | |
648 bool start; | |
649 | |
650 bool operator == (const TaskItem& other) const { | |
651 return type == other.type && cookie == other.cookie && start == other.start; | |
652 } | |
653 }; | |
654 | |
655 std::ostream& operator <<(std::ostream& os, TaskType type) { | |
656 switch (type) { | |
657 case MESSAGEBOX: os << "MESSAGEBOX"; break; | |
658 case ENDDIALOG: os << "ENDDIALOG"; break; | |
659 case RECURSIVE: os << "RECURSIVE"; break; | |
660 case TIMEDMESSAGELOOP: os << "TIMEDMESSAGELOOP"; break; | |
661 case QUITMESSAGELOOP: os << "QUITMESSAGELOOP"; break; | |
662 case ORDERED: os << "ORDERED"; break; | |
663 case PUMPS: os << "PUMPS"; break; | |
664 case SLEEP: os << "SLEEP"; break; | |
665 default: | |
666 NOTREACHED(); | |
667 os << "Unknown TaskType"; | |
668 break; | |
669 } | |
670 return os; | |
671 } | |
672 | |
673 std::ostream& operator <<(std::ostream& os, const TaskItem& item) { | |
674 if (item.start) | |
675 return os << item.type << " " << item.cookie << " starts"; | |
676 else | |
677 return os << item.type << " " << item.cookie << " ends"; | |
678 } | |
679 | |
680 class TaskList { | |
681 public: | |
682 void RecordStart(TaskType type, int cookie) { | |
683 TaskItem item(type, cookie, true); | |
684 DVLOG(1) << item; | |
685 task_list_.push_back(item); | |
686 } | |
687 | |
688 void RecordEnd(TaskType type, int cookie) { | |
689 TaskItem item(type, cookie, false); | |
690 DVLOG(1) << item; | |
691 task_list_.push_back(item); | |
692 } | |
693 | |
694 size_t Size() { | |
695 return task_list_.size(); | |
696 } | |
697 | |
698 TaskItem Get(int n) { | |
699 return task_list_[n]; | |
700 } | |
701 | |
702 private: | |
703 std::vector<TaskItem> task_list_; | |
704 }; | |
705 | |
706 // Saves the order the tasks ran. | |
707 void OrderedFunc(TaskList* order, int cookie) { | |
708 order->RecordStart(ORDERED, cookie); | |
709 order->RecordEnd(ORDERED, cookie); | |
710 } | |
711 | |
712 #if defined(OS_WIN) | |
713 | |
714 // MessageLoop implicitly start a "modal message loop". Modal dialog boxes, | |
715 // common controls (like OpenFile) and StartDoc printing function can cause | |
716 // implicit message loops. | |
717 void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) { | |
718 order->RecordStart(MESSAGEBOX, cookie); | |
719 if (is_reentrant) | |
720 MessageLoop::current()->SetNestableTasksAllowed(true); | |
721 MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK); | |
722 order->RecordEnd(MESSAGEBOX, cookie); | |
723 } | |
724 | |
725 // Will end the MessageBox. | |
726 void EndDialogFunc(TaskList* order, int cookie) { | |
727 order->RecordStart(ENDDIALOG, cookie); | |
728 HWND window = GetActiveWindow(); | |
729 if (window != NULL) { | |
730 EXPECT_NE(EndDialog(window, IDCONTINUE), 0); | |
731 // Cheap way to signal that the window wasn't found if RunEnd() isn't | |
732 // called. | |
733 order->RecordEnd(ENDDIALOG, cookie); | |
734 } | |
735 } | |
736 | |
737 #endif // defined(OS_WIN) | |
738 | |
739 void RecursiveFunc(TaskList* order, int cookie, int depth, | |
740 bool is_reentrant) { | |
741 order->RecordStart(RECURSIVE, cookie); | |
742 if (depth > 0) { | |
743 if (is_reentrant) | |
744 MessageLoop::current()->SetNestableTasksAllowed(true); | |
745 MessageLoop::current()->PostTask( | |
746 FROM_HERE, | |
747 Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant)); | |
748 } | |
749 order->RecordEnd(RECURSIVE, cookie); | |
750 } | |
751 | |
752 void RecursiveSlowFunc(TaskList* order, int cookie, int depth, | |
753 bool is_reentrant) { | |
754 RecursiveFunc(order, cookie, depth, is_reentrant); | |
755 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); | |
756 } | |
757 | |
758 void QuitFunc(TaskList* order, int cookie) { | |
759 order->RecordStart(QUITMESSAGELOOP, cookie); | |
760 MessageLoop::current()->QuitWhenIdle(); | |
761 order->RecordEnd(QUITMESSAGELOOP, cookie); | |
762 } | |
763 | |
764 void SleepFunc(TaskList* order, int cookie, TimeDelta delay) { | |
765 order->RecordStart(SLEEP, cookie); | |
766 PlatformThread::Sleep(delay); | |
767 order->RecordEnd(SLEEP, cookie); | |
768 } | |
769 | |
770 #if defined(OS_WIN) | |
771 void RecursiveFuncWin(MessageLoop* target, | |
772 HANDLE event, | |
773 bool expect_window, | |
774 TaskList* order, | |
775 bool is_reentrant) { | |
776 target->PostTask(FROM_HERE, | |
777 Bind(&RecursiveFunc, order, 1, 2, is_reentrant)); | |
778 target->PostTask(FROM_HERE, | |
779 Bind(&MessageBoxFunc, order, 2, is_reentrant)); | |
780 target->PostTask(FROM_HERE, | |
781 Bind(&RecursiveFunc, order, 3, 2, is_reentrant)); | |
782 // The trick here is that for recursive task processing, this task will be | |
783 // ran _inside_ the MessageBox message loop, dismissing the MessageBox | |
784 // without a chance. | |
785 // For non-recursive task processing, this will be executed _after_ the | |
786 // MessageBox will have been dismissed by the code below, where | |
787 // expect_window_ is true. | |
788 target->PostTask(FROM_HERE, | |
789 Bind(&EndDialogFunc, order, 4)); | |
790 target->PostTask(FROM_HERE, | |
791 Bind(&QuitFunc, order, 5)); | |
792 | |
793 // Enforce that every tasks are sent before starting to run the main thread | |
794 // message loop. | |
795 ASSERT_TRUE(SetEvent(event)); | |
796 | |
797 // Poll for the MessageBox. Don't do this at home! At the speed we do it, | |
798 // you will never realize one MessageBox was shown. | |
799 for (; expect_window;) { | |
800 HWND window = FindWindow(L"#32770", kMessageBoxTitle); | |
801 if (window) { | |
802 // Dismiss it. | |
803 for (;;) { | |
804 HWND button = FindWindowEx(window, NULL, L"Button", NULL); | |
805 if (button != NULL) { | |
806 EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0)); | |
807 EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0)); | |
808 break; | |
809 } | |
810 } | |
811 break; | |
812 } | |
813 } | |
814 } | |
815 | |
816 #endif // defined(OS_WIN) | |
817 | |
818 void RunTest_RecursiveDenial1(MessageLoop::Type message_loop_type) { | |
819 MessageLoop loop(message_loop_type); | |
820 | |
821 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); | |
822 TaskList order; | |
823 MessageLoop::current()->PostTask( | |
824 FROM_HERE, | |
825 Bind(&RecursiveFunc, &order, 1, 2, false)); | |
826 MessageLoop::current()->PostTask( | |
827 FROM_HERE, | |
828 Bind(&RecursiveFunc, &order, 2, 2, false)); | |
829 MessageLoop::current()->PostTask( | |
830 FROM_HERE, | |
831 Bind(&QuitFunc, &order, 3)); | |
832 | |
833 MessageLoop::current()->Run(); | |
834 | |
835 // FIFO order. | |
836 ASSERT_EQ(14U, order.Size()); | |
837 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); | |
838 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); | |
839 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); | |
840 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); | |
841 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); | |
842 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); | |
843 EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); | |
844 EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); | |
845 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); | |
846 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); | |
847 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); | |
848 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); | |
849 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); | |
850 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); | |
851 } | |
852 | |
853 void RunTest_RecursiveDenial3(MessageLoop::Type message_loop_type) { | |
854 MessageLoop loop(message_loop_type); | |
855 | |
856 EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed()); | |
857 TaskList order; | |
858 MessageLoop::current()->PostTask( | |
859 FROM_HERE, Bind(&RecursiveSlowFunc, &order, 1, 2, false)); | |
860 MessageLoop::current()->PostTask( | |
861 FROM_HERE, Bind(&RecursiveSlowFunc, &order, 2, 2, false)); | |
862 MessageLoop::current()->PostDelayedTask( | |
863 FROM_HERE, | |
864 Bind(&OrderedFunc, &order, 3), | |
865 TimeDelta::FromMilliseconds(5)); | |
866 MessageLoop::current()->PostDelayedTask( | |
867 FROM_HERE, | |
868 Bind(&QuitFunc, &order, 4), | |
869 TimeDelta::FromMilliseconds(5)); | |
870 | |
871 MessageLoop::current()->Run(); | |
872 | |
873 // FIFO order. | |
874 ASSERT_EQ(16U, order.Size()); | |
875 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); | |
876 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); | |
877 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); | |
878 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); | |
879 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true)); | |
880 EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false)); | |
881 EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 3, true)); | |
882 EXPECT_EQ(order.Get(7), TaskItem(ORDERED, 3, false)); | |
883 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); | |
884 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); | |
885 EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true)); | |
886 EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false)); | |
887 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true)); | |
888 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false)); | |
889 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true)); | |
890 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false)); | |
891 } | |
892 | |
893 void RunTest_RecursiveSupport1(MessageLoop::Type message_loop_type) { | |
894 MessageLoop loop(message_loop_type); | |
895 | |
896 TaskList order; | |
897 MessageLoop::current()->PostTask( | |
898 FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, true)); | |
899 MessageLoop::current()->PostTask( | |
900 FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, true)); | |
901 MessageLoop::current()->PostTask( | |
902 FROM_HERE, Bind(&QuitFunc, &order, 3)); | |
903 | |
904 MessageLoop::current()->Run(); | |
905 | |
906 // FIFO order. | |
907 ASSERT_EQ(14U, order.Size()); | |
908 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); | |
909 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); | |
910 EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true)); | |
911 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false)); | |
912 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); | |
913 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); | |
914 EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true)); | |
915 EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false)); | |
916 EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true)); | |
917 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false)); | |
918 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); | |
919 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); | |
920 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true)); | |
921 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false)); | |
922 } | |
923 | |
924 #if defined(OS_WIN) | |
925 // TODO(darin): These tests need to be ported since they test critical | |
926 // message loop functionality. | |
927 | |
928 // A side effect of this test is the generation a beep. Sorry. | |
929 void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) { | |
930 MessageLoop loop(message_loop_type); | |
931 | |
932 Thread worker("RecursiveDenial2_worker"); | |
933 Thread::Options options; | |
934 options.message_loop_type = message_loop_type; | |
935 ASSERT_EQ(true, worker.StartWithOptions(options)); | |
936 TaskList order; | |
937 win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL)); | |
938 worker.message_loop()->PostTask(FROM_HERE, | |
939 Bind(&RecursiveFuncWin, | |
940 MessageLoop::current(), | |
941 event.Get(), | |
942 true, | |
943 &order, | |
944 false)); | |
945 // Let the other thread execute. | |
946 WaitForSingleObject(event, INFINITE); | |
947 MessageLoop::current()->Run(); | |
948 | |
949 ASSERT_EQ(order.Size(), 17); | |
950 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); | |
951 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); | |
952 EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true)); | |
953 EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false)); | |
954 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true)); | |
955 EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false)); | |
956 // When EndDialogFunc is processed, the window is already dismissed, hence no | |
957 // "end" entry. | |
958 EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true)); | |
959 EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true)); | |
960 EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false)); | |
961 EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true)); | |
962 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false)); | |
963 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true)); | |
964 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false)); | |
965 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true)); | |
966 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false)); | |
967 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true)); | |
968 EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false)); | |
969 } | |
970 | |
971 // A side effect of this test is the generation a beep. Sorry. This test also | |
972 // needs to process windows messages on the current thread. | |
973 void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) { | |
974 MessageLoop loop(message_loop_type); | |
975 | |
976 Thread worker("RecursiveSupport2_worker"); | |
977 Thread::Options options; | |
978 options.message_loop_type = message_loop_type; | |
979 ASSERT_EQ(true, worker.StartWithOptions(options)); | |
980 TaskList order; | |
981 win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL)); | |
982 worker.message_loop()->PostTask(FROM_HERE, | |
983 Bind(&RecursiveFuncWin, | |
984 MessageLoop::current(), | |
985 event.Get(), | |
986 false, | |
987 &order, | |
988 true)); | |
989 // Let the other thread execute. | |
990 WaitForSingleObject(event, INFINITE); | |
991 MessageLoop::current()->Run(); | |
992 | |
993 ASSERT_EQ(order.Size(), 18); | |
994 EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true)); | |
995 EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false)); | |
996 EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true)); | |
997 // Note that this executes in the MessageBox modal loop. | |
998 EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true)); | |
999 EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false)); | |
1000 EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true)); | |
1001 EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false)); | |
1002 EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false)); | |
1003 /* The order can subtly change here. The reason is that when RecursiveFunc(1) | |
1004 is called in the main thread, if it is faster than getting to the | |
1005 PostTask(FROM_HERE, Bind(&QuitFunc) execution, the order of task | |
1006 execution can change. We don't care anyway that the order isn't correct. | |
1007 EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, true)); | |
1008 EXPECT_EQ(order.Get(9), TaskItem(QUITMESSAGELOOP, 5, false)); | |
1009 EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true)); | |
1010 EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false)); | |
1011 */ | |
1012 EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, true)); | |
1013 EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 3, false)); | |
1014 EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, true)); | |
1015 EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 1, false)); | |
1016 EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, true)); | |
1017 EXPECT_EQ(order.Get(17), TaskItem(RECURSIVE, 3, false)); | |
1018 } | |
1019 | |
1020 #endif // defined(OS_WIN) | |
1021 | |
1022 void FuncThatPumps(TaskList* order, int cookie) { | |
1023 order->RecordStart(PUMPS, cookie); | |
1024 { | |
1025 MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); | |
1026 RunLoop().RunUntilIdle(); | |
1027 } | |
1028 order->RecordEnd(PUMPS, cookie); | |
1029 } | |
1030 | |
1031 void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) { | |
1032 order->RecordStart(RUNS, cookie); | |
1033 { | |
1034 MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current()); | |
1035 run_loop->Run(); | |
1036 } | |
1037 order->RecordEnd(RUNS, cookie); | |
1038 } | |
1039 | |
1040 void FuncThatQuitsNow() { | |
1041 MessageLoop::current()->QuitNow(); | |
1042 } | |
1043 | |
1044 // Tests that non nestable tasks run in FIFO if there are no nested loops. | |
1045 void RunTest_NonNestableWithNoNesting( | |
1046 MessageLoop::Type message_loop_type) { | |
1047 MessageLoop loop(message_loop_type); | |
1048 | |
1049 TaskList order; | |
1050 | |
1051 MessageLoop::current()->PostNonNestableTask( | |
1052 FROM_HERE, | |
1053 Bind(&OrderedFunc, &order, 1)); | |
1054 MessageLoop::current()->PostTask(FROM_HERE, | |
1055 Bind(&OrderedFunc, &order, 2)); | |
1056 MessageLoop::current()->PostTask(FROM_HERE, | |
1057 Bind(&QuitFunc, &order, 3)); | |
1058 MessageLoop::current()->Run(); | |
1059 | |
1060 // FIFO order. | |
1061 ASSERT_EQ(6U, order.Size()); | |
1062 EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true)); | |
1063 EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false)); | |
1064 EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true)); | |
1065 EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false)); | |
1066 EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true)); | |
1067 EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false)); | |
1068 } | |
1069 | |
1070 // Tests that non nestable tasks don't run when there's code in the call stack. | |
1071 void RunTest_NonNestableInNestedLoop(MessageLoop::Type message_loop_type, | |
1072 bool use_delayed) { | |
1073 MessageLoop loop(message_loop_type); | |
1074 | |
1075 TaskList order; | |
1076 | |
1077 MessageLoop::current()->PostTask( | |
1078 FROM_HERE, | |
1079 Bind(&FuncThatPumps, &order, 1)); | |
1080 if (use_delayed) { | |
1081 MessageLoop::current()->PostNonNestableDelayedTask( | |
1082 FROM_HERE, | |
1083 Bind(&OrderedFunc, &order, 2), | |
1084 TimeDelta::FromMilliseconds(1)); | |
1085 } else { | |
1086 MessageLoop::current()->PostNonNestableTask( | |
1087 FROM_HERE, | |
1088 Bind(&OrderedFunc, &order, 2)); | |
1089 } | |
1090 MessageLoop::current()->PostTask(FROM_HERE, | |
1091 Bind(&OrderedFunc, &order, 3)); | |
1092 MessageLoop::current()->PostTask( | |
1093 FROM_HERE, | |
1094 Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50))); | |
1095 MessageLoop::current()->PostTask(FROM_HERE, | |
1096 Bind(&OrderedFunc, &order, 5)); | |
1097 if (use_delayed) { | |
1098 MessageLoop::current()->PostNonNestableDelayedTask( | |
1099 FROM_HERE, | |
1100 Bind(&QuitFunc, &order, 6), | |
1101 TimeDelta::FromMilliseconds(2)); | |
1102 } else { | |
1103 MessageLoop::current()->PostNonNestableTask( | |
1104 FROM_HERE, | |
1105 Bind(&QuitFunc, &order, 6)); | |
1106 } | |
1107 | |
1108 MessageLoop::current()->Run(); | |
1109 | |
1110 // FIFO order. | |
1111 ASSERT_EQ(12U, order.Size()); | |
1112 EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true)); | |
1113 EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true)); | |
1114 EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false)); | |
1115 EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true)); | |
1116 EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false)); | |
1117 EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true)); | |
1118 EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false)); | |
1119 EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false)); | |
1120 EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true)); | |
1121 EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false)); | |
1122 EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true)); | |
1123 EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false)); | |
1124 } | |
1125 | |
1126 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. | |
1127 void RunTest_QuitNow(MessageLoop::Type message_loop_type) { | |
1128 MessageLoop loop(message_loop_type); | |
1129 | |
1130 TaskList order; | |
1131 | |
1132 RunLoop run_loop; | |
1133 | |
1134 MessageLoop::current()->PostTask(FROM_HERE, | |
1135 Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop))); | |
1136 MessageLoop::current()->PostTask( | |
1137 FROM_HERE, Bind(&OrderedFunc, &order, 2)); | |
1138 MessageLoop::current()->PostTask( | |
1139 FROM_HERE, Bind(&FuncThatQuitsNow)); | |
1140 MessageLoop::current()->PostTask( | |
1141 FROM_HERE, Bind(&OrderedFunc, &order, 3)); | |
1142 MessageLoop::current()->PostTask( | |
1143 FROM_HERE, Bind(&FuncThatQuitsNow)); | |
1144 MessageLoop::current()->PostTask( | |
1145 FROM_HERE, Bind(&OrderedFunc, &order, 4)); // never runs | |
1146 | |
1147 MessageLoop::current()->Run(); | |
1148 | |
1149 ASSERT_EQ(6U, order.Size()); | |
1150 int task_index = 0; | |
1151 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); | |
1152 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); | |
1153 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); | |
1154 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); | |
1155 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); | |
1156 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); | |
1157 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); | |
1158 } | |
1159 | |
1160 // Tests RunLoopQuit works before RunWithID. | |
1161 void RunTest_RunLoopQuitOrderBefore(MessageLoop::Type message_loop_type) { | |
1162 MessageLoop loop(message_loop_type); | |
1163 | |
1164 TaskList order; | |
1165 | |
1166 RunLoop run_loop; | |
1167 | |
1168 run_loop.Quit(); | |
1169 | |
1170 MessageLoop::current()->PostTask( | |
1171 FROM_HERE, Bind(&OrderedFunc, &order, 1)); // never runs | |
1172 MessageLoop::current()->PostTask( | |
1173 FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs | |
1174 | |
1175 run_loop.Run(); | |
1176 | |
1177 ASSERT_EQ(0U, order.Size()); | |
1178 } | |
1179 | |
1180 // Tests RunLoopQuit works during RunWithID. | |
1181 void RunTest_RunLoopQuitOrderDuring(MessageLoop::Type message_loop_type) { | |
1182 MessageLoop loop(message_loop_type); | |
1183 | |
1184 TaskList order; | |
1185 | |
1186 RunLoop run_loop; | |
1187 | |
1188 MessageLoop::current()->PostTask( | |
1189 FROM_HERE, Bind(&OrderedFunc, &order, 1)); | |
1190 MessageLoop::current()->PostTask( | |
1191 FROM_HERE, run_loop.QuitClosure()); | |
1192 MessageLoop::current()->PostTask( | |
1193 FROM_HERE, Bind(&OrderedFunc, &order, 2)); // never runs | |
1194 MessageLoop::current()->PostTask( | |
1195 FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs | |
1196 | |
1197 run_loop.Run(); | |
1198 | |
1199 ASSERT_EQ(2U, order.Size()); | |
1200 int task_index = 0; | |
1201 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, true)); | |
1202 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, false)); | |
1203 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); | |
1204 } | |
1205 | |
1206 // Tests RunLoopQuit works after RunWithID. | |
1207 void RunTest_RunLoopQuitOrderAfter(MessageLoop::Type message_loop_type) { | |
1208 MessageLoop loop(message_loop_type); | |
1209 | |
1210 TaskList order; | |
1211 | |
1212 RunLoop run_loop; | |
1213 | |
1214 MessageLoop::current()->PostTask(FROM_HERE, | |
1215 Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop))); | |
1216 MessageLoop::current()->PostTask( | |
1217 FROM_HERE, Bind(&OrderedFunc, &order, 2)); | |
1218 MessageLoop::current()->PostTask( | |
1219 FROM_HERE, Bind(&FuncThatQuitsNow)); | |
1220 MessageLoop::current()->PostTask( | |
1221 FROM_HERE, Bind(&OrderedFunc, &order, 3)); | |
1222 MessageLoop::current()->PostTask( | |
1223 FROM_HERE, run_loop.QuitClosure()); // has no affect | |
1224 MessageLoop::current()->PostTask( | |
1225 FROM_HERE, Bind(&OrderedFunc, &order, 4)); | |
1226 MessageLoop::current()->PostTask( | |
1227 FROM_HERE, Bind(&FuncThatQuitsNow)); | |
1228 | |
1229 RunLoop outer_run_loop; | |
1230 outer_run_loop.Run(); | |
1231 | |
1232 ASSERT_EQ(8U, order.Size()); | |
1233 int task_index = 0; | |
1234 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); | |
1235 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); | |
1236 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); | |
1237 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); | |
1238 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true)); | |
1239 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false)); | |
1240 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, true)); | |
1241 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, false)); | |
1242 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); | |
1243 } | |
1244 | |
1245 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. | |
1246 void RunTest_RunLoopQuitTop(MessageLoop::Type message_loop_type) { | |
1247 MessageLoop loop(message_loop_type); | |
1248 | |
1249 TaskList order; | |
1250 | |
1251 RunLoop outer_run_loop; | |
1252 RunLoop nested_run_loop; | |
1253 | |
1254 MessageLoop::current()->PostTask(FROM_HERE, | |
1255 Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); | |
1256 MessageLoop::current()->PostTask( | |
1257 FROM_HERE, outer_run_loop.QuitClosure()); | |
1258 MessageLoop::current()->PostTask( | |
1259 FROM_HERE, Bind(&OrderedFunc, &order, 2)); | |
1260 MessageLoop::current()->PostTask( | |
1261 FROM_HERE, nested_run_loop.QuitClosure()); | |
1262 | |
1263 outer_run_loop.Run(); | |
1264 | |
1265 ASSERT_EQ(4U, order.Size()); | |
1266 int task_index = 0; | |
1267 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); | |
1268 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); | |
1269 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); | |
1270 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); | |
1271 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); | |
1272 } | |
1273 | |
1274 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. | |
1275 void RunTest_RunLoopQuitNested(MessageLoop::Type message_loop_type) { | |
1276 MessageLoop loop(message_loop_type); | |
1277 | |
1278 TaskList order; | |
1279 | |
1280 RunLoop outer_run_loop; | |
1281 RunLoop nested_run_loop; | |
1282 | |
1283 MessageLoop::current()->PostTask(FROM_HERE, | |
1284 Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); | |
1285 MessageLoop::current()->PostTask( | |
1286 FROM_HERE, nested_run_loop.QuitClosure()); | |
1287 MessageLoop::current()->PostTask( | |
1288 FROM_HERE, Bind(&OrderedFunc, &order, 2)); | |
1289 MessageLoop::current()->PostTask( | |
1290 FROM_HERE, outer_run_loop.QuitClosure()); | |
1291 | |
1292 outer_run_loop.Run(); | |
1293 | |
1294 ASSERT_EQ(4U, order.Size()); | |
1295 int task_index = 0; | |
1296 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); | |
1297 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); | |
1298 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); | |
1299 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); | |
1300 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); | |
1301 } | |
1302 | |
1303 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. | |
1304 void RunTest_RunLoopQuitBogus(MessageLoop::Type message_loop_type) { | |
1305 MessageLoop loop(message_loop_type); | |
1306 | |
1307 TaskList order; | |
1308 | |
1309 RunLoop outer_run_loop; | |
1310 RunLoop nested_run_loop; | |
1311 RunLoop bogus_run_loop; | |
1312 | |
1313 MessageLoop::current()->PostTask(FROM_HERE, | |
1314 Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop))); | |
1315 MessageLoop::current()->PostTask( | |
1316 FROM_HERE, bogus_run_loop.QuitClosure()); | |
1317 MessageLoop::current()->PostTask( | |
1318 FROM_HERE, Bind(&OrderedFunc, &order, 2)); | |
1319 MessageLoop::current()->PostTask( | |
1320 FROM_HERE, outer_run_loop.QuitClosure()); | |
1321 MessageLoop::current()->PostTask( | |
1322 FROM_HERE, nested_run_loop.QuitClosure()); | |
1323 | |
1324 outer_run_loop.Run(); | |
1325 | |
1326 ASSERT_EQ(4U, order.Size()); | |
1327 int task_index = 0; | |
1328 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); | |
1329 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true)); | |
1330 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false)); | |
1331 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); | |
1332 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); | |
1333 } | |
1334 | |
1335 // Tests RunLoopQuit only quits the corresponding MessageLoop::Run. | |
1336 void RunTest_RunLoopQuitDeep(MessageLoop::Type message_loop_type) { | |
1337 MessageLoop loop(message_loop_type); | |
1338 | |
1339 TaskList order; | |
1340 | |
1341 RunLoop outer_run_loop; | |
1342 RunLoop nested_loop1; | |
1343 RunLoop nested_loop2; | |
1344 RunLoop nested_loop3; | |
1345 RunLoop nested_loop4; | |
1346 | |
1347 MessageLoop::current()->PostTask(FROM_HERE, | |
1348 Bind(&FuncThatRuns, &order, 1, Unretained(&nested_loop1))); | |
1349 MessageLoop::current()->PostTask(FROM_HERE, | |
1350 Bind(&FuncThatRuns, &order, 2, Unretained(&nested_loop2))); | |
1351 MessageLoop::current()->PostTask(FROM_HERE, | |
1352 Bind(&FuncThatRuns, &order, 3, Unretained(&nested_loop3))); | |
1353 MessageLoop::current()->PostTask(FROM_HERE, | |
1354 Bind(&FuncThatRuns, &order, 4, Unretained(&nested_loop4))); | |
1355 MessageLoop::current()->PostTask( | |
1356 FROM_HERE, Bind(&OrderedFunc, &order, 5)); | |
1357 MessageLoop::current()->PostTask( | |
1358 FROM_HERE, outer_run_loop.QuitClosure()); | |
1359 MessageLoop::current()->PostTask( | |
1360 FROM_HERE, Bind(&OrderedFunc, &order, 6)); | |
1361 MessageLoop::current()->PostTask( | |
1362 FROM_HERE, nested_loop1.QuitClosure()); | |
1363 MessageLoop::current()->PostTask( | |
1364 FROM_HERE, Bind(&OrderedFunc, &order, 7)); | |
1365 MessageLoop::current()->PostTask( | |
1366 FROM_HERE, nested_loop2.QuitClosure()); | |
1367 MessageLoop::current()->PostTask( | |
1368 FROM_HERE, Bind(&OrderedFunc, &order, 8)); | |
1369 MessageLoop::current()->PostTask( | |
1370 FROM_HERE, nested_loop3.QuitClosure()); | |
1371 MessageLoop::current()->PostTask( | |
1372 FROM_HERE, Bind(&OrderedFunc, &order, 9)); | |
1373 MessageLoop::current()->PostTask( | |
1374 FROM_HERE, nested_loop4.QuitClosure()); | |
1375 MessageLoop::current()->PostTask( | |
1376 FROM_HERE, Bind(&OrderedFunc, &order, 10)); | |
1377 | |
1378 outer_run_loop.Run(); | |
1379 | |
1380 ASSERT_EQ(18U, order.Size()); | |
1381 int task_index = 0; | |
1382 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true)); | |
1383 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, true)); | |
1384 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, true)); | |
1385 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, true)); | |
1386 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, true)); | |
1387 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, false)); | |
1388 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, true)); | |
1389 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, false)); | |
1390 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, true)); | |
1391 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, false)); | |
1392 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, true)); | |
1393 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, false)); | |
1394 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, true)); | |
1395 EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, false)); | |
1396 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, false)); | |
1397 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, false)); | |
1398 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, false)); | |
1399 EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false)); | |
1400 EXPECT_EQ(static_cast<size_t>(task_index), order.Size()); | |
1401 } | |
1402 | |
1403 void PostNTasksThenQuit(int posts_remaining) { | |
1404 if (posts_remaining > 1) { | |
1405 MessageLoop::current()->PostTask( | |
1406 FROM_HERE, | |
1407 Bind(&PostNTasksThenQuit, posts_remaining - 1)); | |
1408 } else { | |
1409 MessageLoop::current()->QuitWhenIdle(); | |
1410 } | |
1411 } | |
1412 | |
1413 void RunTest_RecursivePosts(MessageLoop::Type message_loop_type, | |
1414 int num_times) { | |
1415 MessageLoop loop(message_loop_type); | |
1416 loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, num_times)); | |
1417 loop.Run(); | |
1418 } | |
1419 | |
1420 #if defined(OS_WIN) | |
1421 | |
1422 class DispatcherImpl : public base::MessageLoopForUI::Dispatcher { | |
1423 public: | |
1424 DispatcherImpl() : dispatch_count_(0) {} | |
1425 | |
1426 virtual bool Dispatch(const NativeEvent& msg) OVERRIDE { | |
1427 ::TranslateMessage(&msg); | |
1428 ::DispatchMessage(&msg); | |
1429 // Do not count WM_TIMER since it is not what we post and it will cause | |
1430 // flakiness. | |
1431 if (msg.message != WM_TIMER) | |
1432 ++dispatch_count_; | |
1433 // We treat WM_LBUTTONUP as the last message. | |
1434 return msg.message != WM_LBUTTONUP; | |
1435 } | |
1436 | |
1437 int dispatch_count_; | |
1438 }; | |
1439 | |
1440 void MouseDownUp() { | |
1441 PostMessage(NULL, WM_LBUTTONDOWN, 0, 0); | |
1442 PostMessage(NULL, WM_LBUTTONUP, 'A', 0); | |
1443 } | |
1444 | |
1445 void RunTest_Dispatcher(MessageLoop::Type message_loop_type) { | |
1446 MessageLoop loop(message_loop_type); | |
1447 | |
1448 MessageLoop::current()->PostDelayedTask( | |
1449 FROM_HERE, | |
1450 Bind(&MouseDownUp), | |
1451 TimeDelta::FromMilliseconds(100)); | |
1452 DispatcherImpl dispatcher; | |
1453 RunLoop run_loop(&dispatcher); | |
1454 run_loop.Run(); | |
1455 ASSERT_EQ(2, dispatcher.dispatch_count_); | |
1456 } | |
1457 | |
1458 LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) { | |
1459 if (code == MessagePumpForUI::kMessageFilterCode) { | |
1460 MSG* msg = reinterpret_cast<MSG*>(lparam); | |
1461 if (msg->message == WM_LBUTTONDOWN) | |
1462 return TRUE; | |
1463 } | |
1464 return FALSE; | |
1465 } | |
1466 | |
1467 void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) { | |
1468 MessageLoop loop(message_loop_type); | |
1469 | |
1470 MessageLoop::current()->PostDelayedTask( | |
1471 FROM_HERE, | |
1472 Bind(&MouseDownUp), | |
1473 TimeDelta::FromMilliseconds(100)); | |
1474 HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER, | |
1475 MsgFilterProc, | |
1476 NULL, | |
1477 GetCurrentThreadId()); | |
1478 DispatcherImpl dispatcher; | |
1479 RunLoop run_loop(&dispatcher); | |
1480 run_loop.Run(); | |
1481 ASSERT_EQ(1, dispatcher.dispatch_count_); | |
1482 UnhookWindowsHookEx(msg_hook); | |
1483 } | |
1484 | |
1485 class TestIOHandler : public MessageLoopForIO::IOHandler { | |
1486 public: | |
1487 TestIOHandler(const wchar_t* name, HANDLE signal, bool wait); | |
1488 | |
1489 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context, | |
1490 DWORD bytes_transfered, DWORD error); | |
1491 | |
1492 void Init(); | |
1493 void WaitForIO(); | |
1494 OVERLAPPED* context() { return &context_.overlapped; } | |
1495 DWORD size() { return sizeof(buffer_); } | |
1496 | |
1497 private: | |
1498 char buffer_[48]; | |
1499 MessageLoopForIO::IOContext context_; | |
1500 HANDLE signal_; | |
1501 win::ScopedHandle file_; | |
1502 bool wait_; | |
1503 }; | |
1504 | |
1505 TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait) | |
1506 : signal_(signal), wait_(wait) { | |
1507 memset(buffer_, 0, sizeof(buffer_)); | |
1508 memset(&context_, 0, sizeof(context_)); | |
1509 context_.handler = this; | |
1510 | |
1511 file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING, | |
1512 FILE_FLAG_OVERLAPPED, NULL)); | |
1513 EXPECT_TRUE(file_.IsValid()); | |
1514 } | |
1515 | |
1516 void TestIOHandler::Init() { | |
1517 MessageLoopForIO::current()->RegisterIOHandler(file_, this); | |
1518 | |
1519 DWORD read; | |
1520 EXPECT_FALSE(ReadFile(file_, buffer_, size(), &read, context())); | |
1521 EXPECT_EQ(ERROR_IO_PENDING, GetLastError()); | |
1522 if (wait_) | |
1523 WaitForIO(); | |
1524 } | |
1525 | |
1526 void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context, | |
1527 DWORD bytes_transfered, DWORD error) { | |
1528 ASSERT_TRUE(context == &context_); | |
1529 ASSERT_TRUE(SetEvent(signal_)); | |
1530 } | |
1531 | |
1532 void TestIOHandler::WaitForIO() { | |
1533 EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this)); | |
1534 EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this)); | |
1535 } | |
1536 | |
1537 void RunTest_IOHandler() { | |
1538 win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL)); | |
1539 ASSERT_TRUE(callback_called.IsValid()); | |
1540 | |
1541 const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe"; | |
1542 win::ScopedHandle server( | |
1543 CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL)); | |
1544 ASSERT_TRUE(server.IsValid()); | |
1545 | |
1546 Thread thread("IOHandler test"); | |
1547 Thread::Options options; | |
1548 options.message_loop_type = MessageLoop::TYPE_IO; | |
1549 ASSERT_TRUE(thread.StartWithOptions(options)); | |
1550 | |
1551 MessageLoop* thread_loop = thread.message_loop(); | |
1552 ASSERT_TRUE(NULL != thread_loop); | |
1553 | |
1554 TestIOHandler handler(kPipeName, callback_called, false); | |
1555 thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init, | |
1556 Unretained(&handler))); | |
1557 // Make sure the thread runs and sleeps for lack of work. | |
1558 PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); | |
1559 | |
1560 const char buffer[] = "Hello there!"; | |
1561 DWORD written; | |
1562 EXPECT_TRUE(WriteFile(server, buffer, sizeof(buffer), &written, NULL)); | |
1563 | |
1564 DWORD result = WaitForSingleObject(callback_called, 1000); | |
1565 EXPECT_EQ(WAIT_OBJECT_0, result); | |
1566 | |
1567 thread.Stop(); | |
1568 } | |
1569 | |
1570 void RunTest_WaitForIO() { | |
1571 win::ScopedHandle callback1_called( | |
1572 CreateEvent(NULL, TRUE, FALSE, NULL)); | |
1573 win::ScopedHandle callback2_called( | |
1574 CreateEvent(NULL, TRUE, FALSE, NULL)); | |
1575 ASSERT_TRUE(callback1_called.IsValid()); | |
1576 ASSERT_TRUE(callback2_called.IsValid()); | |
1577 | |
1578 const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1"; | |
1579 const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2"; | |
1580 win::ScopedHandle server1( | |
1581 CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL)); | |
1582 win::ScopedHandle server2( | |
1583 CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL)); | |
1584 ASSERT_TRUE(server1.IsValid()); | |
1585 ASSERT_TRUE(server2.IsValid()); | |
1586 | |
1587 Thread thread("IOHandler test"); | |
1588 Thread::Options options; | |
1589 options.message_loop_type = MessageLoop::TYPE_IO; | |
1590 ASSERT_TRUE(thread.StartWithOptions(options)); | |
1591 | |
1592 MessageLoop* thread_loop = thread.message_loop(); | |
1593 ASSERT_TRUE(NULL != thread_loop); | |
1594 | |
1595 TestIOHandler handler1(kPipeName1, callback1_called, false); | |
1596 TestIOHandler handler2(kPipeName2, callback2_called, true); | |
1597 thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init, | |
1598 Unretained(&handler1))); | |
1599 // TODO(ajwong): Do we really need such long Sleeps in ths function? | |
1600 // Make sure the thread runs and sleeps for lack of work. | |
1601 TimeDelta delay = TimeDelta::FromMilliseconds(100); | |
1602 PlatformThread::Sleep(delay); | |
1603 thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init, | |
1604 Unretained(&handler2))); | |
1605 PlatformThread::Sleep(delay); | |
1606 | |
1607 // At this time handler1 is waiting to be called, and the thread is waiting | |
1608 // on the Init method of handler2, filtering only handler2 callbacks. | |
1609 | |
1610 const char buffer[] = "Hello there!"; | |
1611 DWORD written; | |
1612 EXPECT_TRUE(WriteFile(server1, buffer, sizeof(buffer), &written, NULL)); | |
1613 PlatformThread::Sleep(2 * delay); | |
1614 EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called, 0)) << | |
1615 "handler1 has not been called"; | |
1616 | |
1617 EXPECT_TRUE(WriteFile(server2, buffer, sizeof(buffer), &written, NULL)); | |
1618 | |
1619 HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() }; | |
1620 DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000); | |
1621 EXPECT_EQ(WAIT_OBJECT_0, result); | |
1622 | |
1623 thread.Stop(); | |
1624 } | |
1625 | |
1626 #endif // defined(OS_WIN) | |
1627 | |
1628 } // namespace | |
1629 | |
1630 //----------------------------------------------------------------------------- | |
1631 // Each test is run against each type of MessageLoop. That way we are sure | |
1632 // that message loops work properly in all configurations. Of course, in some | |
1633 // cases, a unit test may only be for a particular type of loop. | |
1634 | |
1635 TEST(MessageLoopTest, PostTask) { | |
1636 RunTest_PostTask(MessageLoop::TYPE_DEFAULT); | |
1637 RunTest_PostTask(MessageLoop::TYPE_UI); | |
1638 RunTest_PostTask(MessageLoop::TYPE_IO); | |
1639 } | |
1640 | |
1641 TEST(MessageLoopTest, PostTask_SEH) { | |
1642 RunTest_PostTask_SEH(MessageLoop::TYPE_DEFAULT); | |
1643 RunTest_PostTask_SEH(MessageLoop::TYPE_UI); | |
1644 RunTest_PostTask_SEH(MessageLoop::TYPE_IO); | |
1645 } | |
1646 | |
1647 TEST(MessageLoopTest, PostDelayedTask_Basic) { | |
1648 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_DEFAULT); | |
1649 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_UI); | |
1650 RunTest_PostDelayedTask_Basic(MessageLoop::TYPE_IO); | |
1651 } | |
1652 | |
1653 TEST(MessageLoopTest, PostDelayedTask_InDelayOrder) { | |
1654 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_DEFAULT); | |
1655 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_UI); | |
1656 RunTest_PostDelayedTask_InDelayOrder(MessageLoop::TYPE_IO); | |
1657 } | |
1658 | |
1659 TEST(MessageLoopTest, PostDelayedTask_InPostOrder) { | |
1660 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_DEFAULT); | |
1661 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_UI); | |
1662 RunTest_PostDelayedTask_InPostOrder(MessageLoop::TYPE_IO); | |
1663 } | |
1664 | |
1665 TEST(MessageLoopTest, PostDelayedTask_InPostOrder_2) { | |
1666 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_DEFAULT); | |
1667 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_UI); | |
1668 RunTest_PostDelayedTask_InPostOrder_2(MessageLoop::TYPE_IO); | |
1669 } | |
1670 | |
1671 TEST(MessageLoopTest, PostDelayedTask_InPostOrder_3) { | |
1672 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_DEFAULT); | |
1673 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_UI); | |
1674 RunTest_PostDelayedTask_InPostOrder_3(MessageLoop::TYPE_IO); | |
1675 } | |
1676 | |
1677 TEST(MessageLoopTest, PostDelayedTask_SharedTimer) { | |
1678 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_DEFAULT); | |
1679 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_UI); | |
1680 RunTest_PostDelayedTask_SharedTimer(MessageLoop::TYPE_IO); | |
1681 } | |
1682 | |
1683 #if defined(OS_WIN) | |
1684 TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) { | |
1685 RunTest_PostDelayedTask_SharedTimer_SubPump(); | |
1686 } | |
1687 #endif | |
1688 | |
1689 // TODO(darin): MessageLoop does not support deleting all tasks in the | |
1690 // destructor. | |
1691 // Fails, http://crbug.com/50272. | |
1692 TEST(MessageLoopTest, DISABLED_EnsureDeletion) { | |
1693 RunTest_EnsureDeletion(MessageLoop::TYPE_DEFAULT); | |
1694 RunTest_EnsureDeletion(MessageLoop::TYPE_UI); | |
1695 RunTest_EnsureDeletion(MessageLoop::TYPE_IO); | |
1696 } | |
1697 | |
1698 // TODO(darin): MessageLoop does not support deleting all tasks in the | |
1699 // destructor. | |
1700 // Fails, http://crbug.com/50272. | |
1701 TEST(MessageLoopTest, DISABLED_EnsureDeletion_Chain) { | |
1702 RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_DEFAULT); | |
1703 RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_UI); | |
1704 RunTest_EnsureDeletion_Chain(MessageLoop::TYPE_IO); | |
1705 } | |
1706 | |
1707 #if defined(OS_WIN) | |
1708 TEST(MessageLoopTest, Crasher) { | |
1709 RunTest_Crasher(MessageLoop::TYPE_DEFAULT); | |
1710 RunTest_Crasher(MessageLoop::TYPE_UI); | |
1711 RunTest_Crasher(MessageLoop::TYPE_IO); | |
1712 } | |
1713 | |
1714 TEST(MessageLoopTest, CrasherNasty) { | |
1715 RunTest_CrasherNasty(MessageLoop::TYPE_DEFAULT); | |
1716 RunTest_CrasherNasty(MessageLoop::TYPE_UI); | |
1717 RunTest_CrasherNasty(MessageLoop::TYPE_IO); | |
1718 } | |
1719 #endif // defined(OS_WIN) | |
1720 | |
1721 TEST(MessageLoopTest, Nesting) { | |
1722 RunTest_Nesting(MessageLoop::TYPE_DEFAULT); | |
1723 RunTest_Nesting(MessageLoop::TYPE_UI); | |
1724 RunTest_Nesting(MessageLoop::TYPE_IO); | |
1725 } | |
1726 | |
1727 TEST(MessageLoopTest, RecursiveDenial1) { | |
1728 RunTest_RecursiveDenial1(MessageLoop::TYPE_DEFAULT); | |
1729 RunTest_RecursiveDenial1(MessageLoop::TYPE_UI); | |
1730 RunTest_RecursiveDenial1(MessageLoop::TYPE_IO); | |
1731 } | |
1732 | |
1733 TEST(MessageLoopTest, RecursiveDenial3) { | |
1734 RunTest_RecursiveDenial3(MessageLoop::TYPE_DEFAULT); | |
1735 RunTest_RecursiveDenial3(MessageLoop::TYPE_UI); | |
1736 RunTest_RecursiveDenial3(MessageLoop::TYPE_IO); | |
1737 } | |
1738 | |
1739 TEST(MessageLoopTest, RecursiveSupport1) { | |
1740 RunTest_RecursiveSupport1(MessageLoop::TYPE_DEFAULT); | |
1741 RunTest_RecursiveSupport1(MessageLoop::TYPE_UI); | |
1742 RunTest_RecursiveSupport1(MessageLoop::TYPE_IO); | |
1743 } | |
1744 | |
1745 #if defined(OS_WIN) | |
1746 // This test occasionally hangs http://crbug.com/44567 | |
1747 TEST(MessageLoopTest, DISABLED_RecursiveDenial2) { | |
1748 RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT); | |
1749 RunTest_RecursiveDenial2(MessageLoop::TYPE_UI); | |
1750 RunTest_RecursiveDenial2(MessageLoop::TYPE_IO); | |
1751 } | |
1752 | |
1753 TEST(MessageLoopTest, RecursiveSupport2) { | |
1754 // This test requires a UI loop | |
1755 RunTest_RecursiveSupport2(MessageLoop::TYPE_UI); | |
1756 } | |
1757 #endif // defined(OS_WIN) | |
1758 | |
1759 TEST(MessageLoopTest, NonNestableWithNoNesting) { | |
1760 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_DEFAULT); | |
1761 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_UI); | |
1762 RunTest_NonNestableWithNoNesting(MessageLoop::TYPE_IO); | |
1763 } | |
1764 | |
1765 TEST(MessageLoopTest, NonNestableInNestedLoop) { | |
1766 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, false); | |
1767 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, false); | |
1768 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, false); | |
1769 } | |
1770 | |
1771 TEST(MessageLoopTest, NonNestableDelayedInNestedLoop) { | |
1772 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_DEFAULT, true); | |
1773 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_UI, true); | |
1774 RunTest_NonNestableInNestedLoop(MessageLoop::TYPE_IO, true); | |
1775 } | |
1776 | |
1777 TEST(MessageLoopTest, QuitNow) { | |
1778 RunTest_QuitNow(MessageLoop::TYPE_DEFAULT); | |
1779 RunTest_QuitNow(MessageLoop::TYPE_UI); | |
1780 RunTest_QuitNow(MessageLoop::TYPE_IO); | |
1781 } | |
1782 | |
1783 TEST(MessageLoopTest, RunLoopQuitTop) { | |
1784 RunTest_RunLoopQuitTop(MessageLoop::TYPE_DEFAULT); | |
1785 RunTest_RunLoopQuitTop(MessageLoop::TYPE_UI); | |
1786 RunTest_RunLoopQuitTop(MessageLoop::TYPE_IO); | |
1787 } | |
1788 | |
1789 TEST(MessageLoopTest, RunLoopQuitNested) { | |
1790 RunTest_RunLoopQuitNested(MessageLoop::TYPE_DEFAULT); | |
1791 RunTest_RunLoopQuitNested(MessageLoop::TYPE_UI); | |
1792 RunTest_RunLoopQuitNested(MessageLoop::TYPE_IO); | |
1793 } | |
1794 | |
1795 TEST(MessageLoopTest, RunLoopQuitBogus) { | |
1796 RunTest_RunLoopQuitBogus(MessageLoop::TYPE_DEFAULT); | |
1797 RunTest_RunLoopQuitBogus(MessageLoop::TYPE_UI); | |
1798 RunTest_RunLoopQuitBogus(MessageLoop::TYPE_IO); | |
1799 } | |
1800 | |
1801 TEST(MessageLoopTest, RunLoopQuitDeep) { | |
1802 RunTest_RunLoopQuitDeep(MessageLoop::TYPE_DEFAULT); | |
1803 RunTest_RunLoopQuitDeep(MessageLoop::TYPE_UI); | |
1804 RunTest_RunLoopQuitDeep(MessageLoop::TYPE_IO); | |
1805 } | |
1806 | |
1807 TEST(MessageLoopTest, RunLoopQuitOrderBefore) { | |
1808 RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_DEFAULT); | |
1809 RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_UI); | |
1810 RunTest_RunLoopQuitOrderBefore(MessageLoop::TYPE_IO); | |
1811 } | |
1812 | |
1813 TEST(MessageLoopTest, RunLoopQuitOrderDuring) { | |
1814 RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_DEFAULT); | |
1815 RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_UI); | |
1816 RunTest_RunLoopQuitOrderDuring(MessageLoop::TYPE_IO); | |
1817 } | |
1818 | |
1819 TEST(MessageLoopTest, RunLoopQuitOrderAfter) { | |
1820 RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_DEFAULT); | |
1821 RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_UI); | |
1822 RunTest_RunLoopQuitOrderAfter(MessageLoop::TYPE_IO); | |
1823 } | |
1824 | |
1825 class DummyTaskObserver : public MessageLoop::TaskObserver { | |
1826 public: | |
1827 explicit DummyTaskObserver(int num_tasks) | |
1828 : num_tasks_started_(0), | |
1829 num_tasks_processed_(0), | |
1830 num_tasks_(num_tasks) {} | |
1831 | |
1832 virtual ~DummyTaskObserver() {} | |
1833 | |
1834 virtual void WillProcessTask(const PendingTask& pending_task) OVERRIDE { | |
1835 num_tasks_started_++; | |
1836 EXPECT_TRUE(pending_task.time_posted != TimeTicks()); | |
1837 EXPECT_LE(num_tasks_started_, num_tasks_); | |
1838 EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1); | |
1839 } | |
1840 | |
1841 virtual void DidProcessTask(const PendingTask& pending_task) OVERRIDE { | |
1842 num_tasks_processed_++; | |
1843 EXPECT_TRUE(pending_task.time_posted != TimeTicks()); | |
1844 EXPECT_LE(num_tasks_started_, num_tasks_); | |
1845 EXPECT_EQ(num_tasks_started_, num_tasks_processed_); | |
1846 } | |
1847 | |
1848 int num_tasks_started() const { return num_tasks_started_; } | |
1849 int num_tasks_processed() const { return num_tasks_processed_; } | |
1850 | |
1851 private: | |
1852 int num_tasks_started_; | |
1853 int num_tasks_processed_; | |
1854 const int num_tasks_; | |
1855 | |
1856 DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver); | |
1857 }; | |
1858 | |
1859 TEST(MessageLoopTest, TaskObserver) { | |
1860 const int kNumPosts = 6; | |
1861 DummyTaskObserver observer(kNumPosts); | |
1862 | |
1863 MessageLoop loop; | |
1864 loop.AddTaskObserver(&observer); | |
1865 loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumPosts)); | |
1866 loop.Run(); | |
1867 loop.RemoveTaskObserver(&observer); | |
1868 | |
1869 EXPECT_EQ(kNumPosts, observer.num_tasks_started()); | |
1870 EXPECT_EQ(kNumPosts, observer.num_tasks_processed()); | |
1871 } | |
1872 | |
1873 #if defined(OS_WIN) | |
1874 TEST(MessageLoopTest, Dispatcher) { | |
1875 // This test requires a UI loop | |
1876 RunTest_Dispatcher(MessageLoop::TYPE_UI); | |
1877 } | |
1878 | |
1879 TEST(MessageLoopTest, DispatcherWithMessageHook) { | |
1880 // This test requires a UI loop | |
1881 RunTest_DispatcherWithMessageHook(MessageLoop::TYPE_UI); | |
1882 } | |
1883 | |
1884 TEST(MessageLoopTest, IOHandler) { | |
1885 RunTest_IOHandler(); | |
1886 } | |
1887 | |
1888 TEST(MessageLoopTest, WaitForIO) { | |
1889 RunTest_WaitForIO(); | |
1890 } | |
1891 | |
1892 TEST(MessageLoopTest, HighResolutionTimer) { | |
1893 MessageLoop loop; | |
1894 | |
1895 const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5); | |
1896 const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100); | |
1897 | |
1898 EXPECT_FALSE(loop.high_resolution_timers_enabled()); | |
1899 | |
1900 // Post a fast task to enable the high resolution timers. | |
1901 loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), | |
1902 kFastTimer); | |
1903 loop.Run(); | |
1904 EXPECT_TRUE(loop.high_resolution_timers_enabled()); | |
1905 | |
1906 // Post a slow task and verify high resolution timers | |
1907 // are still enabled. | |
1908 loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), | |
1909 kSlowTimer); | |
1910 loop.Run(); | |
1911 EXPECT_TRUE(loop.high_resolution_timers_enabled()); | |
1912 | |
1913 // Wait for a while so that high-resolution mode elapses. | |
1914 PlatformThread::Sleep(TimeDelta::FromMilliseconds( | |
1915 MessageLoop::kHighResolutionTimerModeLeaseTimeMs)); | |
1916 | |
1917 // Post a slow task to disable the high resolution timers. | |
1918 loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), | |
1919 kSlowTimer); | |
1920 loop.Run(); | |
1921 EXPECT_FALSE(loop.high_resolution_timers_enabled()); | |
1922 } | |
1923 | |
1924 #endif // defined(OS_WIN) | |
1925 | |
1926 #if defined(OS_POSIX) && !defined(OS_NACL) | |
1927 | |
1928 namespace { | |
1929 | |
1930 class QuitDelegate : public MessageLoopForIO::Watcher { | |
1931 public: | |
1932 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE { | |
1933 MessageLoop::current()->QuitWhenIdle(); | |
1934 } | |
1935 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE { | |
1936 MessageLoop::current()->QuitWhenIdle(); | |
1937 } | |
1938 }; | |
1939 | |
1940 TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) { | |
1941 // Simulate a MessageLoop that dies before an FileDescriptorWatcher. | |
1942 // This could happen when people use the Singleton pattern or atexit. | |
1943 | |
1944 // Create a file descriptor. Doesn't need to be readable or writable, | |
1945 // as we don't need to actually get any notifications. | |
1946 // pipe() is just the easiest way to do it. | |
1947 int pipefds[2]; | |
1948 int err = pipe(pipefds); | |
1949 ASSERT_EQ(0, err); | |
1950 int fd = pipefds[1]; | |
1951 { | |
1952 // Arrange for controller to live longer than message loop. | |
1953 MessageLoopForIO::FileDescriptorWatcher controller; | |
1954 { | |
1955 MessageLoopForIO message_loop; | |
1956 | |
1957 QuitDelegate delegate; | |
1958 message_loop.WatchFileDescriptor(fd, | |
1959 true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate); | |
1960 // and don't run the message loop, just destroy it. | |
1961 } | |
1962 } | |
1963 if (HANDLE_EINTR(close(pipefds[0])) < 0) | |
1964 PLOG(ERROR) << "close"; | |
1965 if (HANDLE_EINTR(close(pipefds[1])) < 0) | |
1966 PLOG(ERROR) << "close"; | |
1967 } | |
1968 | |
1969 TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) { | |
1970 // Verify that it's ok to call StopWatchingFileDescriptor(). | |
1971 // (Errors only showed up in valgrind.) | |
1972 int pipefds[2]; | |
1973 int err = pipe(pipefds); | |
1974 ASSERT_EQ(0, err); | |
1975 int fd = pipefds[1]; | |
1976 { | |
1977 // Arrange for message loop to live longer than controller. | |
1978 MessageLoopForIO message_loop; | |
1979 { | |
1980 MessageLoopForIO::FileDescriptorWatcher controller; | |
1981 | |
1982 QuitDelegate delegate; | |
1983 message_loop.WatchFileDescriptor(fd, | |
1984 true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate); | |
1985 controller.StopWatchingFileDescriptor(); | |
1986 } | |
1987 } | |
1988 if (HANDLE_EINTR(close(pipefds[0])) < 0) | |
1989 PLOG(ERROR) << "close"; | |
1990 if (HANDLE_EINTR(close(pipefds[1])) < 0) | |
1991 PLOG(ERROR) << "close"; | |
1992 } | |
1993 | |
1994 } // namespace | |
1995 | |
1996 #endif // defined(OS_POSIX) && !defined(OS_NACL) | |
1997 | |
1998 namespace { | |
1999 // Inject a test point for recording the destructor calls for Closure objects | |
2000 // send to MessageLoop::PostTask(). It is awkward usage since we are trying to | |
2001 // hook the actual destruction, which is not a common operation. | |
2002 class DestructionObserverProbe : | |
2003 public RefCounted<DestructionObserverProbe> { | |
2004 public: | |
2005 DestructionObserverProbe(bool* task_destroyed, | |
2006 bool* destruction_observer_called) | |
2007 : task_destroyed_(task_destroyed), | |
2008 destruction_observer_called_(destruction_observer_called) { | |
2009 } | |
2010 virtual void Run() { | |
2011 // This task should never run. | |
2012 ADD_FAILURE(); | |
2013 } | |
2014 private: | |
2015 friend class RefCounted<DestructionObserverProbe>; | |
2016 | |
2017 virtual ~DestructionObserverProbe() { | |
2018 EXPECT_FALSE(*destruction_observer_called_); | |
2019 *task_destroyed_ = true; | |
2020 } | |
2021 | |
2022 bool* task_destroyed_; | |
2023 bool* destruction_observer_called_; | |
2024 }; | |
2025 | |
2026 class MLDestructionObserver : public MessageLoop::DestructionObserver { | |
2027 public: | |
2028 MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called) | |
2029 : task_destroyed_(task_destroyed), | |
2030 destruction_observer_called_(destruction_observer_called), | |
2031 task_destroyed_before_message_loop_(false) { | |
2032 } | |
2033 virtual void WillDestroyCurrentMessageLoop() OVERRIDE { | |
2034 task_destroyed_before_message_loop_ = *task_destroyed_; | |
2035 *destruction_observer_called_ = true; | |
2036 } | |
2037 bool task_destroyed_before_message_loop() const { | |
2038 return task_destroyed_before_message_loop_; | |
2039 } | |
2040 private: | |
2041 bool* task_destroyed_; | |
2042 bool* destruction_observer_called_; | |
2043 bool task_destroyed_before_message_loop_; | |
2044 }; | |
2045 | |
2046 } // namespace | |
2047 | |
2048 TEST(MessageLoopTest, DestructionObserverTest) { | |
2049 // Verify that the destruction observer gets called at the very end (after | |
2050 // all the pending tasks have been destroyed). | |
2051 MessageLoop* loop = new MessageLoop; | |
2052 const TimeDelta kDelay = TimeDelta::FromMilliseconds(100); | |
2053 | |
2054 bool task_destroyed = false; | |
2055 bool destruction_observer_called = false; | |
2056 | |
2057 MLDestructionObserver observer(&task_destroyed, &destruction_observer_called); | |
2058 loop->AddDestructionObserver(&observer); | |
2059 loop->PostDelayedTask( | |
2060 FROM_HERE, | |
2061 Bind(&DestructionObserverProbe::Run, | |
2062 new DestructionObserverProbe(&task_destroyed, | |
2063 &destruction_observer_called)), | |
2064 kDelay); | |
2065 delete loop; | |
2066 EXPECT_TRUE(observer.task_destroyed_before_message_loop()); | |
2067 // The task should have been destroyed when we deleted the loop. | |
2068 EXPECT_TRUE(task_destroyed); | |
2069 EXPECT_TRUE(destruction_observer_called); | |
2070 } | |
2071 | |
2072 | |
2073 // Verify that MessageLoop sets ThreadMainTaskRunner::current() and it | |
2074 // posts tasks on that message loop. | |
2075 TEST(MessageLoopTest, ThreadMainTaskRunner) { | |
2076 MessageLoop loop; | |
2077 | |
2078 scoped_refptr<Foo> foo(new Foo()); | |
2079 std::string a("a"); | |
2080 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind( | |
2081 &Foo::Test1ConstRef, foo.get(), a)); | |
2082 | |
2083 // Post quit task; | |
2084 MessageLoop::current()->PostTask(FROM_HERE, Bind( | |
2085 &MessageLoop::Quit, Unretained(MessageLoop::current()))); | |
2086 | |
2087 // Now kick things off | |
2088 MessageLoop::current()->Run(); | |
2089 | |
2090 EXPECT_EQ(foo->test_count(), 1); | |
2091 EXPECT_EQ(foo->result(), "a"); | |
2092 } | |
2093 | |
2094 TEST(MessageLoopTest, IsType) { | |
2095 MessageLoop loop(MessageLoop::TYPE_UI); | |
2096 EXPECT_TRUE(loop.IsType(MessageLoop::TYPE_UI)); | |
2097 EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_IO)); | |
2098 EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_DEFAULT)); | |
2099 } | |
2100 | |
2101 TEST(MessageLoopTest, RecursivePosts) { | |
2102 // There was a bug in the MessagePumpGLib where posting tasks recursively | |
2103 // caused the message loop to hang, due to the buffer of the internal pipe | |
2104 // becoming full. Test all MessageLoop types to ensure this issue does not | |
2105 // exist in other MessagePumps. | |
2106 | |
2107 // On Linux, the pipe buffer size is 64KiB by default. The bug caused one | |
2108 // byte accumulated in the pipe per two posts, so we should repeat 128K | |
2109 // times to reproduce the bug. | |
2110 const int kNumTimes = 1 << 17; | |
2111 RunTest_RecursivePosts(MessageLoop::TYPE_DEFAULT, kNumTimes); | |
2112 RunTest_RecursivePosts(MessageLoop::TYPE_UI, kNumTimes); | |
2113 RunTest_RecursivePosts(MessageLoop::TYPE_IO, kNumTimes); | |
2114 } | |
2115 | |
2116 } // namespace base | |
OLD | NEW |