Flutter Engine
message_loop_linux.cc
Go to the documentation of this file.
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 
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 
27 MessageLoopLinux::~MessageLoopLinux() {
28  bool removed_source = AddOrRemoveTimerSource(false);
29  FML_CHECK(removed_source);
30 }
31 
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|
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|
76 void MessageLoopLinux::Terminate() {
77  running_ = false;
78  WakeUp(fml::TimePoint::Now());
79 }
80 
81 // |fml::MessageLoopImpl|
82 void MessageLoopLinux::WakeUp(fml::TimePoint time_point) {
83  bool result = TimerRearm(timer_fd_.get(), time_point);
84  FML_DCHECK(result);
85 }
86 
87 void MessageLoopLinux::OnEventFired() {
88  if (TimerDrain(timer_fd_.get())) {
90  }
91 }
92 
93 } // namespace fml
#define FML_DCHECK(condition)
Definition: logging.h:86
const T & get() const
Definition: unique_object.h:87
Definition: ascii_trie.cc:9
#define FML_HANDLE_EINTR(x)
Definition: eintr_wrapper.h:33
int timerfd_create(int clockid, int flags)
Definition: timerfd.cc:17
static constexpr int kClockType
GdkEventButton * event
Definition: fl_view.cc:62
#define TFD_CLOEXEC
Definition: timerfd.h:32
#define FML_CHECK(condition)
Definition: logging.h:68
bool TimerDrain(int fd)
Definition: timerfd.cc:54
#define TFD_NONBLOCK
Definition: timerfd.h:33
bool TimerRearm(int fd, fml::TimePoint time_point)
Rearms the timer to expire at the given time point.
Definition: timerfd.cc:36
static TimePoint Now()
Definition: time_point.cc:26