blob: 512cea63125f2a40f40288a9c7f2c3d7ddf2bcb0 [file] [log] [blame]
[email protected]ac4c6682012-01-04 00:57:391// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]b44d5cc2009-06-15 10:30:442// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]59e69e742013-06-18 20:27:525#include "base/message_loop/message_pump_glib.h"
[email protected]b44d5cc2009-06-15 10:30:446
[email protected]d90efd52012-06-28 19:57:267#include <glib.h>
[email protected]23d35392009-06-15 19:53:088#include <math.h>
9
[email protected]b44d5cc2009-06-15 10:30:4410#include <algorithm>
11#include <vector>
[email protected]23d35392009-06-15 19:53:0812
[email protected]8f5a7e492012-01-01 02:14:4713#include "base/bind.h"
14#include "base/bind_helpers.h"
[email protected]763839e2011-12-09 23:06:0215#include "base/callback.h"
avi9b6f42932015-12-26 22:15:1416#include "base/macros.h"
[email protected]3b63f8f42011-03-28 01:54:1517#include "base/memory/ref_counted.h"
[email protected]495cad92013-07-18 08:12:4018#include "base/message_loop/message_loop.h"
Gabriel Charette810f3f432018-04-27 22:28:1419#include "base/message_loop/message_loop_current.h"
[email protected]7ff48ca2013-02-06 16:56:1920#include "base/run_loop.h"
fdoray6ef45cf2016-08-25 15:36:3721#include "base/single_thread_task_runner.h"
[email protected]34b99632011-01-01 01:01:0622#include "base/threading/thread.h"
fdoray2df4a9e2016-07-18 23:47:1623#include "base/threading/thread_task_runner_handle.h"
[email protected]b44d5cc2009-06-15 10:30:4424#include "testing/gtest/include/gtest/gtest.h"
25
[email protected]7ff48ca2013-02-06 16:56:1926namespace base {
[email protected]b44d5cc2009-06-15 10:30:4427namespace {
28
29// This class injects dummy "events" into the GLib loop. When "handled" these
30// events can run tasks. This is intended to mock gtk events (the corresponding
31// GLib source runs at the same priority).
32class EventInjector {
33 public:
34 EventInjector() : processed_events_(0) {
35 source_ = static_cast<Source*>(g_source_new(&SourceFuncs, sizeof(Source)));
36 source_->injector = this;
Ivan Kotenkova16212a52017-11-08 12:37:3337 g_source_attach(source_, nullptr);
[email protected]b44d5cc2009-06-15 10:30:4438 g_source_set_can_recurse(source_, TRUE);
39 }
40
41 ~EventInjector() {
42 g_source_destroy(source_);
43 g_source_unref(source_);
44 }
45
46 int HandlePrepare() {
47 // If the queue is empty, block.
48 if (events_.empty())
49 return -1;
[email protected]59e69e742013-06-18 20:27:5250 TimeDelta delta = events_[0].time - Time::NowFromSystemTime();
[email protected]b44d5cc2009-06-15 10:30:4451 return std::max(0, static_cast<int>(ceil(delta.InMillisecondsF())));
52 }
53
54 bool HandleCheck() {
55 if (events_.empty())
56 return false;
[email protected]59e69e742013-06-18 20:27:5257 return events_[0].time <= Time::NowFromSystemTime();
[email protected]b44d5cc2009-06-15 10:30:4458 }
59
60 void HandleDispatch() {
61 if (events_.empty())
62 return;
tzika8cc2202017-04-18 07:01:1563 Event event = std::move(events_[0]);
[email protected]b44d5cc2009-06-15 10:30:4464 events_.erase(events_.begin());
65 ++processed_events_;
[email protected]8f5a7e492012-01-01 02:14:4766 if (!event.callback.is_null())
tzika8cc2202017-04-18 07:01:1567 std::move(event.callback).Run();
[email protected]8f5a7e492012-01-01 02:14:4768 else if (!event.task.is_null())
tzika8cc2202017-04-18 07:01:1569 std::move(event.task).Run();
[email protected]b44d5cc2009-06-15 10:30:4470 }
71
[email protected]763839e2011-12-09 23:06:0272 // Adds an event to the queue. When "handled", executes |callback|.
[email protected]b44d5cc2009-06-15 10:30:4473 // delay_ms is relative to the last event if any, or to Now() otherwise.
tzika8cc2202017-04-18 07:01:1574 void AddEvent(int delay_ms, OnceClosure callback) {
75 AddEventHelper(delay_ms, std::move(callback), OnceClosure());
[email protected]763839e2011-12-09 23:06:0276 }
77
78 void AddDummyEvent(int delay_ms) {
tzika8cc2202017-04-18 07:01:1579 AddEventHelper(delay_ms, OnceClosure(), OnceClosure());
[email protected]763839e2011-12-09 23:06:0280 }
81
tzika8cc2202017-04-18 07:01:1582 void AddEventAsTask(int delay_ms, OnceClosure task) {
83 AddEventHelper(delay_ms, OnceClosure(), std::move(task));
[email protected]b44d5cc2009-06-15 10:30:4484 }
85
86 void Reset() {
87 processed_events_ = 0;
88 events_.clear();
89 }
90
91 int processed_events() const { return processed_events_; }
92
93 private:
94 struct Event {
[email protected]59e69e742013-06-18 20:27:5295 Time time;
tzika8cc2202017-04-18 07:01:1596 OnceClosure callback;
97 OnceClosure task;
[email protected]b44d5cc2009-06-15 10:30:4498 };
99
100 struct Source : public GSource {
101 EventInjector* injector;
102 };
103
tzika8cc2202017-04-18 07:01:15104 void AddEventHelper(int delay_ms, OnceClosure callback, OnceClosure task) {
[email protected]59e69e742013-06-18 20:27:52105 Time last_time;
[email protected]8f5a7e492012-01-01 02:14:47106 if (!events_.empty())
[email protected]763839e2011-12-09 23:06:02107 last_time = (events_.end()-1)->time;
[email protected]8f5a7e492012-01-01 02:14:47108 else
[email protected]59e69e742013-06-18 20:27:52109 last_time = Time::NowFromSystemTime();
[email protected]8f5a7e492012-01-01 02:14:47110
[email protected]59e69e742013-06-18 20:27:52111 Time future = last_time + TimeDelta::FromMilliseconds(delay_ms);
tzika8cc2202017-04-18 07:01:15112 EventInjector::Event event = {future, std::move(callback), std::move(task)};
113 events_.push_back(std::move(event));
[email protected]763839e2011-12-09 23:06:02114 }
115
[email protected]b44d5cc2009-06-15 10:30:44116 static gboolean Prepare(GSource* source, gint* timeout_ms) {
117 *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare();
118 return FALSE;
119 }
120
121 static gboolean Check(GSource* source) {
122 return static_cast<Source*>(source)->injector->HandleCheck();
123 }
124
125 static gboolean Dispatch(GSource* source,
126 GSourceFunc unused_func,
127 gpointer unused_data) {
128 static_cast<Source*>(source)->injector->HandleDispatch();
129 return TRUE;
130 }
131
132 Source* source_;
133 std::vector<Event> events_;
134 int processed_events_;
135 static GSourceFuncs SourceFuncs;
136 DISALLOW_COPY_AND_ASSIGN(EventInjector);
137};
138
Ivan Kotenkova16212a52017-11-08 12:37:33139GSourceFuncs EventInjector::SourceFuncs = {EventInjector::Prepare,
140 EventInjector::Check,
141 EventInjector::Dispatch, nullptr};
[email protected]b44d5cc2009-06-15 10:30:44142
[email protected]b44d5cc2009-06-15 10:30:44143void IncrementInt(int *value) {
144 ++*value;
145}
146
147// Checks how many events have been processed by the injector.
148void ExpectProcessedEvents(EventInjector* injector, int count) {
149 EXPECT_EQ(injector->processed_events(), count);
150}
151
[email protected]b44d5cc2009-06-15 10:30:44152// Posts a task on the current message loop.
Brett Wilson8e88b312017-09-12 05:22:16153void PostMessageLoopTask(const Location& from_here, OnceClosure task) {
tzika8cc2202017-04-18 07:01:15154 ThreadTaskRunnerHandle::Get()->PostTask(from_here, std::move(task));
[email protected]b44d5cc2009-06-15 10:30:44155}
156
157// Test fixture.
158class MessagePumpGLibTest : public testing::Test {
159 public:
Ivan Kotenkova16212a52017-11-08 12:37:33160 MessagePumpGLibTest() : loop_(nullptr), injector_(nullptr) {}
[email protected]b44d5cc2009-06-15 10:30:44161
[email protected]c19003d2012-07-31 01:38:18162 // Overridden from testing::Test:
dcheng8aef37612014-12-23 02:56:47163 void SetUp() override {
[email protected]b44d5cc2009-06-15 10:30:44164 loop_ = new MessageLoop(MessageLoop::TYPE_UI);
165 injector_ = new EventInjector();
166 }
dcheng8aef37612014-12-23 02:56:47167 void TearDown() override {
[email protected]b44d5cc2009-06-15 10:30:44168 delete injector_;
Ivan Kotenkova16212a52017-11-08 12:37:33169 injector_ = nullptr;
[email protected]b44d5cc2009-06-15 10:30:44170 delete loop_;
Ivan Kotenkova16212a52017-11-08 12:37:33171 loop_ = nullptr;
[email protected]b44d5cc2009-06-15 10:30:44172 }
173
174 MessageLoop* loop() const { return loop_; }
175 EventInjector* injector() const { return injector_; }
176
177 private:
178 MessageLoop* loop_;
179 EventInjector* injector_;
180 DISALLOW_COPY_AND_ASSIGN(MessagePumpGLibTest);
181};
182
183} // namespace
184
[email protected]b44d5cc2009-06-15 10:30:44185TEST_F(MessagePumpGLibTest, TestQuit) {
186 // Checks that Quit works and that the basic infrastructure is working.
187
188 // Quit from a task
[email protected]7ff48ca2013-02-06 16:56:19189 RunLoop().RunUntilIdle();
[email protected]b44d5cc2009-06-15 10:30:44190 EXPECT_EQ(0, injector()->processed_events());
191
192 injector()->Reset();
193 // Quit from an event
Wezfda077b2018-06-07 21:18:11194 RunLoop run_loop;
195 injector()->AddEvent(0, run_loop.QuitClosure());
196 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44197 EXPECT_EQ(1, injector()->processed_events());
198}
199
200TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) {
201 // Checks that tasks posted by events are executed before the next event if
202 // the posted task queue is empty.
203 // MessageLoop doesn't make strong guarantees that it is the case, but the
204 // current implementation ensures it and the tests below rely on it.
205 // If changes cause this test to fail, it is reasonable to change it, but
206 // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be
207 // changed accordingly, otherwise they can become flaky.
Peter Kasting341e1fb2018-02-24 00:03:01208 injector()->AddEventAsTask(0, DoNothing());
tzika8cc2202017-04-18 07:01:15209 OnceClosure check_task =
210 BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2);
211 OnceClosure posted_task =
212 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
213 injector()->AddEventAsTask(0, std::move(posted_task));
Peter Kasting341e1fb2018-02-24 00:03:01214 injector()->AddEventAsTask(0, DoNothing());
Wezfda077b2018-06-07 21:18:11215 {
216 RunLoop run_loop;
217 injector()->AddEvent(0, run_loop.QuitClosure());
218 run_loop.Run();
219 }
[email protected]b44d5cc2009-06-15 10:30:44220 EXPECT_EQ(4, injector()->processed_events());
221
222 injector()->Reset();
Peter Kasting341e1fb2018-02-24 00:03:01223 injector()->AddEventAsTask(0, DoNothing());
tzika8cc2202017-04-18 07:01:15224 check_task = BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2);
225 posted_task =
226 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
227 injector()->AddEventAsTask(0, std::move(posted_task));
Peter Kasting341e1fb2018-02-24 00:03:01228 injector()->AddEventAsTask(10, DoNothing());
Wezfda077b2018-06-07 21:18:11229 {
230 RunLoop run_loop;
231 injector()->AddEvent(0, run_loop.QuitClosure());
232 run_loop.Run();
233 }
[email protected]b44d5cc2009-06-15 10:30:44234 EXPECT_EQ(4, injector()->processed_events());
235}
236
237TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) {
238 int task_count = 0;
239 // Tests that we process tasks while waiting for new events.
240 // The event queue is empty at first.
241 for (int i = 0; i < 10; ++i) {
fdoray6ef45cf2016-08-25 15:36:37242 loop()->task_runner()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44243 BindOnce(&IncrementInt, &task_count));
[email protected]b44d5cc2009-06-15 10:30:44244 }
245 // After all the previous tasks have executed, enqueue an event that will
246 // quit.
Wezfda077b2018-06-07 21:18:11247 {
248 RunLoop run_loop;
249 loop()->task_runner()->PostTask(
250 FROM_HERE, BindOnce(&EventInjector::AddEvent, Unretained(injector()), 0,
251 run_loop.QuitClosure()));
252 run_loop.Run();
253 }
[email protected]b44d5cc2009-06-15 10:30:44254 ASSERT_EQ(10, task_count);
255 EXPECT_EQ(1, injector()->processed_events());
256
257 // Tests that we process delayed tasks while waiting for new events.
258 injector()->Reset();
259 task_count = 0;
260 for (int i = 0; i < 10; ++i) {
fdoray6ef45cf2016-08-25 15:36:37261 loop()->task_runner()->PostDelayedTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44262 BindOnce(&IncrementInt, &task_count),
fdoray6ef45cf2016-08-25 15:36:37263 TimeDelta::FromMilliseconds(10 * i));
[email protected]b44d5cc2009-06-15 10:30:44264 }
265 // After all the previous tasks have executed, enqueue an event that will
266 // quit.
267 // This relies on the fact that delayed tasks are executed in delay order.
268 // That is verified in message_loop_unittest.cc.
Wezfda077b2018-06-07 21:18:11269 {
270 RunLoop run_loop;
271 loop()->task_runner()->PostDelayedTask(
272 FROM_HERE,
273 BindOnce(&EventInjector::AddEvent, Unretained(injector()), 0,
274 run_loop.QuitClosure()),
275 TimeDelta::FromMilliseconds(150));
276 run_loop.Run();
277 }
[email protected]b44d5cc2009-06-15 10:30:44278 ASSERT_EQ(10, task_count);
279 EXPECT_EQ(1, injector()->processed_events());
280}
281
282TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) {
283 // Tests that we process events while waiting for work.
284 // The event queue is empty at first.
285 for (int i = 0; i < 10; ++i) {
[email protected]763839e2011-12-09 23:06:02286 injector()->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44287 }
288 // After all the events have been processed, post a task that will check that
289 // the events have been processed (note: the task executes after the event
290 // that posted it has been handled, so we expect 11 at that point).
tzika8cc2202017-04-18 07:01:15291 OnceClosure check_task =
292 BindOnce(&ExpectProcessedEvents, Unretained(injector()), 11);
293 OnceClosure posted_task =
294 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
295 injector()->AddEventAsTask(10, std::move(posted_task));
[email protected]b44d5cc2009-06-15 10:30:44296
297 // And then quit (relies on the condition tested by TestEventTaskInterleave).
Wezfda077b2018-06-07 21:18:11298 RunLoop run_loop;
299 injector()->AddEvent(10, run_loop.QuitClosure());
300 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44301
302 EXPECT_EQ(12, injector()->processed_events());
303}
304
305namespace {
306
307// This class is a helper for the concurrent events / posted tasks test below.
308// It will quit the main loop once enough tasks and events have been processed,
309// while making sure there is always work to do and events in the queue.
[email protected]59e69e742013-06-18 20:27:52310class ConcurrentHelper : public RefCounted<ConcurrentHelper> {
[email protected]b44d5cc2009-06-15 10:30:44311 public:
Wezfda077b2018-06-07 21:18:11312 ConcurrentHelper(EventInjector* injector, OnceClosure done_closure)
[email protected]b44d5cc2009-06-15 10:30:44313 : injector_(injector),
Wezfda077b2018-06-07 21:18:11314 done_closure_(std::move(done_closure)),
[email protected]b44d5cc2009-06-15 10:30:44315 event_count_(kStartingEventCount),
Wezfda077b2018-06-07 21:18:11316 task_count_(kStartingTaskCount) {}
[email protected]b44d5cc2009-06-15 10:30:44317
318 void FromTask() {
319 if (task_count_ > 0) {
320 --task_count_;
321 }
322 if (task_count_ == 0 && event_count_ == 0) {
Wezfda077b2018-06-07 21:18:11323 std::move(done_closure_).Run();
[email protected]b44d5cc2009-06-15 10:30:44324 } else {
fdoray2df4a9e2016-07-18 23:47:16325 ThreadTaskRunnerHandle::Get()->PostTask(
tzik92b7a422017-04-11 15:00:44326 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, this));
[email protected]b44d5cc2009-06-15 10:30:44327 }
328 }
329
330 void FromEvent() {
331 if (event_count_ > 0) {
332 --event_count_;
333 }
334 if (task_count_ == 0 && event_count_ == 0) {
Wezfda077b2018-06-07 21:18:11335 std::move(done_closure_).Run();
[email protected]b44d5cc2009-06-15 10:30:44336 } else {
tzika8cc2202017-04-18 07:01:15337 injector_->AddEventAsTask(0,
338 BindOnce(&ConcurrentHelper::FromEvent, this));
[email protected]b44d5cc2009-06-15 10:30:44339 }
340 }
341
342 int event_count() const { return event_count_; }
343 int task_count() const { return task_count_; }
344
345 private:
[email protected]59e69e742013-06-18 20:27:52346 friend class RefCounted<ConcurrentHelper>;
[email protected]877d55d2009-11-05 21:53:08347
348 ~ConcurrentHelper() {}
349
[email protected]b44d5cc2009-06-15 10:30:44350 static const int kStartingEventCount = 20;
351 static const int kStartingTaskCount = 20;
352
353 EventInjector* injector_;
Wezfda077b2018-06-07 21:18:11354 OnceClosure done_closure_;
[email protected]b44d5cc2009-06-15 10:30:44355 int event_count_;
356 int task_count_;
357};
358
359} // namespace
360
361TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) {
362 // Tests that posted tasks don't starve events, nor the opposite.
363 // We use the helper class above. We keep both event and posted task queues
364 // full, the helper verifies that both tasks and events get processed.
365 // If that is not the case, either event_count_ or task_count_ will not get
[email protected]91cae2592013-01-10 14:56:17366 // to 0, and MessageLoop::QuitWhenIdle() will never be called.
Wezfda077b2018-06-07 21:18:11367 RunLoop run_loop;
368 scoped_refptr<ConcurrentHelper> helper =
369 new ConcurrentHelper(injector(), run_loop.QuitClosure());
[email protected]b44d5cc2009-06-15 10:30:44370
371 // Add 2 events to the queue to make sure it is always full (when we remove
372 // the event before processing it).
tzika8cc2202017-04-18 07:01:15373 injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper));
374 injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper));
[email protected]b44d5cc2009-06-15 10:30:44375
376 // Similarly post 2 tasks.
fdoray6ef45cf2016-08-25 15:36:37377 loop()->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44378 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper));
fdoray6ef45cf2016-08-25 15:36:37379 loop()->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44380 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper));
[email protected]b44d5cc2009-06-15 10:30:44381
Wezfda077b2018-06-07 21:18:11382 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44383 EXPECT_EQ(0, helper->event_count());
384 EXPECT_EQ(0, helper->task_count());
385}
386
387namespace {
388
Wezfda077b2018-06-07 21:18:11389void AddEventsAndDrainGLib(EventInjector* injector, OnceClosure on_drained) {
[email protected]b44d5cc2009-06-15 10:30:44390 // Add a couple of dummy events
[email protected]763839e2011-12-09 23:06:02391 injector->AddDummyEvent(0);
392 injector->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44393 // Then add an event that will quit the main loop.
Wezfda077b2018-06-07 21:18:11394 injector->AddEvent(0, std::move(on_drained));
[email protected]b44d5cc2009-06-15 10:30:44395
396 // Post a couple of dummy tasks
Peter Kasting341e1fb2018-02-24 00:03:01397 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
398 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
[email protected]b44d5cc2009-06-15 10:30:44399
400 // Drain the events
Ivan Kotenkova16212a52017-11-08 12:37:33401 while (g_main_context_pending(nullptr)) {
402 g_main_context_iteration(nullptr, FALSE);
[email protected]b44d5cc2009-06-15 10:30:44403 }
404}
405
406} // namespace
407
408TEST_F(MessagePumpGLibTest, TestDrainingGLib) {
409 // Tests that draining events using GLib works.
Wezfda077b2018-06-07 21:18:11410 RunLoop run_loop;
fdoray6ef45cf2016-08-25 15:36:37411 loop()->task_runner()->PostTask(
Wezfda077b2018-06-07 21:18:11412 FROM_HERE, BindOnce(&AddEventsAndDrainGLib, Unretained(injector()),
413 run_loop.QuitClosure()));
414 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44415
416 EXPECT_EQ(3, injector()->processed_events());
417}
418
[email protected]b44d5cc2009-06-15 10:30:44419namespace {
420
421// Helper class that lets us run the GLib message loop.
[email protected]59e69e742013-06-18 20:27:52422class GLibLoopRunner : public RefCounted<GLibLoopRunner> {
[email protected]b44d5cc2009-06-15 10:30:44423 public:
424 GLibLoopRunner() : quit_(false) { }
425
426 void RunGLib() {
427 while (!quit_) {
Ivan Kotenkova16212a52017-11-08 12:37:33428 g_main_context_iteration(nullptr, TRUE);
[email protected]b44d5cc2009-06-15 10:30:44429 }
430 }
431
[email protected]258dca42011-09-21 00:17:19432 void RunLoop() {
[email protected]258dca42011-09-21 00:17:19433 while (!quit_) {
Ivan Kotenkova16212a52017-11-08 12:37:33434 g_main_context_iteration(nullptr, TRUE);
[email protected]258dca42011-09-21 00:17:19435 }
[email protected]b44d5cc2009-06-15 10:30:44436 }
437
438 void Quit() {
439 quit_ = true;
440 }
441
442 void Reset() {
443 quit_ = false;
444 }
445
446 private:
[email protected]59e69e742013-06-18 20:27:52447 friend class RefCounted<GLibLoopRunner>;
[email protected]877d55d2009-11-05 21:53:08448
449 ~GLibLoopRunner() {}
450
[email protected]b44d5cc2009-06-15 10:30:44451 bool quit_;
452};
453
Wezfda077b2018-06-07 21:18:11454void TestGLibLoopInternal(EventInjector* injector, OnceClosure done) {
[email protected]b44d5cc2009-06-15 10:30:44455 // Allow tasks to be processed from 'native' event loops.
Gabriel Charette810f3f432018-04-27 22:28:14456 MessageLoopCurrent::Get()->SetNestableTasksAllowed(true);
[email protected]b44d5cc2009-06-15 10:30:44457 scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
458
459 int task_count = 0;
460 // Add a couple of dummy events
[email protected]763839e2011-12-09 23:06:02461 injector->AddDummyEvent(0);
462 injector->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44463 // Post a couple of dummy tasks
fdoray2df4a9e2016-07-18 23:47:16464 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44465 BindOnce(&IncrementInt, &task_count));
fdoray2df4a9e2016-07-18 23:47:16466 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44467 BindOnce(&IncrementInt, &task_count));
[email protected]b44d5cc2009-06-15 10:30:44468 // Delayed events
[email protected]763839e2011-12-09 23:06:02469 injector->AddDummyEvent(10);
470 injector->AddDummyEvent(10);
[email protected]b44d5cc2009-06-15 10:30:44471 // Delayed work
fdoray2df4a9e2016-07-18 23:47:16472 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44473 FROM_HERE, BindOnce(&IncrementInt, &task_count),
[email protected]59e69e742013-06-18 20:27:52474 TimeDelta::FromMilliseconds(30));
fdoray2df4a9e2016-07-18 23:47:16475 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44476 FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner),
[email protected]59e69e742013-06-18 20:27:52477 TimeDelta::FromMilliseconds(40));
[email protected]b44d5cc2009-06-15 10:30:44478
479 // Run a nested, straight GLib message loop.
480 runner->RunGLib();
481
482 ASSERT_EQ(3, task_count);
483 EXPECT_EQ(4, injector->processed_events());
Wezfda077b2018-06-07 21:18:11484 std::move(done).Run();
[email protected]b44d5cc2009-06-15 10:30:44485}
486
Wezfda077b2018-06-07 21:18:11487void TestGtkLoopInternal(EventInjector* injector, OnceClosure done) {
[email protected]b44d5cc2009-06-15 10:30:44488 // Allow tasks to be processed from 'native' event loops.
Gabriel Charette810f3f432018-04-27 22:28:14489 MessageLoopCurrent::Get()->SetNestableTasksAllowed(true);
[email protected]b44d5cc2009-06-15 10:30:44490 scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
491
492 int task_count = 0;
493 // Add a couple of dummy events
[email protected]763839e2011-12-09 23:06:02494 injector->AddDummyEvent(0);
495 injector->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44496 // Post a couple of dummy tasks
fdoray2df4a9e2016-07-18 23:47:16497 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44498 BindOnce(&IncrementInt, &task_count));
fdoray2df4a9e2016-07-18 23:47:16499 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44500 BindOnce(&IncrementInt, &task_count));
[email protected]b44d5cc2009-06-15 10:30:44501 // Delayed events
[email protected]763839e2011-12-09 23:06:02502 injector->AddDummyEvent(10);
503 injector->AddDummyEvent(10);
[email protected]b44d5cc2009-06-15 10:30:44504 // Delayed work
fdoray2df4a9e2016-07-18 23:47:16505 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44506 FROM_HERE, BindOnce(&IncrementInt, &task_count),
[email protected]59e69e742013-06-18 20:27:52507 TimeDelta::FromMilliseconds(30));
fdoray2df4a9e2016-07-18 23:47:16508 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44509 FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner),
[email protected]59e69e742013-06-18 20:27:52510 TimeDelta::FromMilliseconds(40));
[email protected]b44d5cc2009-06-15 10:30:44511
512 // Run a nested, straight Gtk message loop.
[email protected]258dca42011-09-21 00:17:19513 runner->RunLoop();
[email protected]b44d5cc2009-06-15 10:30:44514
515 ASSERT_EQ(3, task_count);
516 EXPECT_EQ(4, injector->processed_events());
Wezfda077b2018-06-07 21:18:11517 std::move(done).Run();
[email protected]b44d5cc2009-06-15 10:30:44518}
519
520} // namespace
521
522TEST_F(MessagePumpGLibTest, TestGLibLoop) {
[email protected]8f5a7e492012-01-01 02:14:47523 // Tests that events and posted tasks are correctly executed if the message
[email protected]b44d5cc2009-06-15 10:30:44524 // loop is not run by MessageLoop::Run() but by a straight GLib loop.
525 // Note that in this case we don't make strong guarantees about niceness
526 // between events and posted tasks.
Wezfda077b2018-06-07 21:18:11527 RunLoop run_loop;
fdoray6ef45cf2016-08-25 15:36:37528 loop()->task_runner()->PostTask(
Wezfda077b2018-06-07 21:18:11529 FROM_HERE, BindOnce(&TestGLibLoopInternal, Unretained(injector()),
530 run_loop.QuitClosure()));
531 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44532}
533
534TEST_F(MessagePumpGLibTest, TestGtkLoop) {
[email protected]8f5a7e492012-01-01 02:14:47535 // Tests that events and posted tasks are correctly executed if the message
[email protected]b44d5cc2009-06-15 10:30:44536 // loop is not run by MessageLoop::Run() but by a straight Gtk loop.
537 // Note that in this case we don't make strong guarantees about niceness
538 // between events and posted tasks.
Wezfda077b2018-06-07 21:18:11539 RunLoop run_loop;
fdoray6ef45cf2016-08-25 15:36:37540 loop()->task_runner()->PostTask(
Wezfda077b2018-06-07 21:18:11541 FROM_HERE, BindOnce(&TestGtkLoopInternal, Unretained(injector()),
542 run_loop.QuitClosure()));
543 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44544}
[email protected]7ff48ca2013-02-06 16:56:19545
546} // namespace base