提交 117679f9 编写于 作者: C Chinmay Garde 提交者: GitHub

The Linux FML backend. (#3488)

上级 6b9eda4a
// 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
// 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_
// 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
// 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_
......@@ -1917,6 +1917,10 @@ FILE: ../../../flutter/fml/message_loop_impl.h
FILE: ../../../flutter/fml/message_loop_unittests.cc
FILE: ../../../flutter/fml/platform/darwin/cf_utils.cc
FILE: ../../../flutter/fml/platform/darwin/cf_utils.h
FILE: ../../../flutter/fml/platform/linux/message_loop_linux.cc
FILE: ../../../flutter/fml/platform/linux/message_loop_linux.h
FILE: ../../../flutter/fml/platform/linux/timerfd.cc
FILE: ../../../flutter/fml/platform/linux/timerfd.h
FILE: ../../../flutter/fml/task_runner.cc
FILE: ../../../flutter/fml/task_runner.h
FILE: ../../../flutter/fml/thread.cc
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册