2018-12-31 20:04:05 +01:00
|
|
|
//
|
2020-01-01 02:23:48 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
//
|
|
|
|
#include "td/utils/port/detail/Epoll.h"
|
|
|
|
|
|
|
|
char disable_linker_warning_about_empty_file_epoll_cpp TD_UNUSED;
|
|
|
|
|
|
|
|
#ifdef TD_POLL_EPOLL
|
|
|
|
|
|
|
|
#include "td/utils/format.h"
|
|
|
|
#include "td/utils/logging.h"
|
|
|
|
#include "td/utils/Status.h"
|
|
|
|
|
2020-06-07 17:14:52 +02:00
|
|
|
#include <cerrno>
|
|
|
|
|
2018-12-31 20:04:05 +01:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
namespace td {
|
|
|
|
namespace detail {
|
|
|
|
void Epoll::init() {
|
2019-07-31 12:45:15 +02:00
|
|
|
CHECK(!epoll_fd_);
|
|
|
|
epoll_fd_ = NativeFd(epoll_create(1));
|
2018-12-31 20:04:05 +01:00
|
|
|
auto epoll_create_errno = errno;
|
2019-07-31 12:45:15 +02:00
|
|
|
LOG_IF(FATAL, !epoll_fd_) << Status::PosixError(epoll_create_errno, "epoll_create failed");
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2019-07-31 12:45:15 +02:00
|
|
|
events_.resize(1000);
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Epoll::clear() {
|
2019-07-31 12:45:15 +02:00
|
|
|
if (!epoll_fd_) {
|
2018-12-31 20:04:05 +01:00
|
|
|
return;
|
|
|
|
}
|
2019-07-31 12:45:15 +02:00
|
|
|
events_.clear();
|
2018-12-31 20:04:05 +01:00
|
|
|
|
2019-07-31 12:45:15 +02:00
|
|
|
epoll_fd_.close();
|
2018-08-13 19:15:09 +02:00
|
|
|
|
2019-07-31 12:45:15 +02:00
|
|
|
for (auto *list_node = list_root_.next; list_node != &list_root_;) {
|
2018-08-13 19:15:09 +02:00
|
|
|
auto pollable_fd = PollableFd::from_list_node(list_node);
|
|
|
|
list_node = list_node->next;
|
|
|
|
}
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-08-13 19:15:09 +02:00
|
|
|
void Epoll::subscribe(PollableFd fd, PollFlags flags) {
|
2018-12-31 20:04:05 +01:00
|
|
|
epoll_event event;
|
|
|
|
event.events = EPOLLHUP | EPOLLERR | EPOLLET;
|
|
|
|
#ifdef EPOLLRDHUP
|
|
|
|
event.events |= EPOLLRDHUP;
|
|
|
|
#endif
|
2018-08-13 19:15:09 +02:00
|
|
|
if (flags.can_read()) {
|
2018-12-31 20:04:05 +01:00
|
|
|
event.events |= EPOLLIN;
|
|
|
|
}
|
2018-08-13 19:15:09 +02:00
|
|
|
if (flags.can_write()) {
|
2018-12-31 20:04:05 +01:00
|
|
|
event.events |= EPOLLOUT;
|
|
|
|
}
|
2018-08-13 19:15:09 +02:00
|
|
|
auto native_fd = fd.native_fd().fd();
|
|
|
|
auto *list_node = fd.release_as_list_node();
|
2019-07-31 12:45:15 +02:00
|
|
|
list_root_.put(list_node);
|
2018-08-13 19:15:09 +02:00
|
|
|
event.data.ptr = list_node;
|
|
|
|
|
2019-07-31 12:45:15 +02:00
|
|
|
int err = epoll_ctl(epoll_fd_.fd(), EPOLL_CTL_ADD, native_fd, &event);
|
2018-12-31 20:04:05 +01:00
|
|
|
auto epoll_ctl_errno = errno;
|
2019-07-31 12:45:15 +02:00
|
|
|
LOG_IF(FATAL, err == -1) << Status::PosixError(epoll_ctl_errno, "epoll_ctl ADD failed")
|
|
|
|
<< ", epoll_fd = " << epoll_fd_.fd() << ", fd = " << native_fd;
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-08-13 19:15:09 +02:00
|
|
|
void Epoll::unsubscribe(PollableFdRef fd_ref) {
|
|
|
|
auto fd = fd_ref.lock();
|
|
|
|
auto native_fd = fd.native_fd().fd();
|
2019-07-31 12:45:15 +02:00
|
|
|
int err = epoll_ctl(epoll_fd_.fd(), EPOLL_CTL_DEL, native_fd, nullptr);
|
2018-12-31 20:04:05 +01:00
|
|
|
auto epoll_ctl_errno = errno;
|
2019-07-31 12:45:15 +02:00
|
|
|
LOG_IF(FATAL, err == -1) << Status::PosixError(epoll_ctl_errno, "epoll_ctl DEL failed")
|
2020-03-10 02:37:46 +01:00
|
|
|
<< ", epoll_fd = " << epoll_fd_.fd() << ", fd = " << native_fd
|
|
|
|
<< ", status = " << fd.native_fd().validate();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
|
2018-08-13 19:15:09 +02:00
|
|
|
void Epoll::unsubscribe_before_close(PollableFdRef fd) {
|
2018-12-31 20:04:05 +01:00
|
|
|
unsubscribe(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Epoll::run(int timeout_ms) {
|
2019-07-31 12:45:15 +02:00
|
|
|
int ready_n = epoll_wait(epoll_fd_.fd(), &events_[0], static_cast<int>(events_.size()), timeout_ms);
|
2018-12-31 20:04:05 +01:00
|
|
|
auto epoll_wait_errno = errno;
|
|
|
|
LOG_IF(FATAL, ready_n == -1 && epoll_wait_errno != EINTR)
|
|
|
|
<< Status::PosixError(epoll_wait_errno, "epoll_wait failed");
|
|
|
|
|
|
|
|
for (int i = 0; i < ready_n; i++) {
|
2018-08-13 19:15:09 +02:00
|
|
|
PollFlags flags;
|
2019-07-31 12:45:15 +02:00
|
|
|
epoll_event *event = &events_[i];
|
2018-12-31 20:04:05 +01:00
|
|
|
if (event->events & EPOLLIN) {
|
|
|
|
event->events &= ~EPOLLIN;
|
2018-08-13 19:15:09 +02:00
|
|
|
flags = flags | PollFlags::Read();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
if (event->events & EPOLLOUT) {
|
|
|
|
event->events &= ~EPOLLOUT;
|
2018-08-13 19:15:09 +02:00
|
|
|
flags = flags | PollFlags::Write();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
#ifdef EPOLLRDHUP
|
|
|
|
if (event->events & EPOLLRDHUP) {
|
|
|
|
event->events &= ~EPOLLRDHUP;
|
2020-06-24 13:47:36 +02:00
|
|
|
flags = flags | PollFlags::Close();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (event->events & EPOLLHUP) {
|
|
|
|
event->events &= ~EPOLLHUP;
|
2018-08-13 19:15:09 +02:00
|
|
|
flags = flags | PollFlags::Close();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
if (event->events & EPOLLERR) {
|
|
|
|
event->events &= ~EPOLLERR;
|
2018-08-13 19:15:09 +02:00
|
|
|
flags = flags | PollFlags::Error();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
if (event->events) {
|
|
|
|
LOG(FATAL) << "Unsupported epoll events: " << event->events;
|
|
|
|
}
|
2018-08-13 19:15:09 +02:00
|
|
|
//LOG(DEBUG) << "Epoll event " << tag("fd", event->data.fd) << tag("flags", format::as_binary(flags));
|
|
|
|
auto pollable_fd = PollableFd::from_list_node(static_cast<ListNode *>(event->data.ptr));
|
|
|
|
pollable_fd.add_flags(flags);
|
|
|
|
pollable_fd.release_as_list_node();
|
2018-12-31 20:04:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
} // namespace td
|
|
|
|
|
|
|
|
#endif
|