• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
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 "flutter/fml/platform/linux/message_loop_linux.h"
6 
7 #include <sys/epoll.h>
8 #include <unistd.h>
9 
10 #include "flutter/fml/eintr_wrapper.h"
11 #include "flutter/fml/platform/linux/timerfd.h"
12 
13 namespace fml {
14 
15 static constexpr int kClockType = CLOCK_MONOTONIC;
16 
MessageLoopLinux()17 MessageLoopLinux::MessageLoopLinux()
18     : epoll_fd_(FML_HANDLE_EINTR(::epoll_create(1 /* unused */))),
19       timer_fd_(::timerfd_create(kClockType, TFD_NONBLOCK | TFD_CLOEXEC)),
20       running_(false) {
21   FML_CHECK(epoll_fd_.is_valid());
22   FML_CHECK(timer_fd_.is_valid());
23   bool added_source = AddOrRemoveTimerSource(true);
24   FML_CHECK(added_source);
25 }
26 
~MessageLoopLinux()27 MessageLoopLinux::~MessageLoopLinux() {
28   bool removed_source = AddOrRemoveTimerSource(false);
29   FML_CHECK(removed_source);
30 }
31 
AddOrRemoveTimerSource(bool add)32 bool MessageLoopLinux::AddOrRemoveTimerSource(bool add) {
33   struct epoll_event event = {};
34 
35   event.events = EPOLLIN;
36   // The data is just for informational purposes so we know when we were worken
37   // by the FD.
38   event.data.fd = timer_fd_.get();
39 
40   int ctl_result =
41       ::epoll_ctl(epoll_fd_.get(), add ? EPOLL_CTL_ADD : EPOLL_CTL_DEL,
42                   timer_fd_.get(), &event);
43   return ctl_result == 0;
44 }
45 
46 // |fml::MessageLoopImpl|
Run()47 void MessageLoopLinux::Run() {
48   running_ = true;
49 
50   while (running_) {
51     struct epoll_event event = {};
52 
53     int epoll_result = FML_HANDLE_EINTR(
54         ::epoll_wait(epoll_fd_.get(), &event, 1, -1 /* timeout */));
55 
56     // Errors are fatal.
57     if (event.events & (EPOLLERR | EPOLLHUP)) {
58       running_ = false;
59       continue;
60     }
61 
62     // Timeouts are fatal since we specified an infinite timeout already.
63     // Likewise, > 1 is not possible since we waited for one result.
64     if (epoll_result != 1) {
65       running_ = false;
66       continue;
67     }
68 
69     if (event.data.fd == timer_fd_.get()) {
70       OnEventFired();
71     }
72   }
73 }
74 
75 // |fml::MessageLoopImpl|
Terminate()76 void MessageLoopLinux::Terminate() {
77   running_ = false;
78   WakeUp(fml::TimePoint::Now());
79 }
80 
81 // |fml::MessageLoopImpl|
WakeUp(fml::TimePoint time_point)82 void MessageLoopLinux::WakeUp(fml::TimePoint time_point) {
83   bool result = TimerRearm(timer_fd_.get(), time_point);
84   FML_DCHECK(result);
85 }
86 
OnEventFired()87 void MessageLoopLinux::OnEventFired() {
88   if (TimerDrain(timer_fd_.get())) {
89     RunExpiredTasksNow();
90   }
91 }
92 
93 }  // namespace fml
94