| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/message_loop/message_pump_glib.h" | 5 #include "base/message_loop/message_pump_glib.h" |
| 6 | 6 |
| 7 #include <glib.h> | 7 #include <glib.h> |
| 8 #include <math.h> | 8 #include <math.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| 11 #include <vector> | 11 #include <vector> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/bind_helpers.h" | 14 #include "base/bind_helpers.h" |
| 15 #include "base/callback.h" | 15 #include "base/callback.h" |
| 16 #include "base/macros.h" | 16 #include "base/macros.h" |
| 17 #include "base/memory/ref_counted.h" | 17 #include "base/memory/ref_counted.h" |
| 18 #include "base/message_loop/message_loop.h" | 18 #include "base/message_loop/message_loop.h" |
| 19 #include "base/run_loop.h" | 19 #include "base/run_loop.h" |
| 20 #include "base/single_thread_task_runner.h" |
| 20 #include "base/threading/thread.h" | 21 #include "base/threading/thread.h" |
| 21 #include "base/threading/thread_task_runner_handle.h" | 22 #include "base/threading/thread_task_runner_handle.h" |
| 22 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
| 23 | 24 |
| 24 namespace base { | 25 namespace base { |
| 25 namespace { | 26 namespace { |
| 26 | 27 |
| 27 // This class injects dummy "events" into the GLib loop. When "handled" these | 28 // This class injects dummy "events" into the GLib loop. When "handled" these |
| 28 // events can run tasks. This is intended to mock gtk events (the corresponding | 29 // events can run tasks. This is intended to mock gtk events (the corresponding |
| 29 // GLib source runs at the same priority). | 30 // GLib source runs at the same priority). |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 TEST_F(MessagePumpGLibTest, TestQuit) { | 189 TEST_F(MessagePumpGLibTest, TestQuit) { |
| 189 // Checks that Quit works and that the basic infrastructure is working. | 190 // Checks that Quit works and that the basic infrastructure is working. |
| 190 | 191 |
| 191 // Quit from a task | 192 // Quit from a task |
| 192 RunLoop().RunUntilIdle(); | 193 RunLoop().RunUntilIdle(); |
| 193 EXPECT_EQ(0, injector()->processed_events()); | 194 EXPECT_EQ(0, injector()->processed_events()); |
| 194 | 195 |
| 195 injector()->Reset(); | 196 injector()->Reset(); |
| 196 // Quit from an event | 197 // Quit from an event |
| 197 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); | 198 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); |
| 198 loop()->Run(); | 199 RunLoop().Run(); |
| 199 EXPECT_EQ(1, injector()->processed_events()); | 200 EXPECT_EQ(1, injector()->processed_events()); |
| 200 } | 201 } |
| 201 | 202 |
| 202 TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) { | 203 TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) { |
| 203 // Checks that tasks posted by events are executed before the next event if | 204 // Checks that tasks posted by events are executed before the next event if |
| 204 // the posted task queue is empty. | 205 // the posted task queue is empty. |
| 205 // MessageLoop doesn't make strong guarantees that it is the case, but the | 206 // MessageLoop doesn't make strong guarantees that it is the case, but the |
| 206 // current implementation ensures it and the tests below rely on it. | 207 // current implementation ensures it and the tests below rely on it. |
| 207 // If changes cause this test to fail, it is reasonable to change it, but | 208 // If changes cause this test to fail, it is reasonable to change it, but |
| 208 // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be | 209 // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be |
| 209 // changed accordingly, otherwise they can become flaky. | 210 // changed accordingly, otherwise they can become flaky. |
| 210 injector()->AddEventAsTask(0, Bind(&DoNothing)); | 211 injector()->AddEventAsTask(0, Bind(&DoNothing)); |
| 211 Closure check_task = | 212 Closure check_task = |
| 212 Bind(&ExpectProcessedEvents, Unretained(injector()), 2); | 213 Bind(&ExpectProcessedEvents, Unretained(injector()), 2); |
| 213 Closure posted_task = | 214 Closure posted_task = |
| 214 Bind(&PostMessageLoopTask, FROM_HERE, check_task); | 215 Bind(&PostMessageLoopTask, FROM_HERE, check_task); |
| 215 injector()->AddEventAsTask(0, posted_task); | 216 injector()->AddEventAsTask(0, posted_task); |
| 216 injector()->AddEventAsTask(0, Bind(&DoNothing)); | 217 injector()->AddEventAsTask(0, Bind(&DoNothing)); |
| 217 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); | 218 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); |
| 218 loop()->Run(); | 219 RunLoop().Run(); |
| 219 EXPECT_EQ(4, injector()->processed_events()); | 220 EXPECT_EQ(4, injector()->processed_events()); |
| 220 | 221 |
| 221 injector()->Reset(); | 222 injector()->Reset(); |
| 222 injector()->AddEventAsTask(0, Bind(&DoNothing)); | 223 injector()->AddEventAsTask(0, Bind(&DoNothing)); |
| 223 check_task = | 224 check_task = |
| 224 Bind(&ExpectProcessedEvents, Unretained(injector()), 2); | 225 Bind(&ExpectProcessedEvents, Unretained(injector()), 2); |
| 225 posted_task = Bind(&PostMessageLoopTask, FROM_HERE, check_task); | 226 posted_task = Bind(&PostMessageLoopTask, FROM_HERE, check_task); |
| 226 injector()->AddEventAsTask(0, posted_task); | 227 injector()->AddEventAsTask(0, posted_task); |
| 227 injector()->AddEventAsTask(10, Bind(&DoNothing)); | 228 injector()->AddEventAsTask(10, Bind(&DoNothing)); |
| 228 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); | 229 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); |
| 229 loop()->Run(); | 230 RunLoop().Run(); |
| 230 EXPECT_EQ(4, injector()->processed_events()); | 231 EXPECT_EQ(4, injector()->processed_events()); |
| 231 } | 232 } |
| 232 | 233 |
| 233 TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) { | 234 TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) { |
| 234 int task_count = 0; | 235 int task_count = 0; |
| 235 // Tests that we process tasks while waiting for new events. | 236 // Tests that we process tasks while waiting for new events. |
| 236 // The event queue is empty at first. | 237 // The event queue is empty at first. |
| 237 for (int i = 0; i < 10; ++i) { | 238 for (int i = 0; i < 10; ++i) { |
| 238 loop()->PostTask(FROM_HERE, Bind(&IncrementInt, &task_count)); | 239 loop()->task_runner()->PostTask(FROM_HERE, |
| 240 Bind(&IncrementInt, &task_count)); |
| 239 } | 241 } |
| 240 // After all the previous tasks have executed, enqueue an event that will | 242 // After all the previous tasks have executed, enqueue an event that will |
| 241 // quit. | 243 // quit. |
| 242 loop()->PostTask( | 244 loop()->task_runner()->PostTask( |
| 243 FROM_HERE, | 245 FROM_HERE, Bind(&EventInjector::AddEvent, Unretained(injector()), 0, |
| 244 Bind(&EventInjector::AddEvent, Unretained(injector()), 0, | 246 MessageLoop::QuitWhenIdleClosure())); |
| 245 MessageLoop::QuitWhenIdleClosure())); | 247 RunLoop().Run(); |
| 246 loop()->Run(); | |
| 247 ASSERT_EQ(10, task_count); | 248 ASSERT_EQ(10, task_count); |
| 248 EXPECT_EQ(1, injector()->processed_events()); | 249 EXPECT_EQ(1, injector()->processed_events()); |
| 249 | 250 |
| 250 // Tests that we process delayed tasks while waiting for new events. | 251 // Tests that we process delayed tasks while waiting for new events. |
| 251 injector()->Reset(); | 252 injector()->Reset(); |
| 252 task_count = 0; | 253 task_count = 0; |
| 253 for (int i = 0; i < 10; ++i) { | 254 for (int i = 0; i < 10; ++i) { |
| 254 loop()->PostDelayedTask( | 255 loop()->task_runner()->PostDelayedTask(FROM_HERE, |
| 255 FROM_HERE, | 256 Bind(&IncrementInt, &task_count), |
| 256 Bind(&IncrementInt, &task_count), | 257 TimeDelta::FromMilliseconds(10 * i)); |
| 257 TimeDelta::FromMilliseconds(10*i)); | |
| 258 } | 258 } |
| 259 // After all the previous tasks have executed, enqueue an event that will | 259 // After all the previous tasks have executed, enqueue an event that will |
| 260 // quit. | 260 // quit. |
| 261 // This relies on the fact that delayed tasks are executed in delay order. | 261 // This relies on the fact that delayed tasks are executed in delay order. |
| 262 // That is verified in message_loop_unittest.cc. | 262 // That is verified in message_loop_unittest.cc. |
| 263 loop()->PostDelayedTask( | 263 loop()->task_runner()->PostDelayedTask( |
| 264 FROM_HERE, | 264 FROM_HERE, Bind(&EventInjector::AddEvent, Unretained(injector()), 10, |
| 265 Bind(&EventInjector::AddEvent, Unretained(injector()), 10, | 265 MessageLoop::QuitWhenIdleClosure()), |
| 266 MessageLoop::QuitWhenIdleClosure()), | |
| 267 TimeDelta::FromMilliseconds(150)); | 266 TimeDelta::FromMilliseconds(150)); |
| 268 loop()->Run(); | 267 RunLoop().Run(); |
| 269 ASSERT_EQ(10, task_count); | 268 ASSERT_EQ(10, task_count); |
| 270 EXPECT_EQ(1, injector()->processed_events()); | 269 EXPECT_EQ(1, injector()->processed_events()); |
| 271 } | 270 } |
| 272 | 271 |
| 273 TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) { | 272 TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) { |
| 274 // Tests that we process events while waiting for work. | 273 // Tests that we process events while waiting for work. |
| 275 // The event queue is empty at first. | 274 // The event queue is empty at first. |
| 276 for (int i = 0; i < 10; ++i) { | 275 for (int i = 0; i < 10; ++i) { |
| 277 injector()->AddDummyEvent(0); | 276 injector()->AddDummyEvent(0); |
| 278 } | 277 } |
| 279 // After all the events have been processed, post a task that will check that | 278 // After all the events have been processed, post a task that will check that |
| 280 // the events have been processed (note: the task executes after the event | 279 // the events have been processed (note: the task executes after the event |
| 281 // that posted it has been handled, so we expect 11 at that point). | 280 // that posted it has been handled, so we expect 11 at that point). |
| 282 Closure check_task = | 281 Closure check_task = |
| 283 Bind(&ExpectProcessedEvents, Unretained(injector()), 11); | 282 Bind(&ExpectProcessedEvents, Unretained(injector()), 11); |
| 284 Closure posted_task = | 283 Closure posted_task = |
| 285 Bind(&PostMessageLoopTask, FROM_HERE, check_task); | 284 Bind(&PostMessageLoopTask, FROM_HERE, check_task); |
| 286 injector()->AddEventAsTask(10, posted_task); | 285 injector()->AddEventAsTask(10, posted_task); |
| 287 | 286 |
| 288 // And then quit (relies on the condition tested by TestEventTaskInterleave). | 287 // And then quit (relies on the condition tested by TestEventTaskInterleave). |
| 289 injector()->AddEvent(10, MessageLoop::QuitWhenIdleClosure()); | 288 injector()->AddEvent(10, MessageLoop::QuitWhenIdleClosure()); |
| 290 loop()->Run(); | 289 RunLoop().Run(); |
| 291 | 290 |
| 292 EXPECT_EQ(12, injector()->processed_events()); | 291 EXPECT_EQ(12, injector()->processed_events()); |
| 293 } | 292 } |
| 294 | 293 |
| 295 namespace { | 294 namespace { |
| 296 | 295 |
| 297 // This class is a helper for the concurrent events / posted tasks test below. | 296 // This class is a helper for the concurrent events / posted tasks test below. |
| 298 // It will quit the main loop once enough tasks and events have been processed, | 297 // It will quit the main loop once enough tasks and events have been processed, |
| 299 // while making sure there is always work to do and events in the queue. | 298 // while making sure there is always work to do and events in the queue. |
| 300 class ConcurrentHelper : public RefCounted<ConcurrentHelper> { | 299 class ConcurrentHelper : public RefCounted<ConcurrentHelper> { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 scoped_refptr<ConcurrentHelper> helper = new ConcurrentHelper(injector()); | 355 scoped_refptr<ConcurrentHelper> helper = new ConcurrentHelper(injector()); |
| 357 | 356 |
| 358 // Add 2 events to the queue to make sure it is always full (when we remove | 357 // Add 2 events to the queue to make sure it is always full (when we remove |
| 359 // the event before processing it). | 358 // the event before processing it). |
| 360 injector()->AddEventAsTask( | 359 injector()->AddEventAsTask( |
| 361 0, Bind(&ConcurrentHelper::FromEvent, helper.get())); | 360 0, Bind(&ConcurrentHelper::FromEvent, helper.get())); |
| 362 injector()->AddEventAsTask( | 361 injector()->AddEventAsTask( |
| 363 0, Bind(&ConcurrentHelper::FromEvent, helper.get())); | 362 0, Bind(&ConcurrentHelper::FromEvent, helper.get())); |
| 364 | 363 |
| 365 // Similarly post 2 tasks. | 364 // Similarly post 2 tasks. |
| 366 loop()->PostTask( | 365 loop()->task_runner()->PostTask( |
| 367 FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get())); | 366 FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get())); |
| 368 loop()->PostTask( | 367 loop()->task_runner()->PostTask( |
| 369 FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get())); | 368 FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get())); |
| 370 | 369 |
| 371 loop()->Run(); | 370 RunLoop().Run(); |
| 372 EXPECT_EQ(0, helper->event_count()); | 371 EXPECT_EQ(0, helper->event_count()); |
| 373 EXPECT_EQ(0, helper->task_count()); | 372 EXPECT_EQ(0, helper->task_count()); |
| 374 } | 373 } |
| 375 | 374 |
| 376 namespace { | 375 namespace { |
| 377 | 376 |
| 378 void AddEventsAndDrainGLib(EventInjector* injector) { | 377 void AddEventsAndDrainGLib(EventInjector* injector) { |
| 379 // Add a couple of dummy events | 378 // Add a couple of dummy events |
| 380 injector->AddDummyEvent(0); | 379 injector->AddDummyEvent(0); |
| 381 injector->AddDummyEvent(0); | 380 injector->AddDummyEvent(0); |
| 382 // Then add an event that will quit the main loop. | 381 // Then add an event that will quit the main loop. |
| 383 injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); | 382 injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); |
| 384 | 383 |
| 385 // Post a couple of dummy tasks | 384 // Post a couple of dummy tasks |
| 386 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(&DoNothing)); | 385 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(&DoNothing)); |
| 387 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(&DoNothing)); | 386 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(&DoNothing)); |
| 388 | 387 |
| 389 // Drain the events | 388 // Drain the events |
| 390 while (g_main_context_pending(NULL)) { | 389 while (g_main_context_pending(NULL)) { |
| 391 g_main_context_iteration(NULL, FALSE); | 390 g_main_context_iteration(NULL, FALSE); |
| 392 } | 391 } |
| 393 } | 392 } |
| 394 | 393 |
| 395 } // namespace | 394 } // namespace |
| 396 | 395 |
| 397 TEST_F(MessagePumpGLibTest, TestDrainingGLib) { | 396 TEST_F(MessagePumpGLibTest, TestDrainingGLib) { |
| 398 // Tests that draining events using GLib works. | 397 // Tests that draining events using GLib works. |
| 399 loop()->PostTask( | 398 loop()->task_runner()->PostTask( |
| 400 FROM_HERE, | 399 FROM_HERE, Bind(&AddEventsAndDrainGLib, Unretained(injector()))); |
| 401 Bind(&AddEventsAndDrainGLib, Unretained(injector()))); | 400 RunLoop().Run(); |
| 402 loop()->Run(); | |
| 403 | 401 |
| 404 EXPECT_EQ(3, injector()->processed_events()); | 402 EXPECT_EQ(3, injector()->processed_events()); |
| 405 } | 403 } |
| 406 | 404 |
| 407 namespace { | 405 namespace { |
| 408 | 406 |
| 409 // Helper class that lets us run the GLib message loop. | 407 // Helper class that lets us run the GLib message loop. |
| 410 class GLibLoopRunner : public RefCounted<GLibLoopRunner> { | 408 class GLibLoopRunner : public RefCounted<GLibLoopRunner> { |
| 411 public: | 409 public: |
| 412 GLibLoopRunner() : quit_(false) { } | 410 GLibLoopRunner() : quit_(false) { } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 505 MessageLoop::current()->QuitWhenIdle(); | 503 MessageLoop::current()->QuitWhenIdle(); |
| 506 } | 504 } |
| 507 | 505 |
| 508 } // namespace | 506 } // namespace |
| 509 | 507 |
| 510 TEST_F(MessagePumpGLibTest, TestGLibLoop) { | 508 TEST_F(MessagePumpGLibTest, TestGLibLoop) { |
| 511 // Tests that events and posted tasks are correctly executed if the message | 509 // Tests that events and posted tasks are correctly executed if the message |
| 512 // loop is not run by MessageLoop::Run() but by a straight GLib loop. | 510 // loop is not run by MessageLoop::Run() but by a straight GLib loop. |
| 513 // Note that in this case we don't make strong guarantees about niceness | 511 // Note that in this case we don't make strong guarantees about niceness |
| 514 // between events and posted tasks. | 512 // between events and posted tasks. |
| 515 loop()->PostTask( | 513 loop()->task_runner()->PostTask( |
| 516 FROM_HERE, | 514 FROM_HERE, Bind(&TestGLibLoopInternal, Unretained(injector()))); |
| 517 Bind(&TestGLibLoopInternal, Unretained(injector()))); | 515 RunLoop().Run(); |
| 518 loop()->Run(); | |
| 519 } | 516 } |
| 520 | 517 |
| 521 TEST_F(MessagePumpGLibTest, TestGtkLoop) { | 518 TEST_F(MessagePumpGLibTest, TestGtkLoop) { |
| 522 // Tests that events and posted tasks are correctly executed if the message | 519 // Tests that events and posted tasks are correctly executed if the message |
| 523 // loop is not run by MessageLoop::Run() but by a straight Gtk loop. | 520 // loop is not run by MessageLoop::Run() but by a straight Gtk loop. |
| 524 // Note that in this case we don't make strong guarantees about niceness | 521 // Note that in this case we don't make strong guarantees about niceness |
| 525 // between events and posted tasks. | 522 // between events and posted tasks. |
| 526 loop()->PostTask( | 523 loop()->task_runner()->PostTask( |
| 527 FROM_HERE, | 524 FROM_HERE, Bind(&TestGtkLoopInternal, Unretained(injector()))); |
| 528 Bind(&TestGtkLoopInternal, Unretained(injector()))); | 525 RunLoop().Run(); |
| 529 loop()->Run(); | |
| 530 } | 526 } |
| 531 | 527 |
| 532 } // namespace base | 528 } // namespace base |
| OLD | NEW |