• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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