#include <folly/io/async/TimerFD.h>
#include <folly/FileUtil.h>
#ifdef FOLLY_HAVE_TIMERFD
#include <sys/timerfd.h>
#endif
namespace folly {
#ifdef FOLLY_HAVE_TIMERFD
TimerFD::TimerFD(folly::EventBase* eventBase)
: TimerFD(eventBase, createTimerFd()) {}
TimerFD::TimerFD(folly::EventBase* eventBase, int fd)
: folly::EventHandler(eventBase, NetworkSocket::fromFd(fd)), fd_(fd) {
setEventCallback(this);
if (fd_ > 0) {
registerHandler(folly::EventHandler::READ | folly::EventHandler::PERSIST);
}
}
TimerFD::~TimerFD() {
cancel();
close();
}
void TimerFD::close() {
unregisterHandler();
if (fd_ > 0) {
detachEventBase();
changeHandlerFD(NetworkSocket());
::close(fd_);
fd_ = -1;
}
}
void TimerFD::schedule(std::chrono::microseconds timeout) {
setTimer(timeout.count() ? timeout : std::chrono::microseconds(1));
}
void TimerFD::cancel() {
setTimer(std::chrono::microseconds(0));
}
bool TimerFD::setTimer(std::chrono::microseconds useconds) {
if (fd_ <= 0) {
return false;
}
struct itimerspec val;
val.it_interval = {0, 0};
val.it_value.tv_sec =
std::chrono::duration_cast<std::chrono::seconds>(useconds).count();
val.it_value.tv_nsec =
std::chrono::duration_cast<std::chrono::nanoseconds>(useconds).count() %
1000000000LL;
return (0 == ::timerfd_settime(fd_, 0, &val, nullptr));
}
void TimerFD::handlerReady(uint16_t events) noexcept {
DestructorGuard dg(this);
auto relevantEvents = uint16_t(events & folly::EventHandler::READ_WRITE);
if (relevantEvents == folly::EventHandler::READ ||
relevantEvents == folly::EventHandler::READ_WRITE) {
uint64_t data = 0;
ssize_t num = folly::readNoInt(fd_, &data, sizeof(data));
if (num == sizeof(data)) {
onTimeout();
}
}
}
void TimerFD::eventReadCallback(IoVec* ioVec, int res) {
ioVec->timerData_ = 0;
ioVecPtr_.reset(ioVec);
if (res == sizeof(ioVec->timerData_)) {
DestructorGuard dg(this);
onTimeout();
}
}
int TimerFD::createTimerFd() {
return ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
}
#else
TimerFD::TimerFD(folly::EventBase* eventBase) : … { … }
TimerFD::~TimerFD() { … }
void TimerFD::schedule(std::chrono::microseconds timeout) { … }
void TimerFD::cancel() { … }
TimerFD::TimerFDAsyncTimeout::TimerFDAsyncTimeout(
folly::EventBase* eventBase, TimerFD* timerFd)
: … { … }
void TimerFD::TimerFDAsyncTimeout::timeoutExpired() noexcept { … }
#endif
}