blob: 94b2d592c324001d940ed3dbe970e1252daca97b [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"
Nick Diego Yamane58914192019-08-08 17:12:4816#include "base/files/file_util.h"
avi9b6f42932015-12-26 22:15:1417#include "base/macros.h"
[email protected]3b63f8f42011-03-28 01:54:1518#include "base/memory/ref_counted.h"
Alexander Timin4f9c35c2018-11-01 20:15:2019#include "base/message_loop/message_loop.h"
Gabriel Charette810f3f432018-04-27 22:28:1420#include "base/message_loop/message_loop_current.h"
Carlos Caballerodd8bf7b042019-07-30 14:14:1521#include "base/message_loop/message_pump_type.h"
Nick Diego Yamane58914192019-08-08 17:12:4822#include "base/posix/eintr_wrapper.h"
[email protected]7ff48ca2013-02-06 16:56:1923#include "base/run_loop.h"
fdoray6ef45cf2016-08-25 15:36:3724#include "base/single_thread_task_runner.h"
Nick Diego Yamane58914192019-08-08 17:12:4825#include "base/synchronization/waitable_event.h"
26#include "base/synchronization/waitable_event_watcher.h"
[email protected]34b99632011-01-01 01:01:0627#include "base/threading/thread.h"
fdoray2df4a9e2016-07-18 23:47:1628#include "base/threading/thread_task_runner_handle.h"
[email protected]b44d5cc2009-06-15 10:30:4429#include "testing/gtest/include/gtest/gtest.h"
30
[email protected]7ff48ca2013-02-06 16:56:1931namespace base {
[email protected]b44d5cc2009-06-15 10:30:4432namespace {
33
34// This class injects dummy "events" into the GLib loop. When "handled" these
35// events can run tasks. This is intended to mock gtk events (the corresponding
36// GLib source runs at the same priority).
37class EventInjector {
38 public:
39 EventInjector() : processed_events_(0) {
40 source_ = static_cast<Source*>(g_source_new(&SourceFuncs, sizeof(Source)));
41 source_->injector = this;
Ivan Kotenkova16212a52017-11-08 12:37:3342 g_source_attach(source_, nullptr);
[email protected]b44d5cc2009-06-15 10:30:4443 g_source_set_can_recurse(source_, TRUE);
44 }
45
46 ~EventInjector() {
47 g_source_destroy(source_);
48 g_source_unref(source_);
49 }
50
51 int HandlePrepare() {
52 // If the queue is empty, block.
53 if (events_.empty())
54 return -1;
[email protected]59e69e742013-06-18 20:27:5255 TimeDelta delta = events_[0].time - Time::NowFromSystemTime();
[email protected]b44d5cc2009-06-15 10:30:4456 return std::max(0, static_cast<int>(ceil(delta.InMillisecondsF())));
57 }
58
59 bool HandleCheck() {
60 if (events_.empty())
61 return false;
[email protected]59e69e742013-06-18 20:27:5262 return events_[0].time <= Time::NowFromSystemTime();
[email protected]b44d5cc2009-06-15 10:30:4463 }
64
65 void HandleDispatch() {
66 if (events_.empty())
67 return;
tzika8cc2202017-04-18 07:01:1568 Event event = std::move(events_[0]);
[email protected]b44d5cc2009-06-15 10:30:4469 events_.erase(events_.begin());
70 ++processed_events_;
[email protected]8f5a7e492012-01-01 02:14:4771 if (!event.callback.is_null())
tzika8cc2202017-04-18 07:01:1572 std::move(event.callback).Run();
[email protected]8f5a7e492012-01-01 02:14:4773 else if (!event.task.is_null())
tzika8cc2202017-04-18 07:01:1574 std::move(event.task).Run();
[email protected]b44d5cc2009-06-15 10:30:4475 }
76
[email protected]763839e2011-12-09 23:06:0277 // Adds an event to the queue. When "handled", executes |callback|.
[email protected]b44d5cc2009-06-15 10:30:4478 // delay_ms is relative to the last event if any, or to Now() otherwise.
tzika8cc2202017-04-18 07:01:1579 void AddEvent(int delay_ms, OnceClosure callback) {
80 AddEventHelper(delay_ms, std::move(callback), OnceClosure());
[email protected]763839e2011-12-09 23:06:0281 }
82
83 void AddDummyEvent(int delay_ms) {
tzika8cc2202017-04-18 07:01:1584 AddEventHelper(delay_ms, OnceClosure(), OnceClosure());
[email protected]763839e2011-12-09 23:06:0285 }
86
tzika8cc2202017-04-18 07:01:1587 void AddEventAsTask(int delay_ms, OnceClosure task) {
88 AddEventHelper(delay_ms, OnceClosure(), std::move(task));
[email protected]b44d5cc2009-06-15 10:30:4489 }
90
91 void Reset() {
92 processed_events_ = 0;
93 events_.clear();
94 }
95
96 int processed_events() const { return processed_events_; }
97
98 private:
99 struct Event {
[email protected]59e69e742013-06-18 20:27:52100 Time time;
tzika8cc2202017-04-18 07:01:15101 OnceClosure callback;
102 OnceClosure task;
[email protected]b44d5cc2009-06-15 10:30:44103 };
104
105 struct Source : public GSource {
106 EventInjector* injector;
107 };
108
tzika8cc2202017-04-18 07:01:15109 void AddEventHelper(int delay_ms, OnceClosure callback, OnceClosure task) {
[email protected]59e69e742013-06-18 20:27:52110 Time last_time;
[email protected]8f5a7e492012-01-01 02:14:47111 if (!events_.empty())
[email protected]763839e2011-12-09 23:06:02112 last_time = (events_.end()-1)->time;
[email protected]8f5a7e492012-01-01 02:14:47113 else
[email protected]59e69e742013-06-18 20:27:52114 last_time = Time::NowFromSystemTime();
[email protected]8f5a7e492012-01-01 02:14:47115
[email protected]59e69e742013-06-18 20:27:52116 Time future = last_time + TimeDelta::FromMilliseconds(delay_ms);
tzika8cc2202017-04-18 07:01:15117 EventInjector::Event event = {future, std::move(callback), std::move(task)};
118 events_.push_back(std::move(event));
[email protected]763839e2011-12-09 23:06:02119 }
120
[email protected]b44d5cc2009-06-15 10:30:44121 static gboolean Prepare(GSource* source, gint* timeout_ms) {
122 *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare();
123 return FALSE;
124 }
125
126 static gboolean Check(GSource* source) {
127 return static_cast<Source*>(source)->injector->HandleCheck();
128 }
129
130 static gboolean Dispatch(GSource* source,
131 GSourceFunc unused_func,
132 gpointer unused_data) {
133 static_cast<Source*>(source)->injector->HandleDispatch();
134 return TRUE;
135 }
136
137 Source* source_;
138 std::vector<Event> events_;
139 int processed_events_;
140 static GSourceFuncs SourceFuncs;
141 DISALLOW_COPY_AND_ASSIGN(EventInjector);
142};
143
Ivan Kotenkova16212a52017-11-08 12:37:33144GSourceFuncs EventInjector::SourceFuncs = {EventInjector::Prepare,
145 EventInjector::Check,
146 EventInjector::Dispatch, nullptr};
[email protected]b44d5cc2009-06-15 10:30:44147
[email protected]b44d5cc2009-06-15 10:30:44148void IncrementInt(int *value) {
149 ++*value;
150}
151
152// Checks how many events have been processed by the injector.
153void ExpectProcessedEvents(EventInjector* injector, int count) {
154 EXPECT_EQ(injector->processed_events(), count);
155}
156
[email protected]b44d5cc2009-06-15 10:30:44157// Posts a task on the current message loop.
Brett Wilson8e88b312017-09-12 05:22:16158void PostMessageLoopTask(const Location& from_here, OnceClosure task) {
tzika8cc2202017-04-18 07:01:15159 ThreadTaskRunnerHandle::Get()->PostTask(from_here, std::move(task));
[email protected]b44d5cc2009-06-15 10:30:44160}
161
162// Test fixture.
163class MessagePumpGLibTest : public testing::Test {
164 public:
Ivan Kotenkova16212a52017-11-08 12:37:33165 MessagePumpGLibTest() : loop_(nullptr), injector_(nullptr) {}
[email protected]b44d5cc2009-06-15 10:30:44166
[email protected]c19003d2012-07-31 01:38:18167 // Overridden from testing::Test:
dcheng8aef37612014-12-23 02:56:47168 void SetUp() override {
Carlos Caballerodd8bf7b042019-07-30 14:14:15169 loop_ = new MessageLoop(MessagePumpType::UI);
[email protected]b44d5cc2009-06-15 10:30:44170 injector_ = new EventInjector();
171 }
dcheng8aef37612014-12-23 02:56:47172 void TearDown() override {
[email protected]b44d5cc2009-06-15 10:30:44173 delete injector_;
Ivan Kotenkova16212a52017-11-08 12:37:33174 injector_ = nullptr;
[email protected]b44d5cc2009-06-15 10:30:44175 delete loop_;
Ivan Kotenkova16212a52017-11-08 12:37:33176 loop_ = nullptr;
[email protected]b44d5cc2009-06-15 10:30:44177 }
178
179 MessageLoop* loop() const { return loop_; }
180 EventInjector* injector() const { return injector_; }
181
182 private:
183 MessageLoop* loop_;
184 EventInjector* injector_;
185 DISALLOW_COPY_AND_ASSIGN(MessagePumpGLibTest);
186};
187
188} // namespace
189
[email protected]b44d5cc2009-06-15 10:30:44190TEST_F(MessagePumpGLibTest, TestQuit) {
191 // Checks that Quit works and that the basic infrastructure is working.
192
193 // Quit from a task
[email protected]7ff48ca2013-02-06 16:56:19194 RunLoop().RunUntilIdle();
[email protected]b44d5cc2009-06-15 10:30:44195 EXPECT_EQ(0, injector()->processed_events());
196
197 injector()->Reset();
198 // Quit from an event
Wezfda077b2018-06-07 21:18:11199 RunLoop run_loop;
200 injector()->AddEvent(0, run_loop.QuitClosure());
201 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44202 EXPECT_EQ(1, injector()->processed_events());
203}
204
205TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) {
206 // Checks that tasks posted by events are executed before the next event if
207 // the posted task queue is empty.
208 // MessageLoop doesn't make strong guarantees that it is the case, but the
209 // current implementation ensures it and the tests below rely on it.
210 // If changes cause this test to fail, it is reasonable to change it, but
211 // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be
212 // changed accordingly, otherwise they can become flaky.
Peter Kasting341e1fb2018-02-24 00:03:01213 injector()->AddEventAsTask(0, DoNothing());
tzika8cc2202017-04-18 07:01:15214 OnceClosure check_task =
215 BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2);
216 OnceClosure posted_task =
217 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
218 injector()->AddEventAsTask(0, std::move(posted_task));
Peter Kasting341e1fb2018-02-24 00:03:01219 injector()->AddEventAsTask(0, DoNothing());
Wezfda077b2018-06-07 21:18:11220 {
221 RunLoop run_loop;
222 injector()->AddEvent(0, run_loop.QuitClosure());
223 run_loop.Run();
224 }
[email protected]b44d5cc2009-06-15 10:30:44225 EXPECT_EQ(4, injector()->processed_events());
226
227 injector()->Reset();
Peter Kasting341e1fb2018-02-24 00:03:01228 injector()->AddEventAsTask(0, DoNothing());
tzika8cc2202017-04-18 07:01:15229 check_task = BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2);
230 posted_task =
231 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
232 injector()->AddEventAsTask(0, std::move(posted_task));
Peter Kasting341e1fb2018-02-24 00:03:01233 injector()->AddEventAsTask(10, DoNothing());
Wezfda077b2018-06-07 21:18:11234 {
235 RunLoop run_loop;
236 injector()->AddEvent(0, run_loop.QuitClosure());
237 run_loop.Run();
238 }
[email protected]b44d5cc2009-06-15 10:30:44239 EXPECT_EQ(4, injector()->processed_events());
240}
241
242TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) {
243 int task_count = 0;
244 // Tests that we process tasks while waiting for new events.
245 // The event queue is empty at first.
246 for (int i = 0; i < 10; ++i) {
fdoray6ef45cf2016-08-25 15:36:37247 loop()->task_runner()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44248 BindOnce(&IncrementInt, &task_count));
[email protected]b44d5cc2009-06-15 10:30:44249 }
250 // After all the previous tasks have executed, enqueue an event that will
251 // quit.
Wezfda077b2018-06-07 21:18:11252 {
253 RunLoop run_loop;
254 loop()->task_runner()->PostTask(
255 FROM_HERE, BindOnce(&EventInjector::AddEvent, Unretained(injector()), 0,
256 run_loop.QuitClosure()));
257 run_loop.Run();
258 }
[email protected]b44d5cc2009-06-15 10:30:44259 ASSERT_EQ(10, task_count);
260 EXPECT_EQ(1, injector()->processed_events());
261
262 // Tests that we process delayed tasks while waiting for new events.
263 injector()->Reset();
264 task_count = 0;
265 for (int i = 0; i < 10; ++i) {
fdoray6ef45cf2016-08-25 15:36:37266 loop()->task_runner()->PostDelayedTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44267 BindOnce(&IncrementInt, &task_count),
fdoray6ef45cf2016-08-25 15:36:37268 TimeDelta::FromMilliseconds(10 * i));
[email protected]b44d5cc2009-06-15 10:30:44269 }
270 // After all the previous tasks have executed, enqueue an event that will
271 // quit.
272 // This relies on the fact that delayed tasks are executed in delay order.
273 // That is verified in message_loop_unittest.cc.
Wezfda077b2018-06-07 21:18:11274 {
275 RunLoop run_loop;
276 loop()->task_runner()->PostDelayedTask(
277 FROM_HERE,
278 BindOnce(&EventInjector::AddEvent, Unretained(injector()), 0,
279 run_loop.QuitClosure()),
280 TimeDelta::FromMilliseconds(150));
281 run_loop.Run();
282 }
[email protected]b44d5cc2009-06-15 10:30:44283 ASSERT_EQ(10, task_count);
284 EXPECT_EQ(1, injector()->processed_events());
285}
286
287TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) {
288 // Tests that we process events while waiting for work.
289 // The event queue is empty at first.
290 for (int i = 0; i < 10; ++i) {
[email protected]763839e2011-12-09 23:06:02291 injector()->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44292 }
293 // After all the events have been processed, post a task that will check that
294 // the events have been processed (note: the task executes after the event
295 // that posted it has been handled, so we expect 11 at that point).
tzika8cc2202017-04-18 07:01:15296 OnceClosure check_task =
297 BindOnce(&ExpectProcessedEvents, Unretained(injector()), 11);
298 OnceClosure posted_task =
299 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
300 injector()->AddEventAsTask(10, std::move(posted_task));
[email protected]b44d5cc2009-06-15 10:30:44301
302 // And then quit (relies on the condition tested by TestEventTaskInterleave).
Wezfda077b2018-06-07 21:18:11303 RunLoop run_loop;
304 injector()->AddEvent(10, run_loop.QuitClosure());
305 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44306
307 EXPECT_EQ(12, injector()->processed_events());
308}
309
310namespace {
311
312// This class is a helper for the concurrent events / posted tasks test below.
313// It will quit the main loop once enough tasks and events have been processed,
314// while making sure there is always work to do and events in the queue.
[email protected]59e69e742013-06-18 20:27:52315class ConcurrentHelper : public RefCounted<ConcurrentHelper> {
[email protected]b44d5cc2009-06-15 10:30:44316 public:
Wezfda077b2018-06-07 21:18:11317 ConcurrentHelper(EventInjector* injector, OnceClosure done_closure)
[email protected]b44d5cc2009-06-15 10:30:44318 : injector_(injector),
Wezfda077b2018-06-07 21:18:11319 done_closure_(std::move(done_closure)),
[email protected]b44d5cc2009-06-15 10:30:44320 event_count_(kStartingEventCount),
Wezfda077b2018-06-07 21:18:11321 task_count_(kStartingTaskCount) {}
[email protected]b44d5cc2009-06-15 10:30:44322
323 void FromTask() {
324 if (task_count_ > 0) {
325 --task_count_;
326 }
327 if (task_count_ == 0 && event_count_ == 0) {
Wezfda077b2018-06-07 21:18:11328 std::move(done_closure_).Run();
[email protected]b44d5cc2009-06-15 10:30:44329 } else {
fdoray2df4a9e2016-07-18 23:47:16330 ThreadTaskRunnerHandle::Get()->PostTask(
tzik92b7a422017-04-11 15:00:44331 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, this));
[email protected]b44d5cc2009-06-15 10:30:44332 }
333 }
334
335 void FromEvent() {
336 if (event_count_ > 0) {
337 --event_count_;
338 }
339 if (task_count_ == 0 && event_count_ == 0) {
Wezfda077b2018-06-07 21:18:11340 std::move(done_closure_).Run();
[email protected]b44d5cc2009-06-15 10:30:44341 } else {
tzika8cc2202017-04-18 07:01:15342 injector_->AddEventAsTask(0,
343 BindOnce(&ConcurrentHelper::FromEvent, this));
[email protected]b44d5cc2009-06-15 10:30:44344 }
345 }
346
347 int event_count() const { return event_count_; }
348 int task_count() const { return task_count_; }
349
350 private:
[email protected]59e69e742013-06-18 20:27:52351 friend class RefCounted<ConcurrentHelper>;
[email protected]877d55d2009-11-05 21:53:08352
353 ~ConcurrentHelper() {}
354
[email protected]b44d5cc2009-06-15 10:30:44355 static const int kStartingEventCount = 20;
356 static const int kStartingTaskCount = 20;
357
358 EventInjector* injector_;
Wezfda077b2018-06-07 21:18:11359 OnceClosure done_closure_;
[email protected]b44d5cc2009-06-15 10:30:44360 int event_count_;
361 int task_count_;
362};
363
364} // namespace
365
366TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) {
367 // Tests that posted tasks don't starve events, nor the opposite.
368 // We use the helper class above. We keep both event and posted task queues
369 // full, the helper verifies that both tasks and events get processed.
370 // If that is not the case, either event_count_ or task_count_ will not get
[email protected]91cae2592013-01-10 14:56:17371 // to 0, and MessageLoop::QuitWhenIdle() will never be called.
Wezfda077b2018-06-07 21:18:11372 RunLoop run_loop;
373 scoped_refptr<ConcurrentHelper> helper =
374 new ConcurrentHelper(injector(), run_loop.QuitClosure());
[email protected]b44d5cc2009-06-15 10:30:44375
376 // Add 2 events to the queue to make sure it is always full (when we remove
377 // the event before processing it).
tzika8cc2202017-04-18 07:01:15378 injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper));
379 injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper));
[email protected]b44d5cc2009-06-15 10:30:44380
381 // Similarly post 2 tasks.
fdoray6ef45cf2016-08-25 15:36:37382 loop()->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44383 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper));
fdoray6ef45cf2016-08-25 15:36:37384 loop()->task_runner()->PostTask(
tzik92b7a422017-04-11 15:00:44385 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper));
[email protected]b44d5cc2009-06-15 10:30:44386
Wezfda077b2018-06-07 21:18:11387 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44388 EXPECT_EQ(0, helper->event_count());
389 EXPECT_EQ(0, helper->task_count());
390}
391
392namespace {
393
Wezfda077b2018-06-07 21:18:11394void AddEventsAndDrainGLib(EventInjector* injector, OnceClosure on_drained) {
[email protected]b44d5cc2009-06-15 10:30:44395 // Add a couple of dummy events
[email protected]763839e2011-12-09 23:06:02396 injector->AddDummyEvent(0);
397 injector->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44398 // Then add an event that will quit the main loop.
Wezfda077b2018-06-07 21:18:11399 injector->AddEvent(0, std::move(on_drained));
[email protected]b44d5cc2009-06-15 10:30:44400
401 // Post a couple of dummy tasks
Peter Kasting341e1fb2018-02-24 00:03:01402 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
403 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, DoNothing());
[email protected]b44d5cc2009-06-15 10:30:44404
405 // Drain the events
Ivan Kotenkova16212a52017-11-08 12:37:33406 while (g_main_context_pending(nullptr)) {
407 g_main_context_iteration(nullptr, FALSE);
[email protected]b44d5cc2009-06-15 10:30:44408 }
409}
410
411} // namespace
412
413TEST_F(MessagePumpGLibTest, TestDrainingGLib) {
414 // Tests that draining events using GLib works.
Wezfda077b2018-06-07 21:18:11415 RunLoop run_loop;
fdoray6ef45cf2016-08-25 15:36:37416 loop()->task_runner()->PostTask(
Wezfda077b2018-06-07 21:18:11417 FROM_HERE, BindOnce(&AddEventsAndDrainGLib, Unretained(injector()),
418 run_loop.QuitClosure()));
419 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44420
421 EXPECT_EQ(3, injector()->processed_events());
422}
423
[email protected]b44d5cc2009-06-15 10:30:44424namespace {
425
426// Helper class that lets us run the GLib message loop.
[email protected]59e69e742013-06-18 20:27:52427class GLibLoopRunner : public RefCounted<GLibLoopRunner> {
[email protected]b44d5cc2009-06-15 10:30:44428 public:
429 GLibLoopRunner() : quit_(false) { }
430
431 void RunGLib() {
432 while (!quit_) {
Ivan Kotenkova16212a52017-11-08 12:37:33433 g_main_context_iteration(nullptr, TRUE);
[email protected]b44d5cc2009-06-15 10:30:44434 }
435 }
436
[email protected]258dca42011-09-21 00:17:19437 void RunLoop() {
[email protected]258dca42011-09-21 00:17:19438 while (!quit_) {
Ivan Kotenkova16212a52017-11-08 12:37:33439 g_main_context_iteration(nullptr, TRUE);
[email protected]258dca42011-09-21 00:17:19440 }
[email protected]b44d5cc2009-06-15 10:30:44441 }
442
443 void Quit() {
444 quit_ = true;
445 }
446
447 void Reset() {
448 quit_ = false;
449 }
450
451 private:
[email protected]59e69e742013-06-18 20:27:52452 friend class RefCounted<GLibLoopRunner>;
[email protected]877d55d2009-11-05 21:53:08453
454 ~GLibLoopRunner() {}
455
[email protected]b44d5cc2009-06-15 10:30:44456 bool quit_;
457};
458
Wezfda077b2018-06-07 21:18:11459void TestGLibLoopInternal(EventInjector* injector, OnceClosure done) {
[email protected]b44d5cc2009-06-15 10:30:44460 // Allow tasks to be processed from 'native' event loops.
Gabriel Charette810f3f432018-04-27 22:28:14461 MessageLoopCurrent::Get()->SetNestableTasksAllowed(true);
[email protected]b44d5cc2009-06-15 10:30:44462 scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
463
464 int task_count = 0;
465 // Add a couple of dummy events
[email protected]763839e2011-12-09 23:06:02466 injector->AddDummyEvent(0);
467 injector->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44468 // Post a couple of dummy tasks
fdoray2df4a9e2016-07-18 23:47:16469 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44470 BindOnce(&IncrementInt, &task_count));
fdoray2df4a9e2016-07-18 23:47:16471 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44472 BindOnce(&IncrementInt, &task_count));
[email protected]b44d5cc2009-06-15 10:30:44473 // Delayed events
[email protected]763839e2011-12-09 23:06:02474 injector->AddDummyEvent(10);
475 injector->AddDummyEvent(10);
[email protected]b44d5cc2009-06-15 10:30:44476 // Delayed work
fdoray2df4a9e2016-07-18 23:47:16477 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44478 FROM_HERE, BindOnce(&IncrementInt, &task_count),
[email protected]59e69e742013-06-18 20:27:52479 TimeDelta::FromMilliseconds(30));
fdoray2df4a9e2016-07-18 23:47:16480 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44481 FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner),
[email protected]59e69e742013-06-18 20:27:52482 TimeDelta::FromMilliseconds(40));
[email protected]b44d5cc2009-06-15 10:30:44483
484 // Run a nested, straight GLib message loop.
485 runner->RunGLib();
486
487 ASSERT_EQ(3, task_count);
488 EXPECT_EQ(4, injector->processed_events());
Wezfda077b2018-06-07 21:18:11489 std::move(done).Run();
[email protected]b44d5cc2009-06-15 10:30:44490}
491
Wezfda077b2018-06-07 21:18:11492void TestGtkLoopInternal(EventInjector* injector, OnceClosure done) {
[email protected]b44d5cc2009-06-15 10:30:44493 // Allow tasks to be processed from 'native' event loops.
Gabriel Charette810f3f432018-04-27 22:28:14494 MessageLoopCurrent::Get()->SetNestableTasksAllowed(true);
[email protected]b44d5cc2009-06-15 10:30:44495 scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
496
497 int task_count = 0;
498 // Add a couple of dummy events
[email protected]763839e2011-12-09 23:06:02499 injector->AddDummyEvent(0);
500 injector->AddDummyEvent(0);
[email protected]b44d5cc2009-06-15 10:30:44501 // Post a couple of dummy tasks
fdoray2df4a9e2016-07-18 23:47:16502 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44503 BindOnce(&IncrementInt, &task_count));
fdoray2df4a9e2016-07-18 23:47:16504 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
tzik92b7a422017-04-11 15:00:44505 BindOnce(&IncrementInt, &task_count));
[email protected]b44d5cc2009-06-15 10:30:44506 // Delayed events
[email protected]763839e2011-12-09 23:06:02507 injector->AddDummyEvent(10);
508 injector->AddDummyEvent(10);
[email protected]b44d5cc2009-06-15 10:30:44509 // Delayed work
fdoray2df4a9e2016-07-18 23:47:16510 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44511 FROM_HERE, BindOnce(&IncrementInt, &task_count),
[email protected]59e69e742013-06-18 20:27:52512 TimeDelta::FromMilliseconds(30));
fdoray2df4a9e2016-07-18 23:47:16513 ThreadTaskRunnerHandle::Get()->PostDelayedTask(
tzik92b7a422017-04-11 15:00:44514 FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner),
[email protected]59e69e742013-06-18 20:27:52515 TimeDelta::FromMilliseconds(40));
[email protected]b44d5cc2009-06-15 10:30:44516
517 // Run a nested, straight Gtk message loop.
[email protected]258dca42011-09-21 00:17:19518 runner->RunLoop();
[email protected]b44d5cc2009-06-15 10:30:44519
520 ASSERT_EQ(3, task_count);
521 EXPECT_EQ(4, injector->processed_events());
Wezfda077b2018-06-07 21:18:11522 std::move(done).Run();
[email protected]b44d5cc2009-06-15 10:30:44523}
524
525} // namespace
526
527TEST_F(MessagePumpGLibTest, TestGLibLoop) {
[email protected]8f5a7e492012-01-01 02:14:47528 // Tests that events and posted tasks are correctly executed if the message
[email protected]b44d5cc2009-06-15 10:30:44529 // loop is not run by MessageLoop::Run() but by a straight GLib loop.
530 // Note that in this case we don't make strong guarantees about niceness
531 // between events and posted tasks.
Wezfda077b2018-06-07 21:18:11532 RunLoop run_loop;
fdoray6ef45cf2016-08-25 15:36:37533 loop()->task_runner()->PostTask(
Wezfda077b2018-06-07 21:18:11534 FROM_HERE, BindOnce(&TestGLibLoopInternal, Unretained(injector()),
535 run_loop.QuitClosure()));
536 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44537}
538
539TEST_F(MessagePumpGLibTest, TestGtkLoop) {
[email protected]8f5a7e492012-01-01 02:14:47540 // Tests that events and posted tasks are correctly executed if the message
[email protected]b44d5cc2009-06-15 10:30:44541 // loop is not run by MessageLoop::Run() but by a straight Gtk loop.
542 // Note that in this case we don't make strong guarantees about niceness
543 // between events and posted tasks.
Wezfda077b2018-06-07 21:18:11544 RunLoop run_loop;
fdoray6ef45cf2016-08-25 15:36:37545 loop()->task_runner()->PostTask(
Wezfda077b2018-06-07 21:18:11546 FROM_HERE, BindOnce(&TestGtkLoopInternal, Unretained(injector()),
547 run_loop.QuitClosure()));
548 run_loop.Run();
[email protected]b44d5cc2009-06-15 10:30:44549}
[email protected]7ff48ca2013-02-06 16:56:19550
Nick Diego Yamane58914192019-08-08 17:12:48551// Tests for WatchFileDescriptor API
552class MessagePumpGLibFdWatchTest : public testing::Test {
553 protected:
554 MessagePumpGLibFdWatchTest()
555 : io_thread_("MessagePumpGLibFdWatchTestIOThread") {}
556 ~MessagePumpGLibFdWatchTest() override = default;
557
558 void SetUp() override {
559 Thread::Options options(MessagePumpType::IO, 0);
560 ASSERT_TRUE(io_thread_.StartWithOptions(options));
561 int ret = pipe(pipefds_);
562 ASSERT_EQ(0, ret);
563 }
564
565 void TearDown() override {
566 if (IGNORE_EINTR(close(pipefds_[0])) < 0)
567 PLOG(ERROR) << "close";
568 if (IGNORE_EINTR(close(pipefds_[1])) < 0)
569 PLOG(ERROR) << "close";
570 }
571
572 void WaitUntilIoThreadStarted() {
573 ASSERT_TRUE(io_thread_.WaitUntilThreadStarted());
574 }
575
576 scoped_refptr<SingleThreadTaskRunner> io_runner() const {
577 return io_thread_.task_runner();
578 }
579
580 void SimulateEvent(MessagePumpGlib* pump,
581 MessagePumpGlib::FdWatchController* controller) {
582 controller->poll_fd_->revents = G_IO_IN | G_IO_OUT;
583 pump->HandleFdWatchDispatch(controller);
584 }
585
586 int pipefds_[2];
587
588 private:
589 Thread io_thread_;
590};
591
592namespace {
593
594class BaseWatcher : public MessagePumpGlib::FdWatcher {
595 public:
596 explicit BaseWatcher(MessagePumpGlib::FdWatchController* controller)
597 : controller_(controller) {
598 DCHECK(controller_);
599 }
600 ~BaseWatcher() override = default;
601
602 // base:MessagePumpGlib::FdWatcher interface
603 void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); }
604 void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); }
605
606 protected:
607 MessagePumpGlib::FdWatchController* controller_;
608};
609
610class DeleteWatcher : public BaseWatcher {
611 public:
612 explicit DeleteWatcher(
613 std::unique_ptr<MessagePumpGlib::FdWatchController> controller)
614 : BaseWatcher(controller.get()),
615 owned_controller_(std::move(controller)) {}
616
617 ~DeleteWatcher() override { DCHECK(!controller_); }
618
619 void OnFileCanWriteWithoutBlocking(int /* fd */) override {
620 DCHECK(owned_controller_);
621 owned_controller_.reset();
622 controller_ = nullptr;
623 }
624
625 private:
626 std::unique_ptr<MessagePumpGlib::FdWatchController> owned_controller_;
627};
628
629class StopWatcher : public BaseWatcher {
630 public:
631 explicit StopWatcher(MessagePumpGlib::FdWatchController* controller)
632 : BaseWatcher(controller) {}
633
634 ~StopWatcher() override = default;
635
636 void OnFileCanWriteWithoutBlocking(int /* fd */) override {
637 controller_->StopWatchingFileDescriptor();
638 }
639};
640
641void QuitMessageLoopAndStart(OnceClosure quit_closure) {
642 std::move(quit_closure).Run();
643
644 RunLoop runloop(RunLoop::Type::kNestableTasksAllowed);
645 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, runloop.QuitClosure());
646 runloop.Run();
647}
648
649class NestedPumpWatcher : public MessagePumpGlib::FdWatcher {
650 public:
651 NestedPumpWatcher() = default;
652 ~NestedPumpWatcher() override = default;
653
654 void OnFileCanReadWithoutBlocking(int /* fd */) override {
655 RunLoop runloop;
656 ThreadTaskRunnerHandle::Get()->PostTask(
657 FROM_HERE, BindOnce(&QuitMessageLoopAndStart, runloop.QuitClosure()));
658 runloop.Run();
659 }
660
661 void OnFileCanWriteWithoutBlocking(int /* fd */) override {}
662};
663
664class QuitWatcher : public BaseWatcher {
665 public:
666 QuitWatcher(MessagePumpGlib::FdWatchController* controller,
667 base::OnceClosure quit_closure)
668 : BaseWatcher(controller), quit_closure_(std::move(quit_closure)) {}
669
670 void OnFileCanReadWithoutBlocking(int /* fd */) override {
671 if (quit_closure_)
672 std::move(quit_closure_).Run();
673 }
674
675 private:
676 base::OnceClosure quit_closure_;
677};
678
679void WriteFDWrapper(const int fd,
680 const char* buf,
681 int size,
682 WaitableEvent* event) {
683 ASSERT_TRUE(WriteFileDescriptor(fd, buf, size));
684}
685
686} // namespace
687
688// Tests that MessagePumpGlib::FdWatcher::OnFileCanReadWithoutBlocking is not
689// called for a READ_WRITE event, when the controller is destroyed in
690// OnFileCanWriteWithoutBlocking callback.
691TEST_F(MessagePumpGLibFdWatchTest, DeleteWatcher) {
692 auto pump = std::make_unique<MessagePumpGlib>();
693 auto controller_ptr =
694 std::make_unique<MessagePumpGlib::FdWatchController>(FROM_HERE);
695 auto* controller = controller_ptr.get();
696
697 DeleteWatcher watcher(std::move(controller_ptr));
698 pump->WatchFileDescriptor(pipefds_[1], false,
699 MessagePumpGlib::WATCH_READ_WRITE, controller,
700 &watcher);
701
702 SimulateEvent(pump.get(), controller);
703}
704
705// Tests that MessagePumpGlib::FdWatcher::OnFileCanReadWithoutBlocking is not
706// called for a READ_WRITE event, when the watcher calls
707// StopWatchingFileDescriptor in OnFileCanWriteWithoutBlocking callback.
708TEST_F(MessagePumpGLibFdWatchTest, StopWatcher) {
709 std::unique_ptr<MessagePumpGlib> pump(new MessagePumpGlib);
710 MessagePumpGlib::FdWatchController controller(FROM_HERE);
711 StopWatcher watcher(&controller);
712 pump->WatchFileDescriptor(pipefds_[1], false,
713 MessagePumpGlib::WATCH_READ_WRITE, &controller,
714 &watcher);
715
716 SimulateEvent(pump.get(), &controller);
717}
718
719// Tests that FdWatcher works properly with nested loops.
720TEST_F(MessagePumpGLibFdWatchTest, NestedPumpWatcher) {
721 MessageLoop loop(MessagePumpType::UI);
722 std::unique_ptr<MessagePumpGlib> pump(new MessagePumpGlib);
723 MessagePumpGlib::FdWatchController controller(FROM_HERE);
724 NestedPumpWatcher watcher;
725 pump->WatchFileDescriptor(pipefds_[1], false, MessagePumpGlib::WATCH_READ,
726 &controller, &watcher);
727
728 SimulateEvent(pump.get(), &controller);
729}
730
731// Tests that MessagePumpGlib quits immediately when it is quit from
732// libevent's event_base_loop().
733TEST_F(MessagePumpGLibFdWatchTest, QuitWatcher) {
734 auto pump_ptr = std::make_unique<MessagePumpGlib>();
735 MessagePumpGlib* pump = pump_ptr.get();
736 MessageLoop loop(std::move(pump_ptr));
737 RunLoop run_loop;
738 MessagePumpGlib::FdWatchController controller(FROM_HERE);
739 QuitWatcher delegate(&controller, run_loop.QuitClosure());
740 WaitableEvent event;
741 auto watcher = std::make_unique<WaitableEventWatcher>();
742
743 pump->WatchFileDescriptor(pipefds_[0], false, MessagePumpGlib::WATCH_READ,
744 &controller, &delegate);
745
746 // Make the IO thread wait for |event| before writing to pipefds[1].
747 const char buf = 0;
748 WaitableEventWatcher::EventCallback write_fd_task =
749 BindOnce(&WriteFDWrapper, pipefds_[1], &buf, 1);
750 io_runner()->PostTask(
751 FROM_HERE, BindOnce(IgnoreResult(&WaitableEventWatcher::StartWatching),
752 Unretained(watcher.get()), &event,
753 std::move(write_fd_task), io_runner()));
754
755 // Queue |event| to signal on |MessageLoopCurrentForUI::Get()|.
756 ThreadTaskRunnerHandle::Get()->PostTask(
757 FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&event)));
758
759 // Now run the MessageLoop.
760 run_loop.Run();
761
762 // StartWatching can move |watcher| to IO thread. Release on IO thread.
763 io_runner()->PostTask(FROM_HERE, BindOnce(&WaitableEventWatcher::StopWatching,
764 Owned(std::move(watcher))));
765}
766
[email protected]7ff48ca2013-02-06 16:56:19767} // namespace base