| 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> |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 | 52 |
| 53 bool HandleCheck() { | 53 bool HandleCheck() { |
| 54 if (events_.empty()) | 54 if (events_.empty()) |
| 55 return false; | 55 return false; |
| 56 return events_[0].time <= Time::NowFromSystemTime(); | 56 return events_[0].time <= Time::NowFromSystemTime(); |
| 57 } | 57 } |
| 58 | 58 |
| 59 void HandleDispatch() { | 59 void HandleDispatch() { |
| 60 if (events_.empty()) | 60 if (events_.empty()) |
| 61 return; | 61 return; |
| 62 Event event = events_[0]; | 62 Event event = std::move(events_[0]); |
| 63 events_.erase(events_.begin()); | 63 events_.erase(events_.begin()); |
| 64 ++processed_events_; | 64 ++processed_events_; |
| 65 if (!event.callback.is_null()) | 65 if (!event.callback.is_null()) |
| 66 event.callback.Run(); | 66 std::move(event.callback).Run(); |
| 67 else if (!event.task.is_null()) | 67 else if (!event.task.is_null()) |
| 68 event.task.Run(); | 68 std::move(event.task).Run(); |
| 69 } | 69 } |
| 70 | 70 |
| 71 // Adds an event to the queue. When "handled", executes |callback|. | 71 // Adds an event to the queue. When "handled", executes |callback|. |
| 72 // delay_ms is relative to the last event if any, or to Now() otherwise. | 72 // delay_ms is relative to the last event if any, or to Now() otherwise. |
| 73 void AddEvent(int delay_ms, const Closure& callback) { | 73 void AddEvent(int delay_ms, OnceClosure callback) { |
| 74 AddEventHelper(delay_ms, callback, Closure()); | 74 AddEventHelper(delay_ms, std::move(callback), OnceClosure()); |
| 75 } | 75 } |
| 76 | 76 |
| 77 void AddDummyEvent(int delay_ms) { | 77 void AddDummyEvent(int delay_ms) { |
| 78 AddEventHelper(delay_ms, Closure(), Closure()); | 78 AddEventHelper(delay_ms, OnceClosure(), OnceClosure()); |
| 79 } | 79 } |
| 80 | 80 |
| 81 void AddEventAsTask(int delay_ms, const Closure& task) { | 81 void AddEventAsTask(int delay_ms, OnceClosure task) { |
| 82 AddEventHelper(delay_ms, Closure(), task); | 82 AddEventHelper(delay_ms, OnceClosure(), std::move(task)); |
| 83 } | 83 } |
| 84 | 84 |
| 85 void Reset() { | 85 void Reset() { |
| 86 processed_events_ = 0; | 86 processed_events_ = 0; |
| 87 events_.clear(); | 87 events_.clear(); |
| 88 } | 88 } |
| 89 | 89 |
| 90 int processed_events() const { return processed_events_; } | 90 int processed_events() const { return processed_events_; } |
| 91 | 91 |
| 92 private: | 92 private: |
| 93 struct Event { | 93 struct Event { |
| 94 Time time; | 94 Time time; |
| 95 Closure callback; | 95 OnceClosure callback; |
| 96 Closure task; | 96 OnceClosure task; |
| 97 }; | 97 }; |
| 98 | 98 |
| 99 struct Source : public GSource { | 99 struct Source : public GSource { |
| 100 EventInjector* injector; | 100 EventInjector* injector; |
| 101 }; | 101 }; |
| 102 | 102 |
| 103 void AddEventHelper( | 103 void AddEventHelper(int delay_ms, OnceClosure callback, OnceClosure task) { |
| 104 int delay_ms, const Closure& callback, const Closure& task) { | |
| 105 Time last_time; | 104 Time last_time; |
| 106 if (!events_.empty()) | 105 if (!events_.empty()) |
| 107 last_time = (events_.end()-1)->time; | 106 last_time = (events_.end()-1)->time; |
| 108 else | 107 else |
| 109 last_time = Time::NowFromSystemTime(); | 108 last_time = Time::NowFromSystemTime(); |
| 110 | 109 |
| 111 Time future = last_time + TimeDelta::FromMilliseconds(delay_ms); | 110 Time future = last_time + TimeDelta::FromMilliseconds(delay_ms); |
| 112 EventInjector::Event event = {future, callback, task}; | 111 EventInjector::Event event = {future, std::move(callback), std::move(task)}; |
| 113 events_.push_back(event); | 112 events_.push_back(std::move(event)); |
| 114 } | 113 } |
| 115 | 114 |
| 116 static gboolean Prepare(GSource* source, gint* timeout_ms) { | 115 static gboolean Prepare(GSource* source, gint* timeout_ms) { |
| 117 *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare(); | 116 *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare(); |
| 118 return FALSE; | 117 return FALSE; |
| 119 } | 118 } |
| 120 | 119 |
| 121 static gboolean Check(GSource* source) { | 120 static gboolean Check(GSource* source) { |
| 122 return static_cast<Source*>(source)->injector->HandleCheck(); | 121 return static_cast<Source*>(source)->injector->HandleCheck(); |
| 123 } | 122 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 147 ++*value; | 146 ++*value; |
| 148 } | 147 } |
| 149 | 148 |
| 150 // Checks how many events have been processed by the injector. | 149 // Checks how many events have been processed by the injector. |
| 151 void ExpectProcessedEvents(EventInjector* injector, int count) { | 150 void ExpectProcessedEvents(EventInjector* injector, int count) { |
| 152 EXPECT_EQ(injector->processed_events(), count); | 151 EXPECT_EQ(injector->processed_events(), count); |
| 153 } | 152 } |
| 154 | 153 |
| 155 // Posts a task on the current message loop. | 154 // Posts a task on the current message loop. |
| 156 void PostMessageLoopTask(const tracked_objects::Location& from_here, | 155 void PostMessageLoopTask(const tracked_objects::Location& from_here, |
| 157 const Closure& task) { | 156 OnceClosure task) { |
| 158 ThreadTaskRunnerHandle::Get()->PostTask(from_here, task); | 157 ThreadTaskRunnerHandle::Get()->PostTask(from_here, std::move(task)); |
| 159 } | 158 } |
| 160 | 159 |
| 161 // Test fixture. | 160 // Test fixture. |
| 162 class MessagePumpGLibTest : public testing::Test { | 161 class MessagePumpGLibTest : public testing::Test { |
| 163 public: | 162 public: |
| 164 MessagePumpGLibTest() : loop_(NULL), injector_(NULL) { } | 163 MessagePumpGLibTest() : loop_(NULL), injector_(NULL) { } |
| 165 | 164 |
| 166 // Overridden from testing::Test: | 165 // Overridden from testing::Test: |
| 167 void SetUp() override { | 166 void SetUp() override { |
| 168 loop_ = new MessageLoop(MessageLoop::TYPE_UI); | 167 loop_ = new MessageLoop(MessageLoop::TYPE_UI); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 } | 200 } |
| 202 | 201 |
| 203 TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) { | 202 TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) { |
| 204 // Checks that tasks posted by events are executed before the next event if | 203 // Checks that tasks posted by events are executed before the next event if |
| 205 // the posted task queue is empty. | 204 // the posted task queue is empty. |
| 206 // MessageLoop doesn't make strong guarantees that it is the case, but the | 205 // MessageLoop doesn't make strong guarantees that it is the case, but the |
| 207 // current implementation ensures it and the tests below rely on it. | 206 // current implementation ensures it and the tests below rely on it. |
| 208 // If changes cause this test to fail, it is reasonable to change it, but | 207 // If changes cause this test to fail, it is reasonable to change it, but |
| 209 // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be | 208 // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be |
| 210 // changed accordingly, otherwise they can become flaky. | 209 // changed accordingly, otherwise they can become flaky. |
| 211 injector()->AddEventAsTask(0, Bind(&DoNothing)); | 210 injector()->AddEventAsTask(0, BindOnce(&DoNothing)); |
| 212 Closure check_task = | 211 OnceClosure check_task = |
| 213 Bind(&ExpectProcessedEvents, Unretained(injector()), 2); | 212 BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2); |
| 214 Closure posted_task = | 213 OnceClosure posted_task = |
| 215 Bind(&PostMessageLoopTask, FROM_HERE, check_task); | 214 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task)); |
| 216 injector()->AddEventAsTask(0, posted_task); | 215 injector()->AddEventAsTask(0, std::move(posted_task)); |
| 217 injector()->AddEventAsTask(0, Bind(&DoNothing)); | 216 injector()->AddEventAsTask(0, BindOnce(&DoNothing)); |
| 218 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); | 217 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); |
| 219 RunLoop().Run(); | 218 RunLoop().Run(); |
| 220 EXPECT_EQ(4, injector()->processed_events()); | 219 EXPECT_EQ(4, injector()->processed_events()); |
| 221 | 220 |
| 222 injector()->Reset(); | 221 injector()->Reset(); |
| 223 injector()->AddEventAsTask(0, Bind(&DoNothing)); | 222 injector()->AddEventAsTask(0, BindOnce(&DoNothing)); |
| 224 check_task = | 223 check_task = BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2); |
| 225 Bind(&ExpectProcessedEvents, Unretained(injector()), 2); | 224 posted_task = |
| 226 posted_task = Bind(&PostMessageLoopTask, FROM_HERE, check_task); | 225 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task)); |
| 227 injector()->AddEventAsTask(0, posted_task); | 226 injector()->AddEventAsTask(0, std::move(posted_task)); |
| 228 injector()->AddEventAsTask(10, Bind(&DoNothing)); | 227 injector()->AddEventAsTask(10, BindOnce(&DoNothing)); |
| 229 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); | 228 injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure()); |
| 230 RunLoop().Run(); | 229 RunLoop().Run(); |
| 231 EXPECT_EQ(4, injector()->processed_events()); | 230 EXPECT_EQ(4, injector()->processed_events()); |
| 232 } | 231 } |
| 233 | 232 |
| 234 TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) { | 233 TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) { |
| 235 int task_count = 0; | 234 int task_count = 0; |
| 236 // Tests that we process tasks while waiting for new events. | 235 // Tests that we process tasks while waiting for new events. |
| 237 // The event queue is empty at first. | 236 // The event queue is empty at first. |
| 238 for (int i = 0; i < 10; ++i) { | 237 for (int i = 0; i < 10; ++i) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 OnceClosure check_task = |
| 283 Bind(&ExpectProcessedEvents, Unretained(injector()), 11); | 282 BindOnce(&ExpectProcessedEvents, Unretained(injector()), 11); |
| 284 Closure posted_task = | 283 OnceClosure posted_task = |
| 285 Bind(&PostMessageLoopTask, FROM_HERE, check_task); | 284 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task)); |
| 286 injector()->AddEventAsTask(10, posted_task); | 285 injector()->AddEventAsTask(10, std::move(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 RunLoop().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 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 317 } | 316 } |
| 318 } | 317 } |
| 319 | 318 |
| 320 void FromEvent() { | 319 void FromEvent() { |
| 321 if (event_count_ > 0) { | 320 if (event_count_ > 0) { |
| 322 --event_count_; | 321 --event_count_; |
| 323 } | 322 } |
| 324 if (task_count_ == 0 && event_count_ == 0) { | 323 if (task_count_ == 0 && event_count_ == 0) { |
| 325 MessageLoop::current()->QuitWhenIdle(); | 324 MessageLoop::current()->QuitWhenIdle(); |
| 326 } else { | 325 } else { |
| 327 injector_->AddEventAsTask( | 326 injector_->AddEventAsTask(0, |
| 328 0, Bind(&ConcurrentHelper::FromEvent, this)); | 327 BindOnce(&ConcurrentHelper::FromEvent, this)); |
| 329 } | 328 } |
| 330 } | 329 } |
| 331 | 330 |
| 332 int event_count() const { return event_count_; } | 331 int event_count() const { return event_count_; } |
| 333 int task_count() const { return task_count_; } | 332 int task_count() const { return task_count_; } |
| 334 | 333 |
| 335 private: | 334 private: |
| 336 friend class RefCounted<ConcurrentHelper>; | 335 friend class RefCounted<ConcurrentHelper>; |
| 337 | 336 |
| 338 ~ConcurrentHelper() {} | 337 ~ConcurrentHelper() {} |
| (...skipping 11 matching lines...) Expand all Loading... |
| 350 TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) { | 349 TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) { |
| 351 // Tests that posted tasks don't starve events, nor the opposite. | 350 // Tests that posted tasks don't starve events, nor the opposite. |
| 352 // We use the helper class above. We keep both event and posted task queues | 351 // We use the helper class above. We keep both event and posted task queues |
| 353 // full, the helper verifies that both tasks and events get processed. | 352 // full, the helper verifies that both tasks and events get processed. |
| 354 // If that is not the case, either event_count_ or task_count_ will not get | 353 // If that is not the case, either event_count_ or task_count_ will not get |
| 355 // to 0, and MessageLoop::QuitWhenIdle() will never be called. | 354 // to 0, and MessageLoop::QuitWhenIdle() will never be called. |
| 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(0, BindOnce(&ConcurrentHelper::FromEvent, helper)); |
| 361 0, Bind(&ConcurrentHelper::FromEvent, helper)); | 360 injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper)); |
| 362 injector()->AddEventAsTask( | |
| 363 0, Bind(&ConcurrentHelper::FromEvent, helper)); | |
| 364 | 361 |
| 365 // Similarly post 2 tasks. | 362 // Similarly post 2 tasks. |
| 366 loop()->task_runner()->PostTask( | 363 loop()->task_runner()->PostTask( |
| 367 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper)); | 364 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper)); |
| 368 loop()->task_runner()->PostTask( | 365 loop()->task_runner()->PostTask( |
| 369 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper)); | 366 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper)); |
| 370 | 367 |
| 371 RunLoop().Run(); | 368 RunLoop().Run(); |
| 372 EXPECT_EQ(0, helper->event_count()); | 369 EXPECT_EQ(0, helper->event_count()); |
| 373 EXPECT_EQ(0, helper->task_count()); | 370 EXPECT_EQ(0, helper->task_count()); |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 // Tests that events and posted tasks are correctly executed if the message | 517 // Tests that events and posted tasks are correctly executed if the message |
| 521 // loop is not run by MessageLoop::Run() but by a straight Gtk loop. | 518 // loop is not run by MessageLoop::Run() but by a straight Gtk loop. |
| 522 // Note that in this case we don't make strong guarantees about niceness | 519 // Note that in this case we don't make strong guarantees about niceness |
| 523 // between events and posted tasks. | 520 // between events and posted tasks. |
| 524 loop()->task_runner()->PostTask( | 521 loop()->task_runner()->PostTask( |
| 525 FROM_HERE, BindOnce(&TestGtkLoopInternal, Unretained(injector()))); | 522 FROM_HERE, BindOnce(&TestGtkLoopInternal, Unretained(injector()))); |
| 526 RunLoop().Run(); | 523 RunLoop().Run(); |
| 527 } | 524 } |
| 528 | 525 |
| 529 } // namespace base | 526 } // namespace base |
| OLD | NEW |