| // 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/timerfd.h" |
| |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include <cstring> |
| |
| #include "flutter/fml/eintr_wrapper.h" |
| #include "flutter/fml/logging.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, fml::TimePoint time_point) { |
| uint64_t nano_secs = time_point.ToEpochDelta().ToNanoseconds(); |
| |
| // "0" will disarm the timer, desired behavior is to immediately |
| // trigger the timer. |
| if (nano_secs < 1) { |
| nano_secs = 1; |
| } |
| |
| struct itimerspec spec = {}; |
| spec.it_value.tv_sec = static_cast<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); |
| if (result != 0) { |
| FML_DLOG(ERROR) << "timerfd_settime err:" << strerror(errno); |
| } |
| return result == 0; |
| } |
| |
| bool TimerDrain(int fd) { |
| // 8 bytes must be read from a signaled timer file descriptor when signaled. |
| uint64_t fire_count = 0; |
| ssize_t size = FML_HANDLE_EINTR(::read(fd, &fire_count, sizeof(uint64_t))); |
| if (size != sizeof(uint64_t)) { |
| return false; |
| } |
| return fire_count > 0; |
| } |
| |
| } // namespace fml |