The Linux FML backend. (flutter/engine#3488)
This commit is contained in:
90
engine/src/flutter/fml/platform/linux/message_loop_linux.cc
Normal file
90
engine/src/flutter/fml/platform/linux/message_loop_linux.cc
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright 2017 The Chromium 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 <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "flutter/fml/platform/linux/timerfd.h"
|
||||
#include "lib/ftl/files/eintr_wrapper.h"
|
||||
|
||||
namespace fml {
|
||||
|
||||
static constexpr int kClockType = CLOCK_MONOTONIC;
|
||||
|
||||
MessageLoopLinux::MessageLoopLinux()
|
||||
: epoll_fd_(HANDLE_EINTR(::epoll_create(1 /* unused */))),
|
||||
timer_fd_(::timerfd_create(kClockType, TFD_NONBLOCK | TFD_CLOEXEC)),
|
||||
running_(false) {
|
||||
FTL_CHECK(epoll_fd_.is_valid());
|
||||
FTL_CHECK(timer_fd_.is_valid());
|
||||
bool added_source = AddOrRemoveTimerSource(true);
|
||||
FTL_CHECK(added_source);
|
||||
}
|
||||
|
||||
MessageLoopLinux::~MessageLoopLinux() {
|
||||
bool removed_source = AddOrRemoveTimerSource(false);
|
||||
FTL_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;
|
||||
}
|
||||
|
||||
void MessageLoopLinux::Run() {
|
||||
running_ = true;
|
||||
|
||||
while (running_) {
|
||||
struct epoll_event event = {};
|
||||
|
||||
int epoll_result = 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLoopLinux::Terminate() {
|
||||
running_ = false;
|
||||
WakeUp(ftl::TimePoint::Now());
|
||||
}
|
||||
|
||||
void MessageLoopLinux::WakeUp(ftl::TimePoint time_point) {
|
||||
bool result = TimerRearm(timer_fd_.get(), time_point);
|
||||
FTL_DCHECK(result);
|
||||
}
|
||||
|
||||
void MessageLoopLinux::OnEventFired() {
|
||||
if (TimerDrain(timer_fd_.get())) {
|
||||
RunExpiredTasksNow();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fml
|
||||
43
engine/src/flutter/fml/platform/linux/message_loop_linux.h
Normal file
43
engine/src/flutter/fml/platform/linux/message_loop_linux.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_FML_PLATFORM_LINUX_MESSAGE_LOOP_LINUX_H_
|
||||
#define FLUTTER_FML_PLATFORM_LINUX_MESSAGE_LOOP_LINUX_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "flutter/fml/message_loop_impl.h"
|
||||
#include "lib/ftl/files/unique_fd.h"
|
||||
#include "lib/ftl/macros.h"
|
||||
|
||||
namespace fml {
|
||||
|
||||
class MessageLoopLinux : public MessageLoopImpl {
|
||||
private:
|
||||
ftl::UniqueFD epoll_fd_;
|
||||
ftl::UniqueFD timer_fd_;
|
||||
bool running_;
|
||||
|
||||
MessageLoopLinux();
|
||||
|
||||
~MessageLoopLinux() override;
|
||||
|
||||
void Run() override;
|
||||
|
||||
void Terminate() override;
|
||||
|
||||
void WakeUp(ftl::TimePoint time_point) override;
|
||||
|
||||
void OnEventFired();
|
||||
|
||||
bool AddOrRemoveTimerSource(bool add);
|
||||
|
||||
FRIEND_MAKE_REF_COUNTED(MessageLoopLinux);
|
||||
FRIEND_REF_COUNTED_THREAD_SAFE(MessageLoopLinux);
|
||||
FTL_DISALLOW_COPY_AND_ASSIGN(MessageLoopLinux);
|
||||
};
|
||||
|
||||
} // namespace fml
|
||||
|
||||
#endif // FLUTTER_FML_PLATFORM_LINUX_MESSAGE_LOOP_LINUX_H_
|
||||
58
engine/src/flutter/fml/platform/linux/timerfd.cc
Normal file
58
engine/src/flutter/fml/platform/linux/timerfd.cc
Normal file
@@ -0,0 +1,58 @@
|
||||
// Copyright 2017 The Chromium 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/timerfd.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/ftl/files/eintr_wrapper.h"
|
||||
|
||||
#if FML_TIMERFD_AVAILABLE == 0
|
||||
|
||||
#include <asm/unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
int timerfd_create(int clockid, int flags) {
|
||||
return syscall(__NR_timerfd_create, clockid, flags);
|
||||
}
|
||||
|
||||
int timerfd_settime(int ufc,
|
||||
int flags,
|
||||
const struct itimerspec* utmr,
|
||||
struct itimerspec* otmr) {
|
||||
return syscall(__NR_timerfd_settime, ufc, flags, utmr, otmr);
|
||||
}
|
||||
|
||||
#endif // FML_TIMERFD_AVAILABLE == 0
|
||||
|
||||
namespace fml {
|
||||
|
||||
#ifndef NSEC_PER_SEC
|
||||
#define NSEC_PER_SEC 1000000000
|
||||
#endif
|
||||
|
||||
bool TimerRearm(int fd, ftl::TimePoint time_point) {
|
||||
const uint64_t nano_secs = time_point.ToEpochDelta().ToNanoseconds();
|
||||
|
||||
struct itimerspec spec = {};
|
||||
spec.it_value.tv_sec = (time_t)(nano_secs / NSEC_PER_SEC);
|
||||
spec.it_value.tv_nsec = nano_secs % NSEC_PER_SEC;
|
||||
spec.it_interval = spec.it_value; // single expiry.
|
||||
|
||||
int result = ::timerfd_settime(fd, TFD_TIMER_ABSTIME, &spec, nullptr);
|
||||
return result == 0;
|
||||
}
|
||||
|
||||
bool TimerDrain(int fd) {
|
||||
// 8 bytes must be read from a signalled timer file descriptor when signalled.
|
||||
uint64_t fire_count = 0;
|
||||
ssize_t size = HANDLE_EINTR(::read(fd, &fire_count, sizeof(uint64_t)));
|
||||
if (size != sizeof(uint64_t)) {
|
||||
return false;
|
||||
}
|
||||
return fire_count > 0;
|
||||
}
|
||||
|
||||
} // namespace fml
|
||||
53
engine/src/flutter/fml/platform/linux/timerfd.h
Normal file
53
engine/src/flutter/fml/platform/linux/timerfd.h
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_FML_PLATFORM_LINUX_TIMER_FD_H_
|
||||
#define FLUTTER_FML_PLATFORM_LINUX_TIMER_FD_H_
|
||||
|
||||
#include "lib/ftl/time/time_point.h"
|
||||
|
||||
// clang-format off
|
||||
#if __has_include(<sys/timerfd.h>)
|
||||
// clang-format on
|
||||
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
#define FML_TIMERFD_AVAILABLE 1
|
||||
|
||||
#else // __has_include(<sys/timerfd.h>)
|
||||
|
||||
#define FML_TIMERFD_AVAILABLE 0
|
||||
|
||||
#include <sys/types.h>
|
||||
// Must come after sys/types
|
||||
#include <linux/time.h>
|
||||
|
||||
#define TFD_TIMER_ABSTIME (1 << 0)
|
||||
#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
|
||||
|
||||
#define TFD_CLOEXEC O_CLOEXEC
|
||||
#define TFD_NONBLOCK O_NONBLOCK
|
||||
|
||||
int timerfd_create(int clockid, int flags);
|
||||
|
||||
int timerfd_settime(int ufc,
|
||||
int flags,
|
||||
const struct itimerspec* utmr,
|
||||
struct itimerspec* otmr);
|
||||
|
||||
#endif // __has_include(<sys/timerfd.h>)
|
||||
|
||||
namespace fml {
|
||||
|
||||
/// Rearms the timer to expire at the given time point.
|
||||
bool TimerRearm(int fd, ftl::TimePoint time_point);
|
||||
|
||||
/// Drains the timer FD and retuns true if it has expired. This may be false in
|
||||
/// case the timer read is non-blocking and this routine was called before the
|
||||
/// timer expiry.
|
||||
bool TimerDrain(int fd);
|
||||
|
||||
} // namespace fml
|
||||
|
||||
#endif // FLUTTER_FML_PLATFORM_LINUX_TIMER_FD_H_
|
||||
Reference in New Issue
Block a user