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