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