1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/message_loop/message_pump_glib.h"
6
7 #include <glib.h>
8 #include <math.h>
9 #include "build/build_config.h"
10
11 #include <algorithm>
12 #include <vector>
13
14 #include "base/files/file_util.h"
15 #include "base/functional/bind.h"
16 #include "base/functional/callback.h"
17 #include "base/functional/callback_helpers.h"
18 #include "base/logging.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/memory/raw_ptr.h"
21 #include "base/memory/ref_counted.h"
22 #include "base/message_loop/message_pump_type.h"
23 #include "base/posix/eintr_wrapper.h"
24 #include "base/run_loop.h"
25 #include "base/synchronization/waitable_event.h"
26 #include "base/synchronization/waitable_event_watcher.h"
27 #include "base/task/current_thread.h"
28 #include "base/task/single_thread_task_executor.h"
29 #include "base/task/single_thread_task_runner.h"
30 #include "base/test/task_environment.h"
31 #include "base/test/trace_event_analyzer.h"
32 #include "base/threading/thread.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34
35 namespace base {
36 namespace {
37
38 // This class injects dummy "events" into the GLib loop. When "handled" these
39 // events can run tasks. This is intended to mock gtk events (the corresponding
40 // GLib source runs at the same priority).
41 class EventInjector {
42 public:
EventInjector()43 EventInjector() : processed_events_(0) {
44 source_ = static_cast<Source*>(g_source_new(&SourceFuncs, sizeof(Source)));
45 source_->injector = this;
46 g_source_attach(source_, nullptr);
47 g_source_set_can_recurse(source_, TRUE);
48 }
49
50 EventInjector(const EventInjector&) = delete;
51 EventInjector& operator=(const EventInjector&) = delete;
52
~EventInjector()53 ~EventInjector() {
54 g_source_destroy(source_);
55 g_source_unref(source_.ExtractAsDangling());
56 }
57
HandlePrepare()58 int HandlePrepare() {
59 // If the queue is empty, block.
60 if (events_.empty())
61 return -1;
62 TimeDelta delta = events_[0].time - Time::NowFromSystemTime();
63 return std::max(0, static_cast<int>(ceil(delta.InMillisecondsF())));
64 }
65
HandleCheck()66 bool HandleCheck() {
67 if (events_.empty())
68 return false;
69 return events_[0].time <= Time::NowFromSystemTime();
70 }
71
HandleDispatch()72 void HandleDispatch() {
73 if (events_.empty())
74 return;
75 Event event = std::move(events_[0]);
76 events_.erase(events_.begin());
77 ++processed_events_;
78 if (!event.callback.is_null())
79 std::move(event.callback).Run();
80 else if (!event.task.is_null())
81 std::move(event.task).Run();
82 }
83
84 // Adds an event to the queue. When "handled", executes |callback|.
85 // delay_ms is relative to the last event if any, or to Now() otherwise.
AddEvent(int delay_ms,OnceClosure callback)86 void AddEvent(int delay_ms, OnceClosure callback) {
87 AddEventHelper(delay_ms, std::move(callback), OnceClosure());
88 }
89
AddDummyEvent(int delay_ms)90 void AddDummyEvent(int delay_ms) {
91 AddEventHelper(delay_ms, OnceClosure(), OnceClosure());
92 }
93
AddEventAsTask(int delay_ms,OnceClosure task)94 void AddEventAsTask(int delay_ms, OnceClosure task) {
95 AddEventHelper(delay_ms, OnceClosure(), std::move(task));
96 }
97
Reset()98 void Reset() {
99 processed_events_ = 0;
100 events_.clear();
101 }
102
processed_events() const103 int processed_events() const { return processed_events_; }
104
105 private:
106 struct Event {
107 Time time;
108 OnceClosure callback;
109 OnceClosure task;
110 };
111
112 struct Source : public GSource {
113 raw_ptr<EventInjector> injector;
114 };
115
AddEventHelper(int delay_ms,OnceClosure callback,OnceClosure task)116 void AddEventHelper(int delay_ms, OnceClosure callback, OnceClosure task) {
117 Time last_time;
118 if (!events_.empty())
119 last_time = (events_.end()-1)->time;
120 else
121 last_time = Time::NowFromSystemTime();
122
123 Time future = last_time + Milliseconds(delay_ms);
124 EventInjector::Event event = {future, std::move(callback), std::move(task)};
125 events_.push_back(std::move(event));
126 }
127
Prepare(GSource * source,gint * timeout_ms)128 static gboolean Prepare(GSource* source, gint* timeout_ms) {
129 *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare();
130 return FALSE;
131 }
132
Check(GSource * source)133 static gboolean Check(GSource* source) {
134 return static_cast<Source*>(source)->injector->HandleCheck();
135 }
136
Dispatch(GSource * source,GSourceFunc unused_func,gpointer unused_data)137 static gboolean Dispatch(GSource* source,
138 GSourceFunc unused_func,
139 gpointer unused_data) {
140 static_cast<Source*>(source)->injector->HandleDispatch();
141 return TRUE;
142 }
143
Finalize(GSource * source)144 static void Finalize(GSource* source) {
145 // Since the Source object memory is managed by glib, Source implicit
146 // destructor is never called, and thus Source's raw_ptr never release its
147 // internal reference on the pump pointer. This leads to adding pressure to
148 // the BackupRefPtr quarantine.
149 static_cast<Source*>(source)->injector = nullptr;
150 }
151
152 raw_ptr<Source> source_;
153 std::vector<Event> events_;
154 int processed_events_;
155 static GSourceFuncs SourceFuncs;
156 };
157
158 GSourceFuncs EventInjector::SourceFuncs = {
159 EventInjector::Prepare,
160 EventInjector::Check,
161 EventInjector::Dispatch,
162 EventInjector::Finalize,
163 };
164
IncrementInt(int * value)165 void IncrementInt(int *value) {
166 ++*value;
167 }
168
169 // Checks how many events have been processed by the injector.
ExpectProcessedEvents(EventInjector * injector,int count)170 void ExpectProcessedEvents(EventInjector* injector, int count) {
171 EXPECT_EQ(injector->processed_events(), count);
172 }
173
174 // Posts a task on the current message loop.
PostMessageLoopTask(const Location & from_here,OnceClosure task)175 void PostMessageLoopTask(const Location& from_here, OnceClosure task) {
176 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(from_here,
177 std::move(task));
178 }
179
180 // Test fixture.
181 class MessagePumpGLibTest : public testing::Test {
182 public:
183 MessagePumpGLibTest() = default;
184
185 MessagePumpGLibTest(const MessagePumpGLibTest&) = delete;
186 MessagePumpGLibTest& operator=(const MessagePumpGLibTest&) = delete;
187
injector()188 EventInjector* injector() { return &injector_; }
189
190 private:
191 test::SingleThreadTaskEnvironment task_environment_{
192 test::SingleThreadTaskEnvironment::MainThreadType::UI};
193 EventInjector injector_;
194 };
195
196 } // namespace
197
TEST_F(MessagePumpGLibTest,TestQuit)198 TEST_F(MessagePumpGLibTest, TestQuit) {
199 // Checks that Quit works and that the basic infrastructure is working.
200
201 // Quit from a task
202 RunLoop().RunUntilIdle();
203 EXPECT_EQ(0, injector()->processed_events());
204
205 injector()->Reset();
206 // Quit from an event
207 RunLoop run_loop;
208 injector()->AddEvent(0, run_loop.QuitClosure());
209 run_loop.Run();
210 EXPECT_EQ(1, injector()->processed_events());
211 }
212
TEST_F(MessagePumpGLibTest,TestEventTaskInterleave)213 TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) {
214 // Checks that tasks posted by events are executed before the next event if
215 // the posted task queue is empty.
216 // MessageLoop doesn't make strong guarantees that it is the case, but the
217 // current implementation ensures it and the tests below rely on it.
218 // If changes cause this test to fail, it is reasonable to change it, but
219 // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be
220 // changed accordingly, otherwise they can become flaky.
221 injector()->AddEventAsTask(0, DoNothing());
222 OnceClosure check_task =
223 BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2);
224 OnceClosure posted_task =
225 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
226 injector()->AddEventAsTask(0, std::move(posted_task));
227 injector()->AddEventAsTask(0, DoNothing());
228 {
229 RunLoop run_loop;
230 injector()->AddEvent(0, run_loop.QuitClosure());
231 run_loop.Run();
232 }
233 EXPECT_EQ(4, injector()->processed_events());
234
235 injector()->Reset();
236 injector()->AddEventAsTask(0, DoNothing());
237 check_task = BindOnce(&ExpectProcessedEvents, Unretained(injector()), 2);
238 posted_task =
239 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
240 injector()->AddEventAsTask(0, std::move(posted_task));
241 injector()->AddEventAsTask(10, DoNothing());
242 {
243 RunLoop run_loop;
244 injector()->AddEvent(0, run_loop.QuitClosure());
245 run_loop.Run();
246 }
247 EXPECT_EQ(4, injector()->processed_events());
248 }
249
TEST_F(MessagePumpGLibTest,TestWorkWhileWaitingForEvents)250 TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) {
251 int task_count = 0;
252 // Tests that we process tasks while waiting for new events.
253 // The event queue is empty at first.
254 for (int i = 0; i < 10; ++i) {
255 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
256 FROM_HERE, BindOnce(&IncrementInt, &task_count));
257 }
258 // After all the previous tasks have executed, enqueue an event that will
259 // quit.
260 {
261 RunLoop run_loop;
262 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
263 FROM_HERE, BindOnce(&EventInjector::AddEvent, Unretained(injector()), 0,
264 run_loop.QuitClosure()));
265 run_loop.Run();
266 }
267 ASSERT_EQ(10, task_count);
268 EXPECT_EQ(1, injector()->processed_events());
269
270 // Tests that we process delayed tasks while waiting for new events.
271 injector()->Reset();
272 task_count = 0;
273 for (int i = 0; i < 10; ++i) {
274 SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
275 FROM_HERE, BindOnce(&IncrementInt, &task_count), Milliseconds(10 * i));
276 }
277 // After all the previous tasks have executed, enqueue an event that will
278 // quit.
279 // This relies on the fact that delayed tasks are executed in delay order.
280 // That is verified in message_loop_unittest.cc.
281 {
282 RunLoop run_loop;
283 SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
284 FROM_HERE,
285 BindOnce(&EventInjector::AddEvent, Unretained(injector()), 0,
286 run_loop.QuitClosure()),
287 Milliseconds(150));
288 run_loop.Run();
289 }
290 ASSERT_EQ(10, task_count);
291 EXPECT_EQ(1, injector()->processed_events());
292 }
293
TEST_F(MessagePumpGLibTest,TestEventsWhileWaitingForWork)294 TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) {
295 // Tests that we process events while waiting for work.
296 // The event queue is empty at first.
297 for (int i = 0; i < 10; ++i) {
298 injector()->AddDummyEvent(0);
299 }
300 // After all the events have been processed, post a task that will check that
301 // the events have been processed (note: the task executes after the event
302 // that posted it has been handled, so we expect 11 at that point).
303 OnceClosure check_task =
304 BindOnce(&ExpectProcessedEvents, Unretained(injector()), 11);
305 OnceClosure posted_task =
306 BindOnce(&PostMessageLoopTask, FROM_HERE, std::move(check_task));
307 injector()->AddEventAsTask(10, std::move(posted_task));
308
309 // And then quit (relies on the condition tested by TestEventTaskInterleave).
310 RunLoop run_loop;
311 injector()->AddEvent(10, run_loop.QuitClosure());
312 run_loop.Run();
313
314 EXPECT_EQ(12, injector()->processed_events());
315 }
316
317 namespace {
318
319 // This class is a helper for the concurrent events / posted tasks test below.
320 // It will quit the main loop once enough tasks and events have been processed,
321 // while making sure there is always work to do and events in the queue.
322 class ConcurrentHelper : public RefCounted<ConcurrentHelper> {
323 public:
ConcurrentHelper(EventInjector * injector,OnceClosure done_closure)324 ConcurrentHelper(EventInjector* injector, OnceClosure done_closure)
325 : injector_(injector),
326 done_closure_(std::move(done_closure)),
327 event_count_(kStartingEventCount),
328 task_count_(kStartingTaskCount) {}
329
FromTask()330 void FromTask() {
331 if (task_count_ > 0) {
332 --task_count_;
333 }
334 if (task_count_ == 0 && event_count_ == 0) {
335 std::move(done_closure_).Run();
336 } else {
337 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
338 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, this));
339 }
340 }
341
FromEvent()342 void FromEvent() {
343 if (event_count_ > 0) {
344 --event_count_;
345 }
346 if (task_count_ == 0 && event_count_ == 0) {
347 std::move(done_closure_).Run();
348 } else {
349 injector_->AddEventAsTask(0,
350 BindOnce(&ConcurrentHelper::FromEvent, this));
351 }
352 }
353
event_count() const354 int event_count() const { return event_count_; }
task_count() const355 int task_count() const { return task_count_; }
356
357 private:
358 friend class RefCounted<ConcurrentHelper>;
359
~ConcurrentHelper()360 ~ConcurrentHelper() {}
361
362 static const int kStartingEventCount = 20;
363 static const int kStartingTaskCount = 20;
364
365 raw_ptr<EventInjector> injector_;
366 OnceClosure done_closure_;
367 int event_count_;
368 int task_count_;
369 };
370
371 } // namespace
372
TEST_F(MessagePumpGLibTest,TestConcurrentEventPostedTask)373 TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) {
374 // Tests that posted tasks don't starve events, nor the opposite.
375 // We use the helper class above. We keep both event and posted task queues
376 // full, the helper verifies that both tasks and events get processed.
377 // If that is not the case, either event_count_ or task_count_ will not get
378 // to 0, and MessageLoop::QuitWhenIdle() will never be called.
379 RunLoop run_loop;
380 scoped_refptr<ConcurrentHelper> helper =
381 new ConcurrentHelper(injector(), run_loop.QuitClosure());
382
383 // Add 2 events to the queue to make sure it is always full (when we remove
384 // the event before processing it).
385 injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper));
386 injector()->AddEventAsTask(0, BindOnce(&ConcurrentHelper::FromEvent, helper));
387
388 // Similarly post 2 tasks.
389 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
390 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper));
391 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
392 FROM_HERE, BindOnce(&ConcurrentHelper::FromTask, helper));
393
394 run_loop.Run();
395 EXPECT_EQ(0, helper->event_count());
396 EXPECT_EQ(0, helper->task_count());
397 }
398
399 namespace {
400
AddEventsAndDrainGLib(EventInjector * injector,OnceClosure on_drained)401 void AddEventsAndDrainGLib(EventInjector* injector, OnceClosure on_drained) {
402 // Add a couple of dummy events
403 injector->AddDummyEvent(0);
404 injector->AddDummyEvent(0);
405 // Then add an event that will quit the main loop.
406 injector->AddEvent(0, std::move(on_drained));
407
408 // Post a couple of dummy tasks
409 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE, DoNothing());
410 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE, DoNothing());
411
412 // Drain the events
413 while (g_main_context_pending(nullptr)) {
414 g_main_context_iteration(nullptr, FALSE);
415 }
416 }
417
418 } // namespace
419
TEST_F(MessagePumpGLibTest,TestDrainingGLib)420 TEST_F(MessagePumpGLibTest, TestDrainingGLib) {
421 // Tests that draining events using GLib works.
422 RunLoop run_loop;
423 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
424 FROM_HERE, BindOnce(&AddEventsAndDrainGLib, Unretained(injector()),
425 run_loop.QuitClosure()));
426 run_loop.Run();
427
428 EXPECT_EQ(3, injector()->processed_events());
429 }
430
431 namespace {
432
433 // Helper class that lets us run the GLib message loop.
434 class GLibLoopRunner : public RefCounted<GLibLoopRunner> {
435 public:
GLibLoopRunner()436 GLibLoopRunner() : quit_(false) { }
437
RunGLib()438 void RunGLib() {
439 while (!quit_) {
440 g_main_context_iteration(nullptr, TRUE);
441 }
442 }
443
RunLoop()444 void RunLoop() {
445 while (!quit_) {
446 g_main_context_iteration(nullptr, TRUE);
447 }
448 }
449
Quit()450 void Quit() {
451 quit_ = true;
452 }
453
Reset()454 void Reset() {
455 quit_ = false;
456 }
457
458 private:
459 friend class RefCounted<GLibLoopRunner>;
460
~GLibLoopRunner()461 ~GLibLoopRunner() {}
462
463 bool quit_;
464 };
465
TestGLibLoopInternal(EventInjector * injector,OnceClosure done)466 void TestGLibLoopInternal(EventInjector* injector, OnceClosure done) {
467 scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
468
469 int task_count = 0;
470 // Add a couple of dummy events
471 injector->AddDummyEvent(0);
472 injector->AddDummyEvent(0);
473 // Post a couple of dummy tasks
474 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
475 FROM_HERE, BindOnce(&IncrementInt, &task_count));
476 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
477 FROM_HERE, BindOnce(&IncrementInt, &task_count));
478 // Delayed events
479 injector->AddDummyEvent(10);
480 injector->AddDummyEvent(10);
481 // Delayed work
482 SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
483 FROM_HERE, BindOnce(&IncrementInt, &task_count), Milliseconds(30));
484 SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
485 FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner), Milliseconds(40));
486
487 // Run a nested, straight GLib message loop.
488 {
489 CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop allow;
490 runner->RunGLib();
491 }
492
493 ASSERT_EQ(3, task_count);
494 EXPECT_EQ(4, injector->processed_events());
495 std::move(done).Run();
496 }
497
TestGtkLoopInternal(EventInjector * injector,OnceClosure done)498 void TestGtkLoopInternal(EventInjector* injector, OnceClosure done) {
499 scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
500
501 int task_count = 0;
502 // Add a couple of dummy events
503 injector->AddDummyEvent(0);
504 injector->AddDummyEvent(0);
505 // Post a couple of dummy tasks
506 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
507 FROM_HERE, BindOnce(&IncrementInt, &task_count));
508 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
509 FROM_HERE, BindOnce(&IncrementInt, &task_count));
510 // Delayed events
511 injector->AddDummyEvent(10);
512 injector->AddDummyEvent(10);
513 // Delayed work
514 SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
515 FROM_HERE, BindOnce(&IncrementInt, &task_count), Milliseconds(30));
516 SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
517 FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner), Milliseconds(40));
518
519 // Run a nested, straight Gtk message loop.
520 {
521 CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop allow;
522 runner->RunLoop();
523 }
524
525 ASSERT_EQ(3, task_count);
526 EXPECT_EQ(4, injector->processed_events());
527 std::move(done).Run();
528 }
529
530 } // namespace
531
TEST_F(MessagePumpGLibTest,TestGLibLoop)532 TEST_F(MessagePumpGLibTest, TestGLibLoop) {
533 // Tests that events and posted tasks are correctly executed if the message
534 // loop is not run by MessageLoop::Run() but by a straight GLib loop.
535 // Note that in this case we don't make strong guarantees about niceness
536 // between events and posted tasks.
537 RunLoop run_loop;
538 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
539 FROM_HERE, BindOnce(&TestGLibLoopInternal, Unretained(injector()),
540 run_loop.QuitClosure()));
541 run_loop.Run();
542 }
543
TEST_F(MessagePumpGLibTest,TestGtkLoop)544 TEST_F(MessagePumpGLibTest, TestGtkLoop) {
545 // Tests that events and posted tasks are correctly executed if the message
546 // loop is not run by MessageLoop::Run() but by a straight Gtk loop.
547 // Note that in this case we don't make strong guarantees about niceness
548 // between events and posted tasks.
549 RunLoop run_loop;
550 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
551 FROM_HERE, BindOnce(&TestGtkLoopInternal, Unretained(injector()),
552 run_loop.QuitClosure()));
553 run_loop.Run();
554 }
555
556 namespace {
557
558 class NestedEventAnalyzer {
559 public:
NestedEventAnalyzer()560 NestedEventAnalyzer() {
561 trace_analyzer::Start(TRACE_DISABLED_BY_DEFAULT("base"));
562 }
563
CountEvents()564 size_t CountEvents() {
565 std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer =
566 trace_analyzer::Stop();
567 trace_analyzer::TraceEventVector events;
568 return analyzer->FindEvents(trace_analyzer::Query::EventName() ==
569 trace_analyzer::Query::String("Nested"),
570 &events);
571 }
572 };
573
574 } // namespace
575
TEST_F(MessagePumpGLibTest,TestNativeNestedLoopWithoutDoWork)576 TEST_F(MessagePumpGLibTest, TestNativeNestedLoopWithoutDoWork) {
577 // Tests that nesting is triggered correctly if a message loop is run
578 // from a native event (gtk event) outside of a work item (not in a posted
579 // task).
580
581 RunLoop run_loop;
582 NestedEventAnalyzer analyzer;
583
584 base::CurrentThread::Get()->EnableMessagePumpTimeKeeperMetrics(
585 "GlibMainLoopTest");
586
587 scoped_refptr<GLibLoopRunner> runner = base::MakeRefCounted<GLibLoopRunner>();
588 injector()->AddEvent(
589 0,
590 BindOnce(
591 [](EventInjector* injector, scoped_refptr<GLibLoopRunner> runner,
592 OnceClosure done) {
593 CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop allow;
594 runner->RunLoop();
595 },
596 Unretained(injector()), runner, run_loop.QuitClosure()));
597
598 injector()->AddDummyEvent(0);
599 injector()->AddDummyEvent(0);
600 injector()->AddDummyEvent(0);
601
602 SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
603 FROM_HERE, BindOnce(&GLibLoopRunner::Quit, runner), Milliseconds(40));
604
605 SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
606 FROM_HERE, run_loop.QuitClosure(), Milliseconds(40));
607
608 run_loop.Run();
609
610 // It would be expected that there be one single event, but it seems like this
611 // is counting the Begin/End of the Nested trace event. Each of the two events
612 // found are of duration 0 with distinct timestamps. It has also been
613 // confirmed that nesting occurs only once.
614 CHECK_EQ(analyzer.CountEvents(), 2ul);
615 }
616
617 // Tests for WatchFileDescriptor API
618 class MessagePumpGLibFdWatchTest : public testing::Test {
619 protected:
MessagePumpGLibFdWatchTest()620 MessagePumpGLibFdWatchTest()
621 : io_thread_("MessagePumpGLibFdWatchTestIOThread") {}
622 ~MessagePumpGLibFdWatchTest() override = default;
623
SetUp()624 void SetUp() override {
625 Thread::Options options(MessagePumpType::IO, 0);
626 ASSERT_TRUE(io_thread_.StartWithOptions(std::move(options)));
627 int ret = pipe(pipefds_);
628 ASSERT_EQ(0, ret);
629 }
630
TearDown()631 void TearDown() override {
632 // Wait for the IO thread to exit before closing FDs which may have been
633 // passed to it.
634 io_thread_.Stop();
635 if (IGNORE_EINTR(close(pipefds_[0])) < 0)
636 PLOG(ERROR) << "close";
637 if (IGNORE_EINTR(close(pipefds_[1])) < 0)
638 PLOG(ERROR) << "close";
639 }
640
WaitUntilIoThreadStarted()641 void WaitUntilIoThreadStarted() {
642 ASSERT_TRUE(io_thread_.WaitUntilThreadStarted());
643 }
644
io_runner() const645 scoped_refptr<SingleThreadTaskRunner> io_runner() const {
646 return io_thread_.task_runner();
647 }
648
SimulateEvent(MessagePumpGlib * pump,MessagePumpGlib::FdWatchController * controller)649 void SimulateEvent(MessagePumpGlib* pump,
650 MessagePumpGlib::FdWatchController* controller) {
651 controller->poll_fd_->revents = G_IO_IN | G_IO_OUT;
652 pump->HandleFdWatchDispatch(controller);
653 }
654
655 int pipefds_[2];
656 static constexpr char null_byte_ = 0;
657
658 private:
659 Thread io_thread_;
660 };
661
662 namespace {
663
664 class BaseWatcher : public MessagePumpGlib::FdWatcher {
665 public:
BaseWatcher(MessagePumpGlib::FdWatchController * controller)666 explicit BaseWatcher(MessagePumpGlib::FdWatchController* controller)
667 : controller_(controller) {
668 DCHECK(controller_);
669 }
670 ~BaseWatcher() override = default;
671
672 // base:MessagePumpGlib::FdWatcher interface
OnFileCanReadWithoutBlocking(int)673 void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); }
OnFileCanWriteWithoutBlocking(int)674 void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); }
675
676 protected:
677 raw_ptr<MessagePumpGlib::FdWatchController> controller_;
678 };
679
680 class DeleteWatcher : public BaseWatcher {
681 public:
DeleteWatcher(std::unique_ptr<MessagePumpGlib::FdWatchController> controller)682 explicit DeleteWatcher(
683 std::unique_ptr<MessagePumpGlib::FdWatchController> controller)
684 : BaseWatcher(controller.get()),
685 owned_controller_(std::move(controller)) {}
686
~DeleteWatcher()687 ~DeleteWatcher() override { DCHECK(!controller_); }
688
HasController() const689 bool HasController() const { return !!controller_; }
690
OnFileCanWriteWithoutBlocking(int)691 void OnFileCanWriteWithoutBlocking(int /* fd */) override {
692 ClearController();
693 }
694
695 protected:
ClearController()696 void ClearController() {
697 DCHECK(owned_controller_);
698 controller_ = nullptr;
699 owned_controller_.reset();
700 }
701
702 private:
703 std::unique_ptr<MessagePumpGlib::FdWatchController> owned_controller_;
704 };
705
706 class StopWatcher : public BaseWatcher {
707 public:
StopWatcher(MessagePumpGlib::FdWatchController * controller)708 explicit StopWatcher(MessagePumpGlib::FdWatchController* controller)
709 : BaseWatcher(controller) {}
710
711 ~StopWatcher() override = default;
712
OnFileCanWriteWithoutBlocking(int)713 void OnFileCanWriteWithoutBlocking(int /* fd */) override {
714 controller_->StopWatchingFileDescriptor();
715 }
716 };
717
QuitMessageLoopAndStart(OnceClosure quit_closure)718 void QuitMessageLoopAndStart(OnceClosure quit_closure) {
719 std::move(quit_closure).Run();
720
721 RunLoop runloop(RunLoop::Type::kNestableTasksAllowed);
722 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE,
723 runloop.QuitClosure());
724 runloop.Run();
725 }
726
727 class NestedPumpWatcher : public MessagePumpGlib::FdWatcher {
728 public:
729 NestedPumpWatcher() = default;
730 ~NestedPumpWatcher() override = default;
731
OnFileCanReadWithoutBlocking(int)732 void OnFileCanReadWithoutBlocking(int /* fd */) override {
733 RunLoop runloop;
734 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
735 FROM_HERE, BindOnce(&QuitMessageLoopAndStart, runloop.QuitClosure()));
736 runloop.Run();
737 }
738
OnFileCanWriteWithoutBlocking(int)739 void OnFileCanWriteWithoutBlocking(int /* fd */) override {}
740 };
741
742 class QuitWatcher : public DeleteWatcher {
743 public:
QuitWatcher(std::unique_ptr<MessagePumpGlib::FdWatchController> controller,base::OnceClosure quit_closure)744 QuitWatcher(std::unique_ptr<MessagePumpGlib::FdWatchController> controller,
745 base::OnceClosure quit_closure)
746 : DeleteWatcher(std::move(controller)),
747 quit_closure_(std::move(quit_closure)) {}
748
OnFileCanReadWithoutBlocking(int fd)749 void OnFileCanReadWithoutBlocking(int fd) override {
750 ClearController();
751 if (quit_closure_)
752 std::move(quit_closure_).Run();
753 }
754
755 private:
756 base::OnceClosure quit_closure_;
757 };
758
WriteFDWrapper(const int fd,const char * buf,int size,WaitableEvent * event)759 void WriteFDWrapper(const int fd,
760 const char* buf,
761 int size,
762 WaitableEvent* event) {
763 ASSERT_TRUE(WriteFileDescriptor(fd, StringPiece(buf, size)));
764 }
765
766 } // namespace
767
768 // Tests that MessagePumpGlib::FdWatcher::OnFileCanReadWithoutBlocking is not
769 // called for a READ_WRITE event, and that the controller is destroyed in
770 // OnFileCanWriteWithoutBlocking callback.
TEST_F(MessagePumpGLibFdWatchTest,DeleteWatcher)771 TEST_F(MessagePumpGLibFdWatchTest, DeleteWatcher) {
772 auto pump = std::make_unique<MessagePumpGlib>();
773 auto controller_ptr =
774 std::make_unique<MessagePumpGlib::FdWatchController>(FROM_HERE);
775 auto* controller = controller_ptr.get();
776
777 DeleteWatcher watcher(std::move(controller_ptr));
778 pump->WatchFileDescriptor(pipefds_[1], false,
779 MessagePumpGlib::WATCH_READ_WRITE, controller,
780 &watcher);
781
782 SimulateEvent(pump.get(), controller);
783 EXPECT_FALSE(watcher.HasController());
784 }
785
786 // Tests that MessagePumpGlib::FdWatcher::OnFileCanReadWithoutBlocking is not
787 // called for a READ_WRITE event, when the watcher calls
788 // StopWatchingFileDescriptor in OnFileCanWriteWithoutBlocking callback.
TEST_F(MessagePumpGLibFdWatchTest,StopWatcher)789 TEST_F(MessagePumpGLibFdWatchTest, StopWatcher) {
790 std::unique_ptr<MessagePumpGlib> pump(new MessagePumpGlib);
791 MessagePumpGlib::FdWatchController controller(FROM_HERE);
792 StopWatcher watcher(&controller);
793 pump->WatchFileDescriptor(pipefds_[1], false,
794 MessagePumpGlib::WATCH_READ_WRITE, &controller,
795 &watcher);
796
797 SimulateEvent(pump.get(), &controller);
798 }
799
800 // Tests that FdWatcher works properly with nested loops.
TEST_F(MessagePumpGLibFdWatchTest,NestedPumpWatcher)801 TEST_F(MessagePumpGLibFdWatchTest, NestedPumpWatcher) {
802 test::SingleThreadTaskEnvironment task_environment(
803 test::SingleThreadTaskEnvironment::MainThreadType::UI);
804 std::unique_ptr<MessagePumpGlib> pump(new MessagePumpGlib);
805 NestedPumpWatcher watcher;
806 MessagePumpGlib::FdWatchController controller(FROM_HERE);
807 pump->WatchFileDescriptor(pipefds_[1], false, MessagePumpGlib::WATCH_READ,
808 &controller, &watcher);
809
810 SimulateEvent(pump.get(), &controller);
811 }
812
813 // Tests that MessagePumpGlib quits immediately when it is quit from
814 // libevent's event_base_loop().
TEST_F(MessagePumpGLibFdWatchTest,QuitWatcher)815 TEST_F(MessagePumpGLibFdWatchTest, QuitWatcher) {
816 MessagePumpGlib* pump = new MessagePumpGlib();
817 SingleThreadTaskExecutor executor(WrapUnique(pump));
818 RunLoop run_loop;
819
820 auto owned_controller =
821 std::make_unique<MessagePumpGlib::FdWatchController>(FROM_HERE);
822 MessagePumpGlib::FdWatchController* controller = owned_controller.get();
823 QuitWatcher delegate(std::move(owned_controller), run_loop.QuitClosure());
824
825 pump->WatchFileDescriptor(pipefds_[0], false, MessagePumpGlib::WATCH_READ,
826 controller, &delegate);
827
828 // Make the IO thread wait for |event| before writing to pipefds[1].
829 WaitableEvent event;
830 auto watcher = std::make_unique<WaitableEventWatcher>();
831 WaitableEventWatcher::EventCallback write_fd_task =
832 BindOnce(&WriteFDWrapper, pipefds_[1], &null_byte_, 1);
833 io_runner()->PostTask(
834 FROM_HERE, BindOnce(IgnoreResult(&WaitableEventWatcher::StartWatching),
835 Unretained(watcher.get()), &event,
836 std::move(write_fd_task), io_runner()));
837
838 // Queue |event| to signal on |CurrentUIThread::Get()|.
839 SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
840 FROM_HERE, BindOnce(&WaitableEvent::Signal, Unretained(&event)));
841
842 // Now run the MessageLoop.
843 run_loop.Run();
844
845 // StartWatching can move |watcher| to IO thread. Release on IO thread.
846 io_runner()->PostTask(FROM_HERE, BindOnce(&WaitableEventWatcher::StopWatching,
847 Owned(std::move(watcher))));
848 }
849
850 } // namespace base
851