// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "flutter/fml/platform/linux/message_loop_linux.h" #include #include #include "flutter/fml/eintr_wrapper.h" #include "flutter/fml/platform/linux/timerfd.h" namespace fml { static constexpr int kClockType = CLOCK_MONOTONIC; MessageLoopLinux::MessageLoopLinux() : epoll_fd_(FML_HANDLE_EINTR(::epoll_create(1 /* unused */))), timer_fd_(::timerfd_create(kClockType, TFD_NONBLOCK | TFD_CLOEXEC)), running_(false) { FML_CHECK(epoll_fd_.is_valid()); FML_CHECK(timer_fd_.is_valid()); bool added_source = AddOrRemoveTimerSource(true); FML_CHECK(added_source); } MessageLoopLinux::~MessageLoopLinux() { bool removed_source = AddOrRemoveTimerSource(false); FML_CHECK(removed_source); } bool MessageLoopLinux::AddOrRemoveTimerSource(bool add) { struct epoll_event event = {}; event.events = EPOLLIN; // The data is just for informational purposes so we know when we were worken // by the FD. event.data.fd = timer_fd_.get(); int ctl_result = ::epoll_ctl(epoll_fd_.get(), add ? EPOLL_CTL_ADD : EPOLL_CTL_DEL, timer_fd_.get(), &event); return ctl_result == 0; } // |fml::MessageLoopImpl| void MessageLoopLinux::Run() { running_ = true; while (running_) { struct epoll_event event = {}; int epoll_result = FML_HANDLE_EINTR( ::epoll_wait(epoll_fd_.get(), &event, 1, -1 /* timeout */)); // Errors are fatal. if (event.events & (EPOLLERR | EPOLLHUP)) { running_ = false; continue; } // Timeouts are fatal since we specified an infinite timeout already. // Likewise, > 1 is not possible since we waited for one result. if (epoll_result != 1) { running_ = false; continue; } if (event.data.fd == timer_fd_.get()) { OnEventFired(); } } } // |fml::MessageLoopImpl| void MessageLoopLinux::Terminate() { running_ = false; WakeUp(fml::TimePoint::Now()); } // |fml::MessageLoopImpl| void MessageLoopLinux::WakeUp(fml::TimePoint time_point) { bool result = TimerRearm(timer_fd_.get(), time_point); FML_DCHECK(result); } void MessageLoopLinux::OnEventFired() { if (TimerDrain(timer_fd_.get())) { RunExpiredTasksNow(); } } } // namespace fml